/* ============================================================================
   Satofy — Rhea token layer
   ----------------------------------------------------------------------------
   A vanilla-CSS port of the geometry and colour behaviour of the shadcn "Rhea"
   style (neutral base, green theme, medium radius, ring-based focus, subtle
   press). No Tailwind, no build step, no dependencies — a preset is only tokens.

   TWO PARTS, and the split is deliberate:

   1. TOKENS (`--rh-*`) are global but INERT. Declaring them changes nothing on
      screen; only a rule that consumes one does. So this half is safe to land
      ahead of any redesign, and it is what every later panel will draw from.

   2. COMPONENTS are scoped to `:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel)`. The id gives specificity 100,
      which beats the shared `.owner-stats-grid .stat-card` (20) rules in
      style.css without a single `!important` — and it means every other panel
      is provably untouched. Judge the direction on one screen, then widen the
      scope (or delete this file) with nothing else to unpick.

   The one global change is the TYPEFACE (see § Typeface). It cannot be judged
   on half a screen, so it applies everywhere.
   ============================================================================ */


/* ============================================================================
   1. TOKENS
   ============================================================================ */

:root {

    /* ── Typeface: Inter, and this is a SETTLED decision ─────────────────────
       My prior was to drop it — Inter is the Rhea preset's font and the most
       cited "AI default" face, so it looked like part of the problem. That
       prior was tested and lost. Robin compared seven candidates side by side
       on the real panel (Plus Jakarta Sans, DM Sans, Figtree, Nunito Sans,
       Manrope, IBM Plex Sans, Inter) and picked Inter, 2026-08-17.

       Two rejected along the way, so nobody re-proposes them: **IBM Plex Sans**
       read "too sharp and thin", and **Plus Jakarta Sans** did not beat Inter.
       The lesson worth keeping is that the dashboard never looked generic
       because of its typeface — it looked generic because of flat greyscale
       and unsystematic geometry, which is what this layer actually fixes.

       Do not re-litigate this from theory. If it is revisited, it is revisited
       the same way: rendered, side by side, judged by eye. */
    --rh-font: "Inter", ui-sans-serif, system-ui, "Segoe UI", Roboto,
               Helvetica, Arial, sans-serif;
    --rh-font-mono: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;

    /* Type scale. Compact, but a step up from the first pass — 12.5px body in a
       humanist face read as spindly, and the panel is used all day. */
    /* Bumped one step 2026-08-17: Robin, reading the real panel — "make the text little bigger, or
       pop out more, right now its more difficult to read". The first scale was tuned for density
       and undershot legibility; 11px labels on a 13px body is a spec sheet, not a dashboard. Every
       size moved up ~1px, which keeps the ratios (and so the hierarchy) and only costs vertical
       space. Re-check the product table's fixed-width Actions column against the ESTONIAN string
       after any change here — a type-scale step is what overflowed it once already. */
    --rh-t-2xs: 12px;
    --rh-t-xs:  13px;
    --rh-t-sm:  14px;
    --rh-t-md:  15px;
    --rh-t-lg:  17px;
    --rh-t-xl:  19px;
    --rh-t-2xl: 26px;

    --rh-lh-tight:  1.2;
    --rh-lh-normal: 1.5;

    /* ── Neutral ramp ────────────────────────────────────────────────────────
       Very slightly green-warm rather than the blue-grey "slate" the file uses
       today. Slate on a green brand is the Tailwind default pairing and reads
       as untouched; a neutral carrying a trace of the brand hue reads as
       chosen. The shift is small on purpose — this is a ground, not an accent. */
    --rh-n-0:   #ffffff;
    --rh-n-25:  #fbfcfb;
    --rh-n-50:  #f6f8f6;
    --rh-n-100: #eef1ef;
    --rh-n-200: #e2e6e3;
    --rh-n-300: #cdd3ce;
    --rh-n-400: #9aa39d;
    --rh-n-500: #656e67;   /* retuned 2026-08-18 — see --rh-fg-subtle below */
    --rh-n-600: #4e564f;
    --rh-n-700: #3a413b;
    --rh-n-800: #262b27;
    --rh-n-900: #171b18;
    --rh-n-950: #0d100e;

    /* ── Green ramp ─────────────────────────────────────────────────────────
       Anchored on the existing brand #27623a at step 600, so nothing that
       already uses the brand colour shifts. */
    --rh-g-50:  #f0f7f2;
    --rh-g-100: #dcebe1;
    --rh-g-200: #b9d7c4;
    --rh-g-300: #8bbb9d;
    --rh-g-400: #579a72;
    --rh-g-500: #357c51;
    --rh-g-600: #27623a;
    --rh-g-700: #1f4e2f;
    --rh-g-800: #1a3f27;
    --rh-g-900: #142f1d;

    /* ── Accent hues ─────────────────────────────────────────────────────────
       The first pass stripped ALL colour out of the stat cards and it read as
       dead (Robin, 2026-08-17). The original was not wrong to be coloured — it
       was wrong to be a RAINBOW: eight unrelated hues at eight different
       saturations, picked one at a time.

       So: six hues, each a `-soft` fill and an `-ink` mark, all tuned to
       roughly the same perceptual lightness so the row reads as one family.
       That is the whole difference between colourful and slop — a set, not an
       assortment. They are assigned by MEANING in the markup (`data-tone`), not
       by position, and repeats are deliberate: the two "is it working" cards
       share green, the two system cards share blue.

       Every pair is contrast-checked against its own soft fill; see the note on
       --rh-fg-muted below for why that is not optional here. */
    --rh-tone-green-ink:   #1f6039;   --rh-tone-green-soft:  #e6f2ea;
    --rh-tone-teal-ink:    #0d6068;   --rh-tone-teal-soft:   #e0f1f2;
    --rh-tone-blue-ink:    #1d5493;   --rh-tone-blue-soft:   #e6eefa;
    --rh-tone-violet-ink:  #61409b;   --rh-tone-violet-soft: #efe9fa;
    --rh-tone-amber-ink:   #7d4f09;   --rh-tone-amber-soft:  #faefdb;
    --rh-tone-rose-ink:    #9c3348;   --rh-tone-rose-soft:   #fae8ec;

    /* ── Status ──────────────────────────────────────────────────────────────
       Muted rather than saturated. A red that shouts on a row you scroll past
       200 times a day is a design bug, not urgency. */
    --rh-danger:        #b42318;
    --rh-danger-soft:   #fef4f2;
    --rh-danger-border: #f2cdc8;
    /* A FILLED destructive button needs a fill dark enough for white text in BOTH
       themes. --rh-danger lightens in dark (it is tuned for text ON a dark ground),
       and white on that measures about 2.6:1 — so the fill gets its own token and is
       deliberately NOT overridden in the dark block. */
    --rh-danger-solid:       #b42318;
    --rh-danger-solid-hover: #912015;
    --rh-warn:          #b54708;
    --rh-warn-soft:     #fff8ef;
    --rh-warn-border:   #f0dcc0;

    /* ── Semantic surfaces (the layer dark mode swaps) ───────────────────── */
    /* NOTE: --rh-bg is defined for the eventual page ground but is NOT consumed yet.
       `body`'s background is style.css's global `--background`, and this layer is
       scoped to :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) on purpose, so recolouring the page is a decision
       for when the tokens go global — not something to sneak in from one panel.
       Separation inside the panel comes from the sunk surfaces + borders instead. */
    --rh-bg:            var(--rh-n-100);
    --rh-surface:       var(--rh-n-0);
    --rh-surface-sunk:  var(--rh-n-100);
    --rh-surface-hover: var(--rh-n-50);
    /* Three text levels, and the two quiet ones are pinned by CONTRAST, not by taste.
       n-400 as `subtle` measured 2.59:1 on white — it looked right in a mockup and failed
       WCAG AA badly on the four places it is actually used (product category, column
       headers, the card sublabels, and the Edit/Delete glyphs). One step darker each:
       muted ≈ 7.6:1, subtle ≈ 5.3:1, and the hierarchy between them still reads.

       `subtle` was retuned again on 2026-08-18, from n-500 #6d766f to #656e67, and the
       reason is worth keeping: pinned against WHITE it measured 4.7:1 and passed, but on
       --rh-surface-sunk it measured 4.13:1 and FAILED — and three separate components put
       quiet text on a sunk background in a single session (the transcript timestamp, the
       document date, the FAQ empty state). Each was caught by measuring and fixed by hand
       to --rh-fg-muted, which is a fix that has to be remembered every time. Darkening the
       token instead clears 4.64:1 on the sunk surface and 5.28:1 on white, so the pairing
       is safe on BOTH grounds and the trap is gone rather than documented. Every existing
       consumer got more contrast, none got less. */
    --rh-fg:            var(--rh-n-900);
    --rh-fg-muted:      var(--rh-n-600);
    --rh-fg-subtle:     var(--rh-n-500);
    --rh-border:        var(--rh-n-200);
    --rh-border-strong: var(--rh-n-300);
    --rh-accent:        var(--rh-g-600);
    --rh-accent-hover:  var(--rh-g-700);
    --rh-accent-fg:     #ffffff;
    --rh-accent-soft:   var(--rh-g-50);
    --rh-accent-ink:    var(--rh-g-700);

    /* ── Geometry ────────────────────────────────────────────────────────────
       ONE radius scale. The landing page currently runs seven unrelated radii
       (3/6/8/12/18/20/99) and that inconsistency is a large part of why the UI
       reads as assembled rather than designed. Rhea's "medium" sits at 8px. */
    --rh-r-xs:   4px;
    --rh-r-sm:   6px;
    --rh-r-md:   8px;
    --rh-r-lg:   10px;
    --rh-r-xl:   14px;
    --rh-r-full: 999px;

    /* 4px spacing scale */
    --rh-s-1:  4px;
    --rh-s-2:  8px;
    --rh-s-3: 12px;
    --rh-s-4: 16px;
    --rh-s-5: 20px;
    --rh-s-6: 24px;
    --rh-s-8: 32px;

    /* ── Focus ring ──────────────────────────────────────────────────────────
       Ring-based focus is the single most characteristic Rhea behaviour: the
       control keeps its own border and gains a soft halo outside it, instead of
       swapping border colour. Static rgba rather than color-mix so it cannot
       silently fail. */
    --rh-ring:        0 0 0 3px rgba(39, 98, 58, 0.20);
    --rh-ring-danger: 0 0 0 3px rgba(180, 35, 24, 0.18);

    /* ── Elevation ───────────────────────────────────────────────────────────
       Border-first. Shadows are for things that genuinely float (menus), not
       for every card — stacked soft shadows are what makes a panel look like a
       template. */
    /* Strengthened 2026-08-17: "i liked the ui softness before, add shadows". The first pass set
       these so faint (0.04–0.06 alpha) that cards read as flat outlines — the flatness Robin
       objected to came from here, not from the borders. Raised enough to give a card a soft lift
       while staying short of a drop-shadow look. Changing the tokens lifts every consumer at once,
       so no component rule needed editing. */
    /* Raised again 2026-08-19, for the same reason as --background above: with a
       near-white ground these were carrying more of the separation than they could.
       Still short of a drop-shadow look — a card should read as lifted, not as
       floating. */
    --rh-sh-xs: 0 1px 2px rgba(13, 16, 14, 0.08);
    --rh-sh-sm: 0 1px 2px rgba(13, 16, 14, 0.09), 0 4px 10px -3px rgba(13, 16, 14, 0.14);
    --rh-sh-md: 0 2px 6px -2px rgba(13, 16, 14, 0.12), 0 14px 30px -10px rgba(13, 16, 14, 0.24);

    /* ── Motion ──────────────────────────────────────────────────────────────
       Fast enough to feel mechanical rather than animated. */
    --rh-dur:  130ms;
    --rh-ease: cubic-bezier(0.2, 0.7, 0.3, 1);
}

/* Dark mode. The dashboard toggles `body.dark-mode`, so the whole theme is one
   token block — no component below knows which theme it is in. */
body.dark-mode {
    --rh-bg:            var(--rh-n-950);
    --rh-surface:       var(--rh-n-900);
    --rh-surface-sunk:  var(--rh-n-950);
    --rh-surface-hover: var(--rh-n-800);
    --rh-fg:            var(--rh-n-50);
    --rh-fg-muted:      var(--rh-n-300);   /* mirrors the light-mode contrast fix */
    --rh-fg-subtle:     var(--rh-n-400);
    --rh-border:        var(--rh-n-800);
    --rh-border-strong: var(--rh-n-700);
    --rh-accent:        var(--rh-g-500);
    --rh-accent-hover:  var(--rh-g-400);
    --rh-accent-fg:     #ffffff;
    --rh-accent-soft:   rgba(39, 98, 58, 0.16);
    --rh-accent-ink:    var(--rh-g-200);   /* g-300 measured 3.35:1 on the soft chip */

    --rh-danger:        #f5786b;
    --rh-danger-soft:   rgba(180, 35, 24, 0.14);
    --rh-danger-border: rgba(180, 35, 24, 0.34);
    --rh-warn:          #e8a45c;
    --rh-warn-soft:     rgba(181, 71, 8, 0.14);
    --rh-warn-border:   rgba(181, 71, 8, 0.34);

    /* Dark tones: the ink lightens to a tint of the same hue, the soft fill
       becomes a low-alpha wash of it. Same six-hue family, same assignments. */
    --rh-tone-green-ink:   #7fc79a;   --rh-tone-green-soft:  rgba(58, 160, 100, 0.16);
    --rh-tone-teal-ink:    #6cc3ca;   --rh-tone-teal-soft:   rgba(45, 160, 168, 0.16);
    --rh-tone-blue-ink:    #8bb6ee;   --rh-tone-blue-soft:   rgba(64, 130, 220, 0.16);
    --rh-tone-violet-ink:  #b79bee;   --rh-tone-violet-soft: rgba(140, 100, 225, 0.16);
    --rh-tone-amber-ink:   #e3ae5f;   --rh-tone-amber-soft:  rgba(205, 140, 40, 0.16);
    --rh-tone-rose-ink:    #eb92a5;   --rh-tone-rose-soft:   rgba(215, 85, 115, 0.16);

    --rh-ring:          0 0 0 3px rgba(87, 154, 114, 0.28);
    --rh-sh-xs: 0 1px 1px rgba(0, 0, 0, 0.3);
    --rh-sh-sm: 0 1px 2px rgba(0, 0, 0, 0.3), 0 2px 6px -2px rgba(0, 0, 0, 0.4);
    --rh-sh-md: 0 2px 4px -2px rgba(0, 0, 0, 0.4), 0 10px 22px -10px rgba(0, 0, 0, 0.6);
}


/* ============================================================================
   2. TYPEFACE — the one global change
   ============================================================================ */

body,
button,
input,
select,
textarea {
    font-family: var(--rh-font);
}

/* Numbers that sit in a column must line up. Plex has tabular figures; without
   this the proportional set makes a price column visibly ragged. */
.rh-num,
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .stat-info .number,
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tbl__price,
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) #sync-quota-label,
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) #sync-progress-pct {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}


/* ============================================================================
   3. COMPONENTS — scoped to :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel)
   ----------------------------------------------------------------------------
   Everything below is inside that :is() list, so nothing here can reach a panel
   that has not opted in. Converting the next panel is therefore ONE attribute:
   put `class="rh-panel"` on its root div. No new selector text, no 153-line
   sed, and every unconverted panel stays provably untouched.

   `.rh-panel` IS THE OPT-IN, BUT THE IDS ARE LOAD-BEARING — DO NOT REMOVE THEM.
   The specificity of `:is()` is the specificity of its most specific argument,
   whichever one actually matched. With an id in the list every rule below
   weighs 100, which is what beats style.css's `.owner-stats-grid .stat-card`
   (20) and `.owner-stats-grid .stat-info .number` (30) with no `!important`
   anywhere. Collapse the list to `:is(.rh-panel)` and every one of those rules
   silently drops to 10 and loses. Keep at least one id, even after all 21
   panels carry the class.
   ============================================================================ */

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) {
    color: var(--rh-fg);
}

/* ── Stat cards ──────────────────────────────────────────────────────────────
   The six tone SETTERS below are deliberately not bound to `.stat-card`: they
   only declare two custom properties, which is inert until a rule consumes
   them, so any element in a converted panel can carry `data-tone` (the lead
   avatar does). The hairline `::before` further down stays on `.stat-card`,
   because that one paints.

   Each card carries a `data-tone` naming one of the six hues above. The tone is
   chosen by what the card MEANS, so the row is a legend rather than a
   decoration:

     green  — the catalogue, and the "is it resolving" rate  (the brand, success)
     blue   — captured leads, and AI usage                   (system / inbound)
     teal   — conversations                                  (dialogue)
     violet — knowledge base                                 (what it was taught)
     amber  — time saved                                     (effort / cost)
     rose   — lead conversion                                (performance)

   Adding a ninth card means picking one of the six, not inventing a seventh. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .owner-stats-grid {
    gap: var(--rh-s-3);
    margin-bottom: var(--rh-s-5);
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) [data-tone="green"]  { --rh-tone-ink: var(--rh-tone-green-ink);  --rh-tone-soft: var(--rh-tone-green-soft); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) [data-tone="teal"]   { --rh-tone-ink: var(--rh-tone-teal-ink);   --rh-tone-soft: var(--rh-tone-teal-soft); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) [data-tone="blue"]   { --rh-tone-ink: var(--rh-tone-blue-ink);   --rh-tone-soft: var(--rh-tone-blue-soft); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) [data-tone="violet"] { --rh-tone-ink: var(--rh-tone-violet-ink); --rh-tone-soft: var(--rh-tone-violet-soft); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) [data-tone="amber"]  { --rh-tone-ink: var(--rh-tone-amber-ink);  --rh-tone-soft: var(--rh-tone-amber-soft); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) [data-tone="rose"]   { --rh-tone-ink: var(--rh-tone-rose-ink);   --rh-tone-soft: var(--rh-tone-rose-soft); }

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .stat-card {
    background: var(--rh-surface);
    border: 1px solid var(--rh-border);
    border-radius: var(--rh-r-lg);
    box-shadow: var(--rh-sh-sm);
    padding: var(--rh-s-3) var(--rh-s-4);
    gap: var(--rh-s-3);
    align-items: center;
    transition: border-color var(--rh-dur) var(--rh-ease),
                box-shadow var(--rh-dur) var(--rh-ease);
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .stat-card:hover {
    border-color: var(--rh-border-strong);
    /* Was also --rh-sh-sm, i.e. hover changed the border and nothing else — the card did not
       respond to the pointer. One step up reads as a lift without moving the layout. */
    box-shadow: var(--rh-sh-md);
}

/* The card also carries a hairline of its own tone along the top edge — enough
   to group the row at a glance without tinting the whole card, which would make
   eight cards fight each other. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .stat-card[data-tone]::before {
    content: "";
    position: absolute;
    left: var(--rh-r-lg);
    right: var(--rh-r-lg);
    top: -1px;
    height: 2px;
    border-radius: 0 0 var(--rh-r-full) var(--rh-r-full);
    background: var(--rh-tone-ink);
    opacity: 0.55;
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .stat-icon {
    width: 36px;
    height: 36px;
    min-width: 36px;
    border-radius: var(--rh-r-md);
    font-size: 15px;
    background: var(--rh-tone-soft, var(--rh-surface-sunk));
    color: var(--rh-tone-ink, var(--rh-fg-muted));
    border: 0;
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .stat-info h3 {
    font-size: var(--rh-t-xs);
    font-weight: 600;
    color: var(--rh-fg-muted);
    letter-spacing: 0.005em;
    margin-bottom: 2px;
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .stat-info .number {
    font-size: var(--rh-t-2xl);
    font-weight: 800;
    line-height: var(--rh-lh-tight);
    letter-spacing: -0.025em;
    color: var(--rh-fg);
    margin-bottom: 1px;
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .trend {
    font-size: var(--rh-t-2xs);
    font-weight: 500;
    color: var(--rh-fg-subtle);
}

/* The Pro upsell overlay reads .stat-icon/.stat-info, so those class names stay
   as they are — only the plate it paints over is retinted. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .premium-locked::after {
    background: rgba(255, 255, 255, 0.84);
    border-radius: var(--rh-r-lg);
    font-size: var(--rh-t-xs);
    font-weight: 600;
    color: var(--rh-fg-muted);
}

body.dark-mode :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .premium-locked::after {
    background: rgba(23, 27, 24, 0.84);
}

/* ── Panel shells ───────────────────────────────────────────────────────────
   The dashed border on .test-panel is a leftover from when these really were
   test panels. A dashed rule around a customer's product catalogue reads as
   unfinished. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .test-panel {
    background: var(--rh-surface);
    border: 1px solid var(--rh-border);
    border-radius: var(--rh-r-xl);
    box-shadow: var(--rh-sh-sm);
    padding: var(--rh-s-5);
    margin-bottom: var(--rh-s-4);
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .test-panel h3 {
    font-size: var(--rh-t-lg);
    font-weight: 700;
    letter-spacing: -0.015em;
    color: var(--rh-fg);
    margin-bottom: 0;
    display: flex;
    align-items: center;
    gap: 9px;
}

/* The heading icon sits in its own tinted chip rather than floating grey next
   to the text — it gives each panel a coloured anchor and matches the stat
   cards' vocabulary instead of inventing a second one. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .test-panel h3 > i {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    flex: none;
    border-radius: var(--rh-r-sm);
    font-size: 12px;
    background: var(--rh-tone-soft, var(--rh-accent-soft));
    color: var(--rh-tone-ink, var(--rh-accent-ink));
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) #sync-control-panel    { --rh-tone-soft: var(--rh-tone-amber-soft); --rh-tone-ink: var(--rh-tone-amber-ink); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) #manual-products-panel { --rh-tone-soft: var(--rh-tone-blue-soft);  --rh-tone-ink: var(--rh-tone-blue-ink); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) #owner-products-panel  { --rh-tone-soft: var(--rh-tone-green-soft); --rh-tone-ink: var(--rh-tone-green-ink); }

/* ── Layout helpers ─────────────────────────────────────────────────────── */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-head {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: var(--rh-s-3);
    flex-wrap: wrap;
    margin-bottom: var(--rh-s-4);
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-sub {
    font-size: var(--rh-t-sm);
    color: var(--rh-fg-muted);
    line-height: var(--rh-lh-normal);
    margin: 4px 0 0;
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-row {
    display: flex;
    gap: var(--rh-s-2);
    flex-wrap: wrap;
    align-items: center;
}
/* A field sharing a row with a button must be the part that gives. The basis is 0, NOT
   auto: `auto` resolves to the field's own `width:100%`, which makes it claim the whole
   line and push the button onto the next one. min-width:0 is what lets it actually
   shrink rather than overflow the panel. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-row > .rh-input,
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-row > .rh-select { flex: 1 1 0; min-width: 0; }

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-note {
    font-size: var(--rh-t-xs);
    color: var(--rh-fg-muted);
    margin: 0;
    line-height: var(--rh-lh-normal);
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-note--ok { color: var(--rh-accent-ink); }

/* ── Buttons ─────────────────────────────────────────────────────────────────
   Rhea's press behaviour: no scale, no bounce — a 1px downward nudge and a
   slightly darker fill, so the control feels physical without animating. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--rh-s-2);
    padding: 8px 14px;
    border-radius: var(--rh-r-md);
    border: 1px solid var(--rh-border-strong);
    background: var(--rh-surface);
    color: var(--rh-fg);
    font-family: inherit;
    font-size: var(--rh-t-sm);
    font-weight: 600;
    line-height: 1.2;
    cursor: pointer;
    white-space: nowrap;
    transition: background var(--rh-dur) var(--rh-ease),
                border-color var(--rh-dur) var(--rh-ease),
                box-shadow var(--rh-dur) var(--rh-ease),
                transform var(--rh-dur) var(--rh-ease);
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-btn:hover { background: var(--rh-surface-hover); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-btn:active { transform: translateY(1px); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-btn:focus-visible { outline: none; box-shadow: var(--rh-ring); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
    transform: none;
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-btn--primary {
    background: var(--rh-accent);
    border-color: var(--rh-accent);
    color: var(--rh-accent-fg);
    font-weight: 600;
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-btn--primary:hover {
    background: var(--rh-accent-hover);
    border-color: var(--rh-accent-hover);
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-btn--danger {
    background: var(--rh-danger-soft);
    border-color: var(--rh-danger-border);
    color: var(--rh-danger);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-btn--danger:hover { background: var(--rh-danger-soft); border-color: var(--rh-danger); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-btn--danger:focus-visible { box-shadow: var(--rh-ring-danger); }

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-btn--sm {
    padding: 5px 10px;
    font-size: var(--rh-t-xs);
    border-radius: var(--rh-r-sm);
}

/* The shared .primary-btn is reused here (manual add). Retint rather than
   rename, so the setup guide's selectors keep working. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .primary-btn {
    background: var(--rh-accent);
    border: 1px solid var(--rh-accent);
    border-radius: var(--rh-r-md);
    padding: 8px 14px;
    font-size: var(--rh-t-sm);
    font-weight: 600;
    transition: background var(--rh-dur) var(--rh-ease),
                transform var(--rh-dur) var(--rh-ease);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .primary-btn:hover { background: var(--rh-accent-hover); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .primary-btn:active { transform: translateY(1px); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .primary-btn:focus-visible { outline: none; box-shadow: var(--rh-ring); }

/* Icon-only action button (table rows) */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-iconbtn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    padding: 0;
    border-radius: var(--rh-r-sm);
    border: 1px solid var(--rh-border);
    background: var(--rh-surface);
    color: var(--rh-fg-subtle);
    font-size: 11px;
    cursor: pointer;
    transition: color var(--rh-dur) var(--rh-ease),
                border-color var(--rh-dur) var(--rh-ease),
                background var(--rh-dur) var(--rh-ease);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-iconbtn:hover {
    color: var(--rh-fg);
    border-color: var(--rh-border-strong);
    background: var(--rh-surface-hover);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-iconbtn:focus-visible { outline: none; box-shadow: var(--rh-ring); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-iconbtn--danger:hover {
    color: var(--rh-danger);
    border-color: var(--rh-danger-border);
    background: var(--rh-danger-soft);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-iconbtn--danger:focus-visible { box-shadow: var(--rh-ring-danger); }

/* ── Fields ─────────────────────────────────────────────────────────────────
   Focus keeps the border and adds a ring, rather than swapping the border
   colour — that is the Rhea behaviour, and it also means focus no longer has
   to be driven by inline onfocus/onblur handlers in the markup. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-input,
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-select,
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-textarea {
    width: 100%;
    padding: 8px 11px;
    border-radius: var(--rh-r-md);
    border: 1px solid var(--rh-border-strong);
    background: var(--rh-surface);
    color: var(--rh-fg);
    font-family: inherit;
    font-size: var(--rh-t-sm);
    line-height: 1.4;
    outline: none;
    box-sizing: border-box;
    transition: border-color var(--rh-dur) var(--rh-ease),
                box-shadow var(--rh-dur) var(--rh-ease);
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-input::placeholder,
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-textarea::placeholder { color: var(--rh-fg-subtle); }

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-input:focus,
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-select:focus,
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-textarea:focus {
    border-color: var(--rh-accent);
    box-shadow: var(--rh-ring);
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-select { cursor: pointer; }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-textarea { resize: vertical; min-height: 60px; }

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-label {
    display: block;
    font-size: var(--rh-t-xs);
    font-weight: 500;
    color: var(--rh-fg-muted);
    margin-bottom: 5px;
}

/* Search field with a leading icon */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-search { position: relative; flex: 1; min-width: 180px; }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-search > i {
    position: absolute;
    left: 11px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--rh-fg-subtle);
    font-size: 11px;
    pointer-events: none;
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-search .rh-input { padding-left: 30px; }

/* ── Badges ─────────────────────────────────────────────────────────────── */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 2px 8px;
    border-radius: var(--rh-r-full);
    border: 1px solid var(--rh-border);
    background: var(--rh-surface-sunk);
    color: var(--rh-fg-muted);
    font-size: var(--rh-t-2xs);
    font-weight: 600;
    letter-spacing: 0.02em;
    white-space: nowrap;
    vertical-align: middle;
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-badge--accent {
    background: var(--rh-accent-soft);
    border-color: var(--rh-g-200);
    color: var(--rh-accent-ink);
}
body.dark-mode :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-badge--accent { border-color: var(--rh-g-800); }

/* A badge is normally a nowrap chip, but the solved note is a whole sentence and
   Estonian makes it 326px wide — measured, and it was the ONLY thing overflowing a
   375px viewport. Size chips against the Estonian string, never the English one:
   "✓ Lahendatud — kustub automaatselt 30 päeva pärast" vs "✓ Solved — auto-deletes
   in 30 days". This modifier lets that one wrap instead of pushing the card wider. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-badge--wrap { white-space: normal; }

/* STATE badges. The superadmin renderers carried these as ~40 hardcoded
   `background:#soft;color:#ink` pairs — a paid/past-due/inactive pill written out by hand at
   every site, none of which swaps theme. They are three states, not forty colours, so they
   live here once. Same reasoning as `window._rhStatus` replacing fifteen colour literals.
   Use --ok / --warn / --bad; anything else is the neutral base. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-badge--ok {
    background: var(--rh-tone-green-soft);
    border-color: transparent;
    color: var(--rh-tone-green-ink);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-badge--warn {
    background: var(--rh-warn-soft);
    border-color: var(--rh-warn-border);
    color: var(--rh-warn);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-badge--bad {
    background: var(--rh-danger-soft);
    border-color: var(--rh-danger-border);
    color: var(--rh-danger);
}
/* A badge sitting in a dense table row wants square corners and no ring, so it reads as a
   cell rather than a floating pill. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-badge--sq {
    border-radius: var(--rh-r-sm);
    border-color: transparent;
    padding: 2px 7px;
}
/* Takes whatever hue its own data-tone sets, so a category chip names a MEANING and never a
   colour. Soft ground + ink text rather than a solid fill: the ink tokens are tuned for text
   on the soft ground (5.98-7.02:1) and would only reach ~3.5:1 under white on a solid fill. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-badge--tone {
    background: var(--rh-tone-soft, var(--rh-surface-sunk));
    border-color: transparent;
    color: var(--rh-tone-ink, var(--rh-fg-muted));
}

/* ── Action button (the superadmin store row's Manage menu) ──────────────────
   Every one of these was an inline `background:#soft;color:#ink;border:1px solid #mid`
   triple — sixty literals for what is really ONE button with a hue and an on/off state,
   and not one of them swapped theme. It takes its hue from its own data-tone, so the
   markup names a MEANING (rename=blue, access log=violet, handover=green, pilot=teal)
   and never a colour.

   `.is-on` is the toggled state — white-label granted, pilot running, B2B, marked demo.
   Those four used to hardcode a solid fill plus `color:#fff` for the on case and a soft
   fill for the off case, in the same attribute, which is why they read as four different
   controls. Same fix as the Installation panel's gateway cards and setLauncherShape. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .action-btn.rh-act {
    background: var(--rh-tone-soft, var(--rh-surface-sunk));
    color: var(--rh-tone-ink, var(--rh-fg-muted));
    border: 1px solid color-mix(in srgb, var(--rh-tone-ink, var(--rh-fg-muted)) 26%, transparent);
    transition: background var(--rh-dur) var(--rh-ease), border-color var(--rh-dur) var(--rh-ease);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .action-btn.rh-act:hover {
    background: color-mix(in srgb, var(--rh-tone-ink, var(--rh-fg-muted)) 13%, var(--rh-surface));
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .action-btn.rh-act:focus-visible {
    outline: 2px solid var(--rh-ring);
    outline-offset: 2px;
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .action-btn.rh-act.is-on {
    background: var(--rh-tone-ink, var(--rh-accent));
    color: var(--rh-surface);
    border-color: transparent;
}
/* Delete is a STATE, not a hue: it keeps its own danger pair so a red control can never
   read as a seventh tone. Solid only once the owner has actually requested deletion. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .action-btn.rh-act--danger {
    background: var(--rh-danger-soft);
    color: var(--rh-danger);
    border: 1px solid var(--rh-danger-border);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .action-btn.rh-act--danger.is-on {
    background: var(--rh-danger-solid);
    color: #fff;
    border-color: transparent;
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .action-btn.rh-act--danger:focus-visible {
    outline: 2px solid var(--rh-ring-danger);
    outline-offset: 2px;
}

/* `.test-panel h3` takes style.css's `--secondary`, a #6366f1 indigo that is (a) outside the
   six-hue vocabulary entirely and (b) a single value for both themes. Measured in a browser:
   4.27:1 light and 4.28:1 dark — an AA failure in BOTH, which is exactly what a colour that
   never swaps looks like. Scoped to converted panels only, so unconverted owner panels that
   also use .test-panel keep their current appearance until they are converted too.
   The heading text is plain foreground; the ICON carries the panel's tone. */
/* Both forms are needed: #admin-upgrades-panel WRAPS a .test-panel (descendant), while
   #admin-alerts-panel carries `class="test-panel rh-panel"` on the SAME element, which a
   descendant selector cannot reach. Measured, not assumed — the descendant-only version
   left the alerts heading at 4.27:1. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .test-panel h3,
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel).test-panel h3 {
    color: var(--rh-fg);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .test-panel h3 > i,
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel).test-panel h3 > i,
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-phead > i {
    color: var(--rh-tone-ink, var(--rh-fg-muted));
}

/* A wide table scrolls inside its OWN container; the page body must never scroll sideways.
   Measured at 1180px: the 8-column store table is 1285px in a 1078px container that was
   `overflow-x: visible`, so the whole document scrolled horizontally. #admin-engagement-panel
   already wrapped its table correctly — these two did not. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) #stores-table-container,
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) #upgrades-tbody-wrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

/* Store identity: name, owner email and store id are three facts about ONE entity, so they are
   one column, not three. Measured at 1280px (a 260px sidebar leaves ~956px): the 8-column table
   was 1285px and forced the page to scroll sideways. Stacking these is what buys it back. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .store-ident strong {
    font-size: var(--rh-t-sm);
    font-weight: 700;
    color: var(--rh-fg);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .store-ident__auto {
    display: inline-block;
    margin-left: 6px;
    font-size: var(--rh-t-2xs);
    font-weight: 600;
    color: var(--rh-tone-green-ink);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .store-ident__sub {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 3px 8px;
    margin-top: 3px;
    font-size: var(--rh-t-2xs);
    color: var(--rh-fg-muted);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .store-ident__sub code {
    font-family: var(--rh-font-mono);
    font-size: 10.5px;
    color: var(--rh-fg-subtle);
    background: var(--rh-surface-sunk);
    padding: 1px 5px;
    border-radius: var(--rh-r-xs);
}

/* ── Meter (sync quota + sync progress) ─────────────────────────────────────
   Flat fill, no gradient. A two-stop gradient on a 8px bar is invisible as a
   gradient and reads only as "generic dashboard". */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-meter {
    height: 6px;
    background: var(--rh-n-200);
    border-radius: var(--rh-r-full);
    overflow: hidden;
}
body.dark-mode :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-meter { background: var(--rh-n-800); }

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-meter__fill {
    height: 100%;
    background: var(--rh-accent);
    border-radius: var(--rh-r-full);
    transition: width 0.5s var(--rh-ease);
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-meter--lg { height: 8px; }

/* ── CSV drop zone ─────────────────────────────────────────────────────────
   Drag state is a class now, not inline style mutation, so the hover/valid
   colours live in one place. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-drop {
    border: 1.5px dashed var(--rh-border-strong);
    border-radius: var(--rh-r-lg);
    padding: var(--rh-s-5);
    background: var(--rh-surface-sunk);
    text-align: center;
    cursor: pointer;
    transition: border-color var(--rh-dur) var(--rh-ease),
                background var(--rh-dur) var(--rh-ease);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-drop.is-over {
    border-color: var(--rh-accent);
    background: var(--rh-accent-soft);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-drop > i {
    font-size: 20px;
    color: var(--rh-fg-subtle);
    margin-bottom: var(--rh-s-2);
    display: block;
}

/* ── Disclosure (CSV fallback) ─────────────────────────────────────────── */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-details {
    margin-top: var(--rh-s-5);
    border-top: 1px solid var(--rh-border);
    padding-top: var(--rh-s-3);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-details > summary {
    cursor: pointer;
    list-style: none;
    font-size: var(--rh-t-sm);
    font-weight: 500;
    color: var(--rh-fg-muted);
    display: flex;
    align-items: center;
    gap: var(--rh-s-2);
    padding: 2px 0;
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-details > summary::-webkit-details-marker { display: none; }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-details > summary:hover { color: var(--rh-fg); }

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-well {
    background: var(--rh-surface-sunk);
    border: 1px solid var(--rh-border);
    border-radius: var(--rh-r-lg);
    padding: var(--rh-s-3) var(--rh-s-4);
    margin: var(--rh-s-3) 0;
    font-size: var(--rh-t-sm);
    color: var(--rh-fg-muted);
    line-height: 1.65;
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-well strong { color: var(--rh-fg); font-weight: 600; }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-well code {
    font-family: var(--rh-font-mono);
    font-size: 11px;
    background: var(--rh-n-100);
    border-radius: var(--rh-r-xs);
    padding: 1px 5px;
    color: var(--rh-accent-ink);
}
body.dark-mode :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-well code { background: var(--rh-n-800); }

/* ── Product table ─────────────────────────────────────────────────────────
   One shared column template so the header and every row cannot drift apart.
   Zebra striping is gone: with a 1px rule between rows it adds nothing but
   noise, and it was implemented as a per-row inline background that had to be
   restored by inline mouseenter/mouseleave handlers. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tbl {
    /* The last column is sized for the ESTONIAN header "Tegevused", not the English
       "Actions" — it is the wider word, and a column measured against English copy
       spills. It has bitten twice now (once on a font change, once when the type scale
       went up one step), so it carries headroom rather than a snug fit. */
    /* Widened again 2026-08-17 with the type-scale step (--rh-t-2xs 11px → 12px). Uppercase
       "TEGEVUSED" at 12px/600 with 0.06em tracking measures ~73px of glyphs before cell padding,
       and the old 82px was already snug at 11px. All three fixed columns grew ~10% so the ratios
       hold; the name column is minmax(0, 1fr) and absorbs the 24px. */
    --rh-cols: 40px minmax(0, 1fr) 104px 92px 92px;
    border: 1px solid var(--rh-border);
    border-radius: var(--rh-r-lg);
    overflow: hidden;
    background: var(--rh-surface);
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tbl__head,
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tbl__row {
    display: grid;
    grid-template-columns: var(--rh-cols);
    gap: var(--rh-s-2);
    align-items: center;
    padding: 8px 12px;
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tbl__head {
    background: var(--rh-surface-sunk);
    border-bottom: 1px solid var(--rh-border);
    font-size: var(--rh-t-2xs);
    font-weight: 600;
    /* muted, not subtle: at 10.5px this is small text, and subtle-on-sunk measured
       4.40:1 — just under AA. The uppercase + tracking already separate it from the rows. */
    color: var(--rh-fg-muted);
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tbl__row {
    border-top: 1px solid var(--rh-border);
    transition: background var(--rh-dur) var(--rh-ease);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tbl__row:first-of-type { border-top: none; }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tbl__row:hover { background: var(--rh-surface-hover); }

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tbl__thumbcell { line-height: 0; }

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tbl__thumb,
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tbl__thumb--empty {
    width: 32px;
    height: 32px;
    border-radius: var(--rh-r-sm);
    object-fit: cover;
    border: 1px solid var(--rh-border);
    flex-shrink: 0;
    background: var(--rh-surface-sunk);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tbl__thumb--empty {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--rh-fg-subtle);
    font-size: 11px;
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tbl__namecell { min-width: 0; }

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tbl__name {
    font-size: var(--rh-t-sm);
    font-weight: 600;
    color: var(--rh-fg);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tbl__cat {
    font-size: var(--rh-t-2xs);
    color: var(--rh-fg-subtle);
    margin-top: 1px;
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tbl__link {
    display: block;
    margin-top: 1px;
    font-size: var(--rh-t-2xs);
    color: var(--rh-fg-muted);
    text-decoration: none;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 260px;
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tbl__link:hover { color: var(--rh-accent-ink); text-decoration: underline; }

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tbl__price {
    font-size: var(--rh-t-sm);
    font-weight: 700;
    color: var(--rh-fg);
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tbl__actions {
    display: flex;
    gap: var(--rh-s-1);
    justify-content: flex-end;
}

/* Stock is one of the few places colour earns its keep — it is a state the
   owner has to act on. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-stock {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: var(--rh-t-2xs);
    font-weight: 500;
    color: var(--rh-fg-muted);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-stock::before {
    content: "";
    width: 6px;
    height: 6px;
    border-radius: var(--rh-r-full);
    background: var(--rh-accent);
    flex-shrink: 0;
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-stock--out { color: var(--rh-danger); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-stock--out::before { background: var(--rh-danger); }

/* ── Table chrome: count line + pager ──────────────────────────────────── */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tblbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--rh-s-2);
    flex-wrap: wrap;
    margin-bottom: var(--rh-s-2);
    font-size: var(--rh-t-xs);
    color: var(--rh-fg-muted);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tblbar em {
    font-style: normal;
    color: var(--rh-accent-ink);
    font-weight: 600;
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-pager {
    display: flex;
    align-items: center;
    gap: var(--rh-s-1);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-pager__num {
    width: 46px;
    padding: 4px 6px;
    text-align: center;
    border-radius: var(--rh-r-sm);
    border: 1px solid var(--rh-border-strong);
    background: var(--rh-surface);
    color: var(--rh-fg);
    font-family: inherit;
    font-size: var(--rh-t-xs);
    font-variant-numeric: tabular-nums;
    outline: none;
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-pager__num:focus { border-color: var(--rh-accent); box-shadow: var(--rh-ring); }

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-foot {
    text-align: center;
    margin-top: var(--rh-s-2);
    font-size: var(--rh-t-2xs);
    color: var(--rh-fg-subtle);
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-empty {
    padding: var(--rh-s-6) var(--rh-s-4);
    text-align: center;
    color: var(--rh-fg-muted);
    font-size: var(--rh-t-sm);
}

/* ── Inline form (manual add) ──────────────────────────────────────────── */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-form {
    background: var(--rh-surface-sunk);
    border: 1px solid var(--rh-border);
    border-radius: var(--rh-r-lg);
    padding: var(--rh-s-4);
    margin-bottom: var(--rh-s-4);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-form h4 {
    font-size: var(--rh-t-md);
    font-weight: 600;
    color: var(--rh-fg);
    margin-bottom: var(--rh-s-3);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-grid2 {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--rh-s-2);
    margin-bottom: var(--rh-s-2);
}

/* ── Responsive ──────────────────────────────────────────────────────────────
   Breakpoints match the ones already in style.css (768 / 640) rather than
   inventing new ones.

   The row does NOT drop columns on a phone. Hiding the actions cell to make
   the grid fit would silently remove Edit and Delete on mobile — the owner
   would have no way to correct a product from their phone, which is worse than
   a slightly taller row. At ≤640 the row becomes a wrapping flex line instead:
   thumbnail + name on the first line, price / stock / actions indented on the
   second. Everything stays present and tappable. */
@media (max-width: 768px) {
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tbl { --rh-cols: 36px minmax(0, 1fr) 84px 76px 80px; }
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tbl__head,
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tbl__row { padding: 8px 10px; }
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-grid2 { grid-template-columns: 1fr; }
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .test-panel { padding: var(--rh-s-4); }
}

@media (max-width: 640px) {
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tbl__head { display: none; }

    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tbl__row {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: 7px 10px;
        padding: 10px 12px;
    }
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tbl__namecell  { flex: 1 1 calc(100% - 46px); min-width: 0; }
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tbl__price     { flex: 0 0 auto; margin-left: 42px; }
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tbl__stockcell { flex: 1 1 auto; }
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tbl__actions   { flex: 0 0 auto; }
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-tbl__link      { max-width: none; }

    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-head { flex-direction: column; align-items: stretch; }
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-head .rh-row > .rh-btn { flex: 1; }

    /* A phone-width viewport is a touch device in practice even when the browser
       reports a fine pointer (device emulation, a narrowed window on a 2-in-1), so the
       row buttons get real targets here as well as under (pointer: coarse). */
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-iconbtn { width: 38px; height: 38px; font-size: 13px; }

    /* The URL field and the Sync button will not both fit on one 375px line — the field
       was squeezed to ~146px, too narrow to read a domain in. Let the button drop below
       and take the full width. */
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) #sync-form-section .rh-row { flex-wrap: wrap; }
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) #sync-form-section .rh-row > .rh-input { flex: 1 1 100%; }
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) #magic-sync-btn { flex: 1 1 100%; }

    /* Same for the catalog's search + sort pair. */
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-search { flex: 1 1 100%; }
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) #prod-sort { width: 100% !important; flex: 1 1 100% !important; }
}

/* Touch devices get real targets regardless of viewport width — an iPad in
   landscape is 1024px wide and still has no cursor. 26px is fine for a mouse
   and unusable with a thumb. */
@media (pointer: coarse) {
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-iconbtn { width: 38px; height: 38px; font-size: 13px; }
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-btn     { padding: 10px 16px; }
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-btn--sm { padding: 8px 12px; }
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-details > summary { padding: 8px 0; }
}

/* iOS Safari zooms the page in when a focused field's text is under 16px.
   Bumping the font size on touch keeps the layout still when the owner taps a
   field — the same reason the widget's composer does it. */
@media (pointer: coarse) and (max-width: 768px) {
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-input,
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-select,
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-textarea,
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-pager__num { font-size: 16px; }
}

@media (prefers-reduced-motion: reduce) {
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) * { transition-duration: 1ms !important; }
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-btn:active,
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .primary-btn:active { transform: none; }
}

/* ============================================================================
   4. LIST PANELS — the Leads inbox and the Conversations log
   ----------------------------------------------------------------------------
   Both panels are a header, one filter row, and a stack of records; the records
   differ but the chrome does not. So the components here are shared, and a
   third list panel (the superadmin store table is the obvious next one) should
   reuse them rather than grow a fourth vocabulary.
   ============================================================================ */

/* ── Panel header ───────────────────────────────────────────────────────────
   The panel-level h2 had no component at all — every panel hand-rolled it as
   inline styles, which is why Analytics, Leads and Conversations each had a
   slightly different heading. Same icon-chip treatment as `.test-panel h3` so a
   panel title and a card title read as one system, one step larger. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-phead {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: var(--rh-s-3);
    flex-wrap: wrap;
    margin-bottom: var(--rh-s-5);
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-phead h2 {
    font-size: var(--rh-t-xl);
    font-weight: 700;
    letter-spacing: -0.02em;
    color: var(--rh-fg);
    margin: 0;
    display: flex;
    align-items: center;
    gap: 10px;
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-phead h2 > i {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    flex: none;
    border-radius: var(--rh-r-md);
    font-size: 13px;
    background: var(--rh-tone-soft, var(--rh-accent-soft));
    color: var(--rh-tone-ink, var(--rh-accent-ink));
}

/* Tone by MEANING, from the same six-hue set as the stat cards — leads are the
   blue "inbound" family and conversations the teal "dialogue" one, matching the
   Home-panel cards that count them. */
#leads-panel         { --rh-tone-soft: var(--rh-tone-blue-soft); --rh-tone-ink: var(--rh-tone-blue-ink); }
#conversations-panel { --rh-tone-soft: var(--rh-tone-teal-soft); --rh-tone-ink: var(--rh-tone-teal-ink); }

/* ── Segmented control (lead status tabs) ───────────────────────────────────
   A sunk track with the active option raised out of it. The active state used
   to be four inline style writes in switchLeadTab; it is `.is-on` now, so the
   tab colours live here and cannot drift from the markup's initial state.
   Colour is carried by the TEXT, not by a filled green pill — a filled tab
   beside a filled Refresh button gives one row two primaries. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-seg {
    display: inline-flex;
    gap: 2px;
    padding: 3px;
    background: var(--rh-surface-sunk);
    border: 1px solid var(--rh-border);
    border-radius: var(--rh-r-md);
    flex: none;
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-seg__btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 13px;
    border: 1px solid transparent;
    border-radius: var(--rh-r-sm);
    background: transparent;
    color: var(--rh-fg-muted);
    font-family: inherit;
    font-size: var(--rh-t-xs);
    font-weight: 600;
    line-height: 1.2;
    cursor: pointer;
    white-space: nowrap;
    transition: background var(--rh-dur) var(--rh-ease),
                color var(--rh-dur) var(--rh-ease);
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-seg__btn:hover { color: var(--rh-fg); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-seg__btn:focus-visible { outline: none; box-shadow: var(--rh-ring); }

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-seg__btn.is-on {
    background: var(--rh-surface);
    border-color: var(--rh-border);
    color: var(--rh-accent-ink);
    box-shadow: var(--rh-sh-xs);
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-seg__n {
    border-radius: var(--rh-r-full);
    padding: 1px 7px;
    background: var(--rh-surface);
    color: var(--rh-fg-muted);
    font-size: var(--rh-t-2xs);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-seg__btn.is-on .rh-seg__n {
    background: var(--rh-accent-soft);
    color: var(--rh-accent-ink);
}

/* ── Checkbox row ───────────────────────────────────────────────────────── */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-check {
    display: inline-flex;
    align-items: center;
    gap: var(--rh-s-2);
    font-size: var(--rh-t-xs);
    color: var(--rh-fg-muted);
    cursor: pointer;
    user-select: none;
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-check input {
    width: 16px;
    height: 16px;
    margin: 0;
    accent-color: var(--rh-accent);
    cursor: pointer;
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-check:hover { color: var(--rh-fg); }

/* The one filter row every list panel has: a search field, and beside it
   whatever narrows the list (status tabs, an archived toggle). Its own class
   rather than `.rh-row` + an inline margin, so the spacing below the filters is
   one number in one place. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-filters {
    display: flex;
    align-items: center;
    gap: var(--rh-s-3);
    flex-wrap: wrap;
    margin-bottom: var(--rh-s-4);
}

/* ── Record card ────────────────────────────────────────────────────────────
   One card shape for a lead and for a conversation. State is a border tint plus
   a badge, never a wash of colour across the whole card: a green-filled solved
   lead read as a success message rather than as a closed record, and it was the
   one place the list carried two different backgrounds at once. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-item {
    background: var(--rh-surface);
    border: 1px solid var(--rh-border);
    border-radius: var(--rh-r-lg);
    box-shadow: var(--rh-sh-xs);
    padding: var(--rh-s-4);
    margin-bottom: var(--rh-s-2);
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-item--done { border-color: var(--rh-g-200); }
body.dark-mode :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-item--done { border-color: var(--rh-g-800); }

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-item__row {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: var(--rh-s-3);
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-item__body { flex: 1 1 0; min-width: 0; }

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-item__id {
    display: flex;
    align-items: center;
    gap: var(--rh-s-3);
    min-width: 0;
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-item__id > div { min-width: 0; }

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-item__title {
    font-size: var(--rh-t-sm);
    font-weight: 600;
    color: var(--rh-fg);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-item__meta {
    display: flex;
    align-items: center;
    gap: var(--rh-s-2);
    flex-wrap: wrap;
    margin-top: 3px;
    font-size: var(--rh-t-2xs);
    color: var(--rh-fg-subtle);
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-item__acts {
    display: flex;
    align-items: center;
    gap: var(--rh-s-1);
    flex: none;
    flex-wrap: wrap;
    justify-content: flex-end;
}

/* The initial in a tinted disc, from the six-hue set — a saturated brand fill
   with white text on every row made the list read as a column of buttons. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    flex: none;
    border-radius: var(--rh-r-full);
    background: var(--rh-tone-soft, var(--rh-accent-soft));
    color: var(--rh-tone-ink, var(--rh-accent-ink));
    font-size: var(--rh-t-sm);
    font-weight: 700;
    line-height: 1;
}

/* ── Quoted summary (the AI read of a lead) ─────────────────────────────── */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-quote {
    margin-top: var(--rh-s-2);
    padding: var(--rh-s-2) var(--rh-s-3);
    background: var(--rh-surface-sunk);
    border-left: 3px solid var(--rh-tone-ink, var(--rh-accent));
    border-radius: 0 var(--rh-r-sm) var(--rh-r-sm) 0;
    font-size: var(--rh-t-xs);
    color: var(--rh-fg);
    line-height: var(--rh-lh-normal);
}

/* ── Verbatim transcript ────────────────────────────────────────────────────
   --rh-fg-muted, not --rh-fg-subtle: subtle is pinned against white and
   measures 4.13:1 on a sunk surface, which is below AA. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-pre {
    margin: var(--rh-s-3) 0 0;
    padding: var(--rh-s-3);
    background: var(--rh-surface-sunk);
    border: 1px solid var(--rh-border);
    border-radius: var(--rh-r-md);
    font-family: var(--rh-font-mono);
    font-size: var(--rh-t-2xs);
    color: var(--rh-fg-muted);
    line-height: 1.65;
    max-height: 220px;
    overflow-y: auto;
    overflow-wrap: anywhere;
}

/* ── Empty and error states ───────────────────────────────────────────────── */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-empty--lg { padding: var(--rh-s-8) var(--rh-s-4); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-empty--lg > i {
    display: block;
    font-size: 30px;
    margin-bottom: var(--rh-s-3);
    color: var(--rh-fg-subtle);
    opacity: 0.65;
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-err {
    padding: var(--rh-s-4) 0;
    font-size: var(--rh-t-sm);
    color: var(--rh-danger);
}

/* Two more icon-button intents. The check and the reopen arrow are the only
   glyphs in these panels that carry meaning on their own, so they keep a tone
   in rest state; everything else stays neutral until hover. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-iconbtn--ok { color: var(--rh-tone-green-ink); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-iconbtn--ok:hover {
    color: var(--rh-tone-green-ink);
    background: var(--rh-tone-green-soft);
    border-color: var(--rh-g-200);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-iconbtn--warn { color: var(--rh-tone-amber-ink); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-iconbtn--warn:hover {
    color: var(--rh-tone-amber-ink);
    background: var(--rh-tone-amber-soft);
    border-color: var(--rh-warn-border);
}

/* ── Conversation record: a real <details> ───────────────────────────────────
   The old row toggled `style.display` from two separate inline handlers and
   kept a "▼"/"▲" text chevron in sync by hand — and one of those handlers read
   `this.closest('div')`, which resolves to the clicked element itself, so it
   threw on every body click and that chevron never turned. <details> removes
   the state, the sync and the keyboard gap in one go. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-conv {
    background: var(--rh-surface);
    border: 1px solid var(--rh-border);
    border-radius: var(--rh-r-lg);
    box-shadow: var(--rh-sh-xs);
    margin-bottom: var(--rh-s-2);
    overflow: hidden;
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-conv > summary {
    display: flex;
    align-items: center;
    gap: var(--rh-s-3);
    padding: var(--rh-s-3) var(--rh-s-4);
    cursor: pointer;
    list-style: none;
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-conv > summary::-webkit-details-marker { display: none; }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-conv > summary:hover { background: var(--rh-surface-hover); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-conv > summary:focus-visible { outline: none; box-shadow: var(--rh-ring); }

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-conv__icon {
    flex: none;
    font-size: 14px;
    color: var(--rh-fg-subtle);
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-conv__sid {
    font-family: var(--rh-font-mono);
    font-size: var(--rh-t-2xs);
    color: var(--rh-fg-muted);
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-conv__preview {
    margin-top: 2px;
    font-size: var(--rh-t-xs);
    color: var(--rh-fg);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-conv__chev {
    flex: none;
    font-size: 11px;
    color: var(--rh-fg-subtle);
    transition: transform var(--rh-dur) var(--rh-ease);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-conv[open] > summary .rh-conv__chev { transform: rotate(180deg); }

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-thread {
    padding: var(--rh-s-4);
    border-top: 1px solid var(--rh-border);
    background: var(--rh-surface-sunk);
    max-height: 420px;
    overflow-y: auto;
}

/* ── Transcript bubbles ─────────────────────────────────────────────────── */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-msg {
    display: flex;
    gap: var(--rh-s-2);
    align-items: flex-end;
    margin-bottom: var(--rh-s-3);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-msg--user { flex-direction: row-reverse; }

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-msg__av {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    flex: none;
    border-radius: var(--rh-r-full);
    background: var(--rh-surface-hover);
    color: var(--rh-fg-muted);
    font-size: 11px;
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-msg--user .rh-msg__av {
    background: var(--rh-accent);
    color: var(--rh-accent-fg);
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-msg__col { max-width: 75%; }

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-msg__bub {
    padding: 9px 13px;
    border: 1px solid var(--rh-border);
    border-radius: var(--rh-r-xl) var(--rh-r-xl) var(--rh-r-xl) var(--rh-r-xs);
    background: var(--rh-surface);
    color: var(--rh-fg);
    font-size: var(--rh-t-xs);
    line-height: 1.55;
    overflow-wrap: anywhere;
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-msg--user .rh-msg__bub {
    background: var(--rh-accent);
    border-color: var(--rh-accent);
    color: var(--rh-accent-fg);
    border-radius: var(--rh-r-xl) var(--rh-r-xl) var(--rh-r-xs) var(--rh-r-xl);
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-msg__time {
    margin-top: 3px;
    font-size: var(--rh-t-2xs);
    /* --rh-fg-muted, NOT --rh-fg-subtle: the bubbles sit on --rh-surface-sunk, and
       subtle is pinned against white — it measures 4.13:1 there, below AA. */
    color: var(--rh-fg-muted);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-msg--user .rh-msg__time { text-align: right; }

/* ── Plan wall (older conversations withheld on trial/Starter) ───────────────
   Amber from the six-hue set instead of the old #fefce8 / #facc15 / #854d0e
   trio, which was a fourth yellow and never swapped in dark mode. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-wall {
    margin-top: var(--rh-s-4);
    padding: var(--rh-s-6);
    text-align: center;
    background: var(--rh-tone-amber-soft);
    border: 1px dashed var(--rh-warn-border);
    border-radius: var(--rh-r-xl);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-wall > i {
    display: block;
    font-size: 22px;
    margin-bottom: var(--rh-s-3);
    color: var(--rh-tone-amber-ink);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-wall h3 {
    margin: 0 0 var(--rh-s-2);
    font-size: var(--rh-t-md);
    font-weight: 700;
    color: var(--rh-fg);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-wall p {
    margin: 0 0 var(--rh-s-4);
    font-size: var(--rh-t-xs);
    color: var(--rh-fg-muted);
}

/* ── Responsive: the record cards ───────────────────────────────────────────
   The actions must never be hidden to make a card fit — same rule as the
   product table. Below 640 they move under the record instead. */
@media (max-width: 640px) {
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-item__row { flex-wrap: wrap; }
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-item__acts { flex: 1 1 100%; justify-content: flex-start; }
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-seg { flex: 1 1 100%; }
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-seg__btn { flex: 1 1 0; justify-content: center; }
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-msg__col { max-width: 84%; }
}

/* ============================================================================
   5. KNOWLEDGE BASE — the Pro blocks, and the widget-FAQ curator
   ----------------------------------------------------------------------------
   This panel used to carry its own <style> element inline in index.html. Those
   rules are here now, with their CLASS NAMES UNCHANGED (.kb-pro-*, .faq-*):
   `renderFaqManager` and `_wireFaqDrag` select on them, so renaming would have
   silently broken publishing and drag-reordering. Same reasoning as retinting
   `.primary-btn` and `.stat-card` rather than renaming them.

   Panel tone is VIOLET, from the six-hue set — violet is already "what the AI
   was taught" on the stat cards, and this is the panel where you teach it.
   ============================================================================ */

#owner-kb-panel { --rh-tone-soft: var(--rh-tone-violet-soft); --rh-tone-ink: var(--rh-tone-violet-ink); }

/* ── The Pro gate ───────────────────────────────────────────────────────────
   Shown-but-locked, never hidden: a locked control that names the plan sells
   the upgrade, a missing one just looks like a feature we do not have. The
   SERVER is the real gate — this is only the affordance. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .kb-pro-badge {
    display: inline-flex;
    align-items: center;
    padding: 1px 6px;
    border-radius: var(--rh-r-xs);
    background: var(--rh-tone-violet-soft);
    color: var(--rh-tone-violet-ink);
    font-size: var(--rh-t-2xs);
    font-weight: 800;
    letter-spacing: 0.06em;
    vertical-align: middle;
    margin-left: 4px;
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .kb-pro-block[data-locked="true"] { opacity: 0.6; }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .kb-pro-block[data-locked="true"] textarea,
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .kb-pro-block[data-locked="true"] button,
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .kb-pro-block[data-locked="true"] label { cursor: not-allowed; }

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .kb-pro-upsell {
    margin-top: var(--rh-s-2);
    font-size: var(--rh-t-xs);
    font-weight: 600;
    color: var(--rh-tone-violet-ink);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .kb-pro-upsell a {
    color: inherit;
    text-decoration: underline;
    cursor: pointer;
}

/* ── A sub-section inside a panel ───────────────────────────────────────────
   The KB panel is one .test-panel holding five distinct jobs, so each needs a
   surface of its own. Sunk + solid border, NOT the dashed box it used to be:
   dashed means "drop a file here", which is exactly one of these five and not
   the other four. `.rh-drop` still carries the dashed treatment for the upload
   block, where it is true. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-sect {
    background: var(--rh-surface-sunk);
    border: 1px solid var(--rh-border);
    border-radius: var(--rh-r-lg);
    padding: var(--rh-s-4);
    margin-bottom: var(--rh-s-4);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-sect__t {
    display: flex;
    align-items: center;
    gap: 7px;
    margin: 0 0 var(--rh-s-1);
    font-size: var(--rh-t-sm);
    font-weight: 700;
    color: var(--rh-fg);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-sect__t > i { color: var(--rh-tone-ink, var(--rh-accent-ink)); font-size: 13px; }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-sect__t .rh-quiet { font-weight: 400; color: var(--rh-fg-muted); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-sect > p.rh-note { margin-bottom: var(--rh-s-3); }

/* A section on the raised surface rather than the sunk one — for the FAQ
   curator, which contains its own two sunk columns and would otherwise be a
   sunk box inside a sunk box. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-sect--raised { background: var(--rh-surface); }

/* ── Status line that JS writes into ────────────────────────────────────────
   These were `style.color = '#10b981' | '#ef4444' | '#6b7280'` from a dozen
   places, which is three literals per call site and none of them theme-aware.
   The renderers set a CLASS now. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-status {
    margin: var(--rh-s-2) 0 0;
    font-size: var(--rh-t-xs);
    font-weight: 500;
    min-height: 16px;
    color: var(--rh-fg-muted);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-status.is-ok   { color: var(--rh-tone-green-ink); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-status.is-bad  { color: var(--rh-danger); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-status.is-busy { color: var(--rh-fg-muted); }

/* ── Widget-FAQ curator ─────────────────────────────────────────────────────
   Two columns, each independently scrollable, so a store with hundreds of
   entries cannot stretch the page. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .faq-mgr-cols {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--rh-s-3);
}
@media (max-width: 820px) {
    :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .faq-mgr-cols { grid-template-columns: 1fr; }
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .faq-col {
    border: 1px solid var(--rh-border);
    border-radius: var(--rh-r-md);
    background: var(--rh-surface-sunk);
    min-height: 120px;
    max-height: 260px;
    overflow-y: auto;
    padding: 6px;
}

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .faq-item {
    display: flex;
    align-items: center;
    gap: var(--rh-s-2);
    background: var(--rh-surface);
    border: 1px solid var(--rh-border);
    border-radius: var(--rh-r-sm);
    padding: 7px 9px;
    margin-bottom: 5px;
    font-size: var(--rh-t-xs);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .faq-item:last-child { margin-bottom: 0; }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .faq-item .q {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--rh-fg);
    font-weight: 600;
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .faq-item .num {
    flex: none;
    width: 16px;
    font-size: var(--rh-t-2xs);
    font-weight: 800;
    color: var(--rh-fg-subtle);
    font-variant-numeric: tabular-nums;
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .faq-item button {
    flex: none;
    padding: 2px 5px;
    border: 0;
    border-radius: var(--rh-r-xs);
    background: transparent;
    font-size: 13px;
    cursor: pointer;
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .faq-item button:focus-visible { outline: none; box-shadow: var(--rh-ring); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .faq-item .rm { color: var(--rh-danger); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .faq-item .rm:hover { background: var(--rh-danger-soft); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .faq-item .add { color: var(--rh-accent-ink); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .faq-item .add:hover { background: var(--rh-accent-soft); }

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .faq-pub { cursor: grab; }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .faq-pub .grip { flex: none; cursor: grab; color: var(--rh-fg-subtle); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .faq-pub.dragging { opacity: 0.4; }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .faq-pub.over {
    border-color: var(--rh-accent);
    box-shadow: 0 -2px 0 0 var(--rh-accent);
}

/* fg-MUTED, not fg-subtle: this sits on .faq-col, which is the SUNK surface,
   where subtle measures 4.13:1 in light mode — below AA. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .faq-empty {
    padding: 22px var(--rh-s-2);
    text-align: center;
    font-size: var(--rh-t-xs);
    color: var(--rh-fg-muted);
}

/* ── The generated-FAQ candidates (tickable, nothing saved until picked) ──── */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-pick {
    display: flex;
    align-items: flex-start;
    gap: var(--rh-s-2);
    background: var(--rh-surface);
    border: 1px solid var(--rh-border);
    border-radius: var(--rh-r-md);
    padding: 9px 10px;
    margin-bottom: 6px;
    cursor: pointer;
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-pick:hover { border-color: var(--rh-border-strong); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-pick input {
    width: 15px;
    height: 15px;
    margin-top: 2px;
    flex: none;
    accent-color: var(--rh-accent);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-pick__q {
    display: block;
    font-size: var(--rh-t-xs);
    font-weight: 700;
    color: var(--rh-fg);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-pick__a {
    font-size: var(--rh-t-xs);
    color: var(--rh-fg-muted);
}

/* ── Uploaded documents ─────────────────────────────────────────────────── */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-doc {
    display: flex;
    align-items: flex-start;
    gap: var(--rh-s-3);
    background: var(--rh-surface-sunk);
    border: 1px solid var(--rh-border);
    border-radius: var(--rh-r-md);
    padding: 10px var(--rh-s-3);
    margin-bottom: var(--rh-s-2);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-doc > i {
    flex: none;
    margin-top: 2px;
    font-size: 17px;
    color: var(--rh-fg-subtle);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-doc__body { flex: 1 1 0; min-width: 0; }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-doc__name {
    font-size: var(--rh-t-xs);
    font-weight: 600;
    color: var(--rh-fg);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-doc__meta {
    margin: 2px 0 3px;
    font-size: var(--rh-t-2xs);
    color: var(--rh-fg-subtle);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-doc__prev {
    font-size: var(--rh-t-2xs);
    color: var(--rh-fg-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ── The KB table reuses .store-table, so retint rather than rename ────────
   `.premium-locked` and the setup guide both reach into this panel by class
   name; the shared table also appears on panels that are not converted yet, so
   these rules stay inside the scope. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .store-table { font-size: var(--rh-t-xs); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .store-table th {
    background: var(--rh-surface-sunk);
    color: var(--rh-fg-muted);
    font-size: var(--rh-t-2xs);
    font-weight: 700;
    letter-spacing: 0.02em;
    border-bottom: 1px solid var(--rh-border);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .store-table td {
    color: var(--rh-fg);
    border-bottom: 1px solid var(--rh-border);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .store-table tr:hover td { background: var(--rh-surface-hover); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .store-table input[type="checkbox"] { accent-color: var(--rh-accent); width: 16px; height: 16px; cursor: pointer; }

/* ============================================================================
   6. INSTALLATION — the two-way gateway, the developer hand-off, the snippet
   ----------------------------------------------------------------------------
   This is the panel a self-installing Estonian merchant actually reads, so it is
   the one where a broken dark mode costs a conversion rather than a compliment.
   Panel tone is AMBER: in the six-hue vocabulary amber means effort, and this
   panel is the effort between paying and working.
   ============================================================================ */

#installation-panel { --rh-tone-soft: var(--rh-tone-amber-soft); --rh-tone-ink: var(--rh-tone-amber-ink); }

/* ── The choose-your-path cards ─────────────────────────────────────────────
   Hover was four inline onmouseover/onmouseout handlers writing borderColor and
   boxShadow by hand, twice per card. It is a :hover rule now, which also means
   the focus ring works for a keyboard user — the inline version had none. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-choice {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
    padding: 18px 20px;
    border: 1px solid var(--rh-border-strong);
    border-radius: var(--rh-r-xl);
    background: var(--rh-surface);
    box-shadow: var(--rh-sh-xs);
    text-align: left;
    cursor: pointer;
    font-family: inherit;
    transition: border-color var(--rh-dur) var(--rh-ease),
                box-shadow var(--rh-dur) var(--rh-ease);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-choice:hover {
    border-color: var(--rh-tone-ink, var(--rh-accent));
    box-shadow: var(--rh-sh-sm);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-choice:focus-visible { outline: none; box-shadow: var(--rh-ring); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-choice.is-on {
    border-color: var(--rh-tone-ink, var(--rh-accent));
    box-shadow: var(--rh-sh-sm);
    background: var(--rh-tone-soft, var(--rh-accent-soft));
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-choice__t {
    display: flex;
    align-items: center;
    gap: var(--rh-s-2);
    font-size: var(--rh-t-md);
    font-weight: 700;
    color: var(--rh-fg);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-choice__t > i { color: var(--rh-tone-ink, var(--rh-accent-ink)); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-choice__s {
    font-size: var(--rh-t-2xs);
    color: var(--rh-fg-muted);
    line-height: 1.45;
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-choices {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--rh-s-3);
    margin-bottom: var(--rh-s-6);
}
@media (max-width: 640px) { :is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-choices { grid-template-columns: 1fr; } }

/* ── A tinted notice box (the developer hand-off) ──────────────────────────── */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-info {
    margin-bottom: var(--rh-s-6);
    padding: var(--rh-s-5);
    background: var(--rh-tone-soft, var(--rh-accent-soft));
    border: 1px solid var(--rh-border);
    border-radius: var(--rh-r-xl);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-info__t {
    display: flex;
    align-items: center;
    gap: 7px;
    margin: 0 0 var(--rh-s-1);
    font-size: var(--rh-t-sm);
    font-weight: 700;
    color: var(--rh-fg);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-info__s {
    margin: 0 0 var(--rh-s-3);
    font-size: var(--rh-t-xs);
    color: var(--rh-fg-muted);
    line-height: var(--rh-lh-normal);
}
/* A tone box needs its own tone, or the blue hand-off reads as part of the amber panel. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) #install-send-it-section { --rh-tone-soft: var(--rh-tone-blue-soft); --rh-tone-ink: var(--rh-tone-blue-ink); }

/* ── The snippet ────────────────────────────────────────────────────────────
   Deliberately dark in BOTH themes: a code block is dark by convention, the
   merchant is about to paste it into an editor that is also dark, and a snippet
   that restyles itself between themes reads as a different snippet. Measured
   9.6:1, so it is not a contrast concession. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-code {
    margin: 0;
    padding: var(--rh-s-4);
    background: var(--rh-n-900);
    color: #a3e635;
    border-radius: var(--rh-r-md);
    font-family: var(--rh-font-mono);
    font-size: var(--rh-t-2xs);
    line-height: 1.55;
    overflow-x: auto;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* ============================================================================
   7. SETTINGS — account configuration, and the one card that destroys things
   ============================================================================
   Panel 9 of 21. Tone is BLUE, the "system" hue, repeating the Leads panel
   deliberately: the six-hue rule assigns by meaning and a settings screen is
   system configuration, not a seventh category.

   The exception inside it is the Delete Account card, which is not a tone at
   all — danger is a STATE and has its own token pair, so a red card here can
   never be mistaken for a sixth-hue category card. */

#settings-panel { --rh-tone-soft: var(--rh-tone-blue-soft); --rh-tone-ink: var(--rh-tone-blue-ink); }

/* A card whose only child is a header row should not carry the header's
   trailing gap — otherwise the Setup Guide card is 16px taller than it needs
   to be for no reason a reader can see. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-head:last-child { margin-bottom: 0; }

/* A status line sitting IN a row aligns with the row, not below it. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-row > .rh-status { margin: 0; }

/* ── An auto-fitting field grid ─────────────────────────────────────────────
   .rh-grid2 is a fixed two columns, which is right for a pair of fields and
   wrong for the seven of Business Details — at 220px minimum the row count
   follows the panel width instead of being asserted. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-fields {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: var(--rh-s-3);
}

/* The required marker. Its own class rather than a red literal, because the
   danger token is the one colour in this file that must swap with the theme
   and still read at the same weight. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-req { color: var(--rh-danger); font-weight: 700; }

/* A quiet aside inside a label — "required", a unit, a hint. Previously only
   defined inside .rh-sect__t, so a label reaching for it silently got nothing. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-quiet { font-weight: 400; color: var(--rh-fg-muted); }

/* An icon inside a notice or a well carries the section's tone, same as every
   other icon in this layer. Without this the info glyph inherits body colour
   and reads as punctuation rather than as a marker. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-well > i,
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-info__t > i { color: var(--rh-tone-ink, var(--rh-accent-ink)); }

/* ── The destructive card ───────────────────────────────────────────────────
   Border and heading only. The card body stays on the normal surface: a fully
   red panel reads as an error that has already happened, when in fact nothing
   is wrong — the owner simply has the option. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .test-panel.rh-danger {
    border-color: var(--rh-danger-border);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .test-panel.rh-danger h3 { color: var(--rh-danger); }
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .test-panel.rh-danger h3 > i {
    background: var(--rh-danger-soft);
    color: var(--rh-danger);
}

/* The pending-deletion notice is a WARNING, not the panel's blue: the request
   is in flight and withdrawable, which is neither "system information" nor
   "destroyed". Compact, because it replaces a form rather than heading a
   section. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) #del-req-pending {
    --rh-tone-soft: var(--rh-warn-soft);
    --rh-tone-ink:  var(--rh-warn);
    border-color: var(--rh-warn-border);
    padding: var(--rh-s-4);
    margin-bottom: 0;
}

/* A momentary success state on a button ("Saved!"). The old `#22c55e` was
   neither the brand green nor theme-aware; the green tone pair is both, and
   is already contrast-checked against its own fill. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-btn.is-ok {
    background: var(--rh-tone-green-soft);
    border-color: var(--rh-tone-green-ink);
    color: var(--rh-tone-green-ink);
}

/* ============================================================================
   8. APPEARANCE — the widget styler
   ============================================================================
   Panel 10 of 21, and the largest. Tone is TEAL, which already means "the
   conversation" on the Conversations panel: this screen configures the chat
   widget, so it is the same subject at a different altitude.

   These rules used to live in a <style> element inside #appearance-panel, half
   converted — every declaration carried a `var(--rh-…, #hexfallback)` pair, so
   the panel read as themed while 25 literals were still one CSS-variable
   failure away from being the actual colour. They are moved here whole, with
   the fallbacks dropped: this file always loads before the panel renders, and a
   fallback that is never exercised is just a second value to keep in sync.

   CLASS NAMES ARE UNCHANGED ON PURPOSE. `.cust-seg` and `.color-swatch` are
   queried from JS (the delegated segment handler, the swatch marker), and every
   id here is read by loadWidgetAppearance / saveWidgetAppearance by name.

   NOT IN THIS FILE, and must not be: the live preview's own CSS. #cust-stage
   hosts a SHADOW ROOT, and CUST_PV_CSS inside it mirrors widget.core.js value
   for value. The shopper preview must keep looking like the shopper's widget,
   not like the owner's dashboard. */

#appearance-panel { --rh-tone-soft: var(--rh-tone-teal-soft); --rh-tone-ink: var(--rh-tone-teal-ink); }

/* Simple vs Advanced. Simple keeps only what a shopper actually registers (logo,
   colour, name, greeting, language, support email) — the rest is decoration a
   non-technical owner should not have to wade through to launch. Hiding is
   display-only: save reads every control by id, so an advanced setting made in
   Advanced survives a save made in Simple. */
#appearance-panel[data-mode="simple"] [data-adv] { display: none !important; }
/* a 2-col pair with its partner hidden would otherwise leave a dead column */
#appearance-panel[data-mode="simple"] .ap-two { grid-template-columns: 1fr; }

/* The panel's own shell is the sunk surface, so the control cards read as
   raised objects sitting on it rather than as boxes drawn on the page. */
#appearance-panel .test-panel {
    background: var(--rh-surface-sunk);
    border: 1px solid var(--rh-border);
}

#appearance-panel .ap-mode-seg {
    display: inline-flex;
    gap: 2px;
    background: var(--rh-surface-sunk);
    border-radius: var(--rh-r-full);
    padding: 3px;
    flex: none;
}
#appearance-panel .ap-mode-seg button {
    border: 0;
    background: transparent;
    color: var(--rh-fg-muted);
    font-family: inherit;
    font-size: var(--rh-t-2xs);
    font-weight: 700;
    padding: 6px 14px;
    border-radius: var(--rh-r-full);
    cursor: pointer;
    transition: background var(--rh-dur) var(--rh-ease), color var(--rh-dur) var(--rh-ease);
}
#appearance-panel .ap-mode-seg button.on {
    background: var(--rh-surface);
    color: var(--rh-accent-ink);
    box-shadow: var(--rh-sh-xs);
}
#appearance-panel .ap-mode-seg button:focus-visible { outline: none; box-shadow: var(--rh-ring); }

#appearance-panel .ap-cards { display: flex; flex-direction: column; gap: var(--rh-s-5); }

#appearance-panel .ap-card {
    background: var(--rh-surface);
    border: 1px solid var(--rh-border);
    border-radius: var(--rh-r-xl);
    padding: var(--rh-s-4) var(--rh-s-5) var(--rh-s-5);
    box-shadow: var(--rh-sh-sm);
}
#appearance-panel .ap-card > h4 {
    font-size: var(--rh-t-sm);
    margin: 0 0 3px;
    letter-spacing: -0.015em;
    display: flex;
    align-items: center;
    gap: 9px;
    color: var(--rh-fg);
    font-weight: 800;
}
/* Same tinted chip as every other panel heading, so a card here belongs to the
   same family as a card there. */
#appearance-panel .ap-card > h4 i {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    flex: none;
    border-radius: var(--rh-r-sm);
    font-size: 12px;
    background: var(--rh-tone-soft);
    color: var(--rh-tone-ink);
}
#appearance-panel .ap-card > .ap-desc {
    font-size: var(--rh-t-2xs);
    color: var(--rh-fg-muted);
    margin: 0 0 15px;
    padding-bottom: 15px;
    border-bottom: 1px solid var(--rh-border);
}

#appearance-panel .ap-row { margin-bottom: 15px; }
#appearance-panel .ap-row:last-child { margin-bottom: 0; }
#appearance-panel .ap-lab {
    font-size: var(--rh-t-2xs);
    font-weight: 700;
    color: var(--rh-fg-muted);
    display: block;
    margin-bottom: 6px;
}
#appearance-panel .ap-lab .rv {
    float: right;
    color: var(--rh-accent-ink);
    font-weight: 800;
    font-variant-numeric: tabular-nums;
}
/* Was --rh-fg-subtle. These help lines sit on the raised card, which is the
   easier ground, but the token is pinned for the sunk one and the difference
   is not worth a second class — muted reads correctly on both. */
#appearance-panel .ap-hlp {
    font-size: var(--rh-t-2xs);
    color: var(--rh-fg-muted);
    font-weight: 500;
    display: block;
    margin-top: 5px;
    line-height: var(--rh-lh-normal);
}
/* The contrast advice under "Text on your brand colour" was two style.color
   writes from JS. Warning and failure are STATES. */
#appearance-panel .ap-hlp.is-warn { color: var(--rh-warn); font-weight: 600; }
#appearance-panel .ap-hlp.is-bad  { color: var(--rh-danger); font-weight: 600; }

#appearance-panel .ap-inp {
    font: inherit;
    font-size: var(--rh-t-xs);
    color: var(--rh-fg);
    background: var(--rh-surface-sunk);
    border: 1px solid var(--rh-border-strong);
    border-radius: var(--rh-r-lg);
    padding: 10px 12px;
    width: 100%;
    box-sizing: border-box;
    outline: none;
    transition: border-color var(--rh-dur) var(--rh-ease), box-shadow var(--rh-dur) var(--rh-ease);
}
#appearance-panel .ap-inp::placeholder { color: var(--rh-fg-subtle); }
#appearance-panel .ap-inp:focus { border-color: var(--rh-accent); box-shadow: var(--rh-ring); }
#appearance-panel textarea.ap-inp { resize: vertical; min-height: 52px; font-family: inherit; }
#appearance-panel select.ap-inp { cursor: pointer; }

#appearance-panel .ap-two {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--rh-s-3);
    margin-bottom: 15px;
}
#appearance-panel .ap-two .ap-row { margin-bottom: 0; }
@media (max-width: 900px) { #appearance-panel .ap-two { grid-template-columns: 1fr; } }

#appearance-panel .ap-rng {
    width: 100%;
    -webkit-appearance: none;
    appearance: none;
    height: 6px;
    border-radius: var(--rh-r-full);
    background: var(--rh-border-strong);
    outline: none;
    cursor: pointer;
}
/* The knob stays white in both themes: it is a physical control on a coloured
   track, and n-0 is the one neutral this file never swaps. */
#appearance-panel .ap-rng::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 18px; height: 18px;
    border-radius: 50%;
    background: var(--rh-accent);
    cursor: pointer;
    border: 2px solid var(--rh-n-0);
    box-shadow: var(--rh-sh-xs);
}
#appearance-panel .ap-rng::-moz-range-thumb {
    width: 18px; height: 18px;
    border-radius: 50%;
    background: var(--rh-accent);
    cursor: pointer;
    border: 2px solid var(--rh-n-0);
}
#appearance-panel .ap-rng:focus-visible { box-shadow: var(--rh-ring); }

/* ── switch rows ─────────────────────────────────────────────────────────── */
#appearance-panel .ap-switch {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--rh-s-3);
    padding: 13px 0;
    border-top: 1px solid var(--rh-border);
}
#appearance-panel .ap-switch .lab { font-size: var(--rh-t-xs); font-weight: 600; color: var(--rh-fg); }
#appearance-panel .ap-switch .lab small {
    display: block;
    font-size: var(--rh-t-2xs);
    color: var(--rh-fg-muted);
    font-weight: 500;
    margin-top: 2px;
    line-height: 1.4;
}
#appearance-panel .ap-toggle { position: relative; flex: none; margin: 0; }
#appearance-panel .ap-toggle input { position: absolute; opacity: 0; pointer-events: none; }
#appearance-panel .ap-toggle .track {
    width: 40px; height: 23px;
    border-radius: var(--rh-r-full);
    background: var(--rh-border-strong);
    position: relative;
    transition: background var(--rh-dur) var(--rh-ease);
    cursor: pointer;
    display: block;
}
#appearance-panel .ap-toggle .track::after {
    content: "";
    position: absolute;
    top: 2px; left: 2px;
    width: 19px; height: 19px;
    border-radius: 50%;
    background: var(--rh-n-0);
    transition: transform var(--rh-dur) var(--rh-ease);
    box-shadow: var(--rh-sh-xs);
}
#appearance-panel .ap-toggle input:checked + .track { background: var(--rh-accent); }
#appearance-panel .ap-toggle input:checked + .track::after { transform: translateX(17px); }
#appearance-panel .ap-toggle input:focus-visible + .track { box-shadow: var(--rh-ring); }

#appearance-panel .ap-gated {
    font-size: 10px;
    font-weight: 800;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    border-radius: var(--rh-r-xs);
    padding: 2px 6px;
    color: var(--rh-tone-violet-ink);
    background: var(--rh-tone-violet-soft);
}

/* ── segmented + glow palette (JS depends on these names and on .on) ─────── */
#appearance-panel .cust-seg,
#appearance-panel .pv-theme-seg {
    display: inline-flex;
    flex-wrap: wrap;
    gap: 2px;
    background: var(--rh-surface-sunk);
    border-radius: var(--rh-r-full);
    padding: 3px;
}
#appearance-panel .cust-seg button,
#appearance-panel .pv-theme-seg button {
    border: 0;
    background: transparent;
    color: var(--rh-fg-muted);
    font-family: inherit;
    font-size: var(--rh-t-2xs);
    font-weight: 600;
    padding: 7px 13px;
    border-radius: var(--rh-r-full);
    cursor: pointer;
    transition: background var(--rh-dur) var(--rh-ease), color var(--rh-dur) var(--rh-ease);
}
#appearance-panel .cust-seg button.on,
#appearance-panel .pv-theme-seg button.on { background: var(--rh-accent); color: var(--rh-accent-fg); }
#appearance-panel .cust-seg button:focus-visible,
#appearance-panel .pv-theme-seg button:focus-visible { outline: none; box-shadow: var(--rh-ring); }
/* Preview-only theme switch: smaller than a real control, so it does not read as a store setting. */
#appearance-panel .pv-theme-seg button { font-size: 11.5px; padding: 4px 10px; }

#appearance-panel .cust-glowpal { display: flex; gap: 7px; flex-wrap: wrap; }
#appearance-panel .cust-glowpal button {
    width: 26px; height: 26px;
    border-radius: var(--rh-r-md);
    border: 2px solid transparent;
    cursor: pointer;
    padding: 0;
}
#appearance-panel .cust-glowpal button.on { border-color: var(--rh-fg); }
#appearance-panel .cust-glowpal button:focus-visible { outline: none; box-shadow: var(--rh-ring); }

/* ── the brand-colour picker ─────────────────────────────────────────────── */
/* The swatches ARE data — they are the palette the owner chooses from, so their
   hexes stay literal in the markup for the same reason the language <option>s
   stay in their own language. Only the chrome around them is tokenised. */
#appearance-panel .ap-swatches { display: flex; gap: var(--rh-s-2); flex-wrap: wrap; margin-bottom: 10px; }
#appearance-panel .color-swatch.selected {
    /* was `border-color:white; box-shadow:0 0 0 2px #374151` in the global block —
       in dark mode that outer ring all but vanished against the card. */
    border-color: var(--rh-surface);
    box-shadow: 0 0 0 2px var(--rh-fg);
}
#appearance-panel .ap-colorrow { display: flex; gap: var(--rh-s-2); align-items: center; }
#appearance-panel .ap-colorrow .ap-inp { flex: 1 1 0; min-width: 0; font-family: var(--rh-font-mono); text-transform: uppercase; }
#appearance-panel .ap-native {
    width: 40px; height: 40px;
    border: none;
    border-radius: var(--rh-r-lg);
    cursor: pointer;
    padding: 2px;
    flex: none;
    background: var(--rh-surface-sunk);
}
#appearance-panel .ap-eyedrop {
    width: 40px; height: 40px;
    border-radius: var(--rh-r-lg);
    border: 1px solid var(--rh-border-strong);
    background: var(--rh-surface-sunk);
    color: var(--rh-fg-muted);
    cursor: pointer;
    display: grid;
    place-items: center;
    flex: none;
}
#appearance-panel .ap-eyedrop:hover { background: var(--rh-surface-hover); color: var(--rh-fg); }
#appearance-panel .ap-eyedrop:focus-visible { outline: none; box-shadow: var(--rh-ring); }

/* ── logo ────────────────────────────────────────────────────────────────── */
#appearance-panel .ap-logo-row { display: flex; align-items: center; gap: var(--rh-s-3); }
#appearance-panel .ap-thumb {
    width: 52px; height: 52px;
    border-radius: var(--rh-r-xl);
    border: 1.5px dashed var(--rh-border-strong);
    background: var(--rh-surface-sunk);
    display: grid;
    place-items: center;
    color: var(--rh-fg-subtle);
    flex: none;
    overflow: hidden;
}
#appearance-panel .ap-linkbtn {
    margin-top: 6px;
    background: none;
    border: none;
    padding: 0;
    color: var(--rh-danger);
    font-family: inherit;
    font-size: 11.5px;
    font-weight: 700;
    cursor: pointer;
    text-decoration: underline;
}

/* ── launcher shape picker ───────────────────────────────────────────────── */
/* setLauncherShape used to write borderColor + background + color inline on all
   three buttons, which is three literals per click and none of them theme-aware
   — the same trap the Installation gateway had. It toggles .is-on now. */
#appearance-panel .ap-shape {
    flex: 1;
    padding: 10px;
    border-radius: var(--rh-r-md);
    border: 2px solid var(--rh-border);
    background: var(--rh-surface);
    font-family: inherit;
    font-size: var(--rh-t-2xs);
    font-weight: 600;
    color: var(--rh-fg-muted);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    transition: border-color var(--rh-dur) var(--rh-ease), background var(--rh-dur) var(--rh-ease);
}
#appearance-panel .ap-shape:hover { border-color: var(--rh-border-strong); }
#appearance-panel .ap-shape.is-on {
    border-color: var(--rh-accent);
    background: var(--rh-accent-soft);
    color: var(--rh-accent-ink);
}
#appearance-panel .ap-shape:focus-visible { outline: none; box-shadow: var(--rh-ring); }
#appearance-panel .ap-shape__c,
#appearance-panel .ap-shape__p,
#appearance-panel .ap-shape__r { display: inline-block; background: var(--rh-fg-subtle); }
#appearance-panel .ap-shape__c { width: 24px; height: 24px; border-radius: 50%; }
#appearance-panel .ap-shape__p { width: 48px; height: 22px; border-radius: 30px; }
#appearance-panel .ap-shape__r { width: 48px; height: 22px; border-radius: var(--rh-r-sm); }
#appearance-panel .ap-shape.is-on .ap-shape__c,
#appearance-panel .ap-shape.is-on .ap-shape__p,
#appearance-panel .ap-shape.is-on .ap-shape__r { background: var(--rh-accent); }

/* ── layout: controls left, preview pinned right ─────────────────────────── */
#appearance-panel .ap-split {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 360px;
    gap: var(--rh-s-5);
    align-items: start;
}
@media (max-width: 1100px) { #appearance-panel .ap-split { grid-template-columns: minmax(0, 1fr); } }
#appearance-panel .ap-scroll {
    max-height: calc(100vh - 300px);
    overflow-y: auto;
    padding-right: var(--rh-s-3);
}
#appearance-panel .ap-pvhead {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: var(--rh-s-2);
    flex-wrap: wrap;
}
#appearance-panel .ap-pvlab {
    font-size: var(--rh-t-2xs);
    font-weight: 600;
    color: var(--rh-fg-muted);
    display: flex;
    align-items: center;
    gap: var(--rh-s-2);
    margin: 0;
}
#appearance-panel .ap-pvlive { font-weight: 500; color: var(--rh-tone-green-ink); font-size: 11px; }

/* THE PREVIEW STAGE STAYS LIGHT IN BOTH THEMES, and that is the rule for this
   panel. It stands in for the merchant's own storefront page, which has nothing
   to do with whether the OWNER is running their dashboard dark — recolouring it
   would make them style their widget against a page no shopper will ever see.
   The widget itself is inside a shadow root on this element, so dashboard CSS
   cannot reach it at all; this rule only paints the ground behind it.
   (The docs used to name #widget-preview here. That id does not exist in this
   file — the host is #cust-stage — so dark.css's :not(#widget-preview) guards
   have never matched anything. Shadow DOM is what has actually been protecting
   the preview.) */
#appearance-panel #cust-stage {
    height: clamp(380px, calc(100vh - 300px), 580px);
    border-radius: var(--rh-r-xl);
    overflow: hidden;
    border: 1px solid var(--rh-border);
    background: #eef1ee;
}

/* ── a compact warning notice ────────────────────────────────────────────── */
/* The sibling of .rh-info, at the other size. .rh-info is a section-sized notice
   with a heading and a control (the developer hand-off, the pending deletion);
   this is the one-sentence caution that sits directly above the field it is
   about, where that padding would push the field off the card. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-warn {
    background: var(--rh-warn-soft);
    border: 1px solid var(--rh-warn-border);
    border-radius: var(--rh-r-md);
    padding: var(--rh-s-2) var(--rh-s-3);
    margin: 0 0 var(--rh-s-2);
    font-size: var(--rh-t-2xs);
    color: var(--rh-warn);
    line-height: var(--rh-lh-normal);
}
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-warn strong { font-weight: 700; }

/* ============================================================================
   9. SUBSCRIPTION — the plan, the usage bar, and the page they pay on
   ============================================================================
   Panel 11 of 21 and the last one in the OWNER view. Tone is GREEN: this is the
   "what you have" screen, and the hero card was already brand green, so nothing
   jars. Repeats are deliberate — a seventh hue would be the rainbow again. */

#subscription-panel { --rh-tone-soft: var(--rh-tone-green-soft); --rh-tone-ink: var(--rh-tone-green-ink); }

/* ── The plan hero ───────────────────────────────────────────────────────────
   Brand gradient in both themes, like the widget's own header: it is the one
   place the owner should see their brand rather than the dashboard's chrome.
   Text is --rh-accent-fg, so it stays legible whichever way the theme goes. */
#subscription-panel .sub-hero {
    background: linear-gradient(135deg, var(--rh-g-600), var(--rh-g-800));
    border-radius: var(--rh-r-xl);
    padding: var(--rh-s-6);
    color: var(--rh-accent-fg);
    margin-bottom: var(--rh-s-5);
    position: relative;
    overflow: hidden;
}
#subscription-panel .sub-hero__orb {
    position: absolute;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.06);
    pointer-events: none;
}
#subscription-panel .sub-hero__orb--a { top: -20px; right: -20px; width: 100px; height: 100px; }
#subscription-panel .sub-hero__orb--b { bottom: -30px; right: 30px; width: 140px; height: 140px; background: rgba(255, 255, 255, 0.04); }
#subscription-panel .sub-hero__lab {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 1px;
    opacity: 0.75;
    margin-bottom: 6px;
}
#subscription-panel .sub-hero__name { font-size: 2rem; font-weight: 800; letter-spacing: -1px; margin-bottom: 4px; }
#subscription-panel .sub-hero__price { font-size: var(--rh-t-sm); opacity: 0.85; }

/* ── Usage meter ─────────────────────────────────────────────────────────────
   The fill colour was three literals written from JS on every render. It is a
   THRESHOLD — a state — so it is a class, and the two warning steps reuse the
   warn/danger tokens rather than inventing an amber and a red. */
#subscription-panel .sub-bar {
    background: var(--rh-border-strong);
    border-radius: var(--rh-r-full);
    height: 10px;
    overflow: hidden;
    margin-bottom: var(--rh-s-2);
}
#subscription-panel .sub-bar__fill {
    height: 100%;
    border-radius: var(--rh-r-full);
    background: var(--rh-accent);
    width: 0;
    transition: width 0.6s var(--rh-ease), background var(--rh-dur) var(--rh-ease);
}
#subscription-panel .sub-bar__fill.is-warn { background: var(--rh-warn); }
#subscription-panel .sub-bar__fill.is-bad  { background: var(--rh-danger); }

#subscription-panel .sub-usage-row {
    display: flex;
    justify-content: space-between;
    font-size: var(--rh-t-xs);
    margin-bottom: 6px;
    color: var(--rh-fg);
}
#subscription-panel .sub-usage-row b { font-weight: 700; }

/* ── Billing facts ───────────────────────────────────────────────────────── */
#subscription-panel .sub-facts {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--rh-s-3);
    font-size: var(--rh-t-xs);
}
@media (max-width: 640px) { #subscription-panel .sub-facts { grid-template-columns: 1fr; } }
#subscription-panel .sub-fact {
    padding: var(--rh-s-3);
    background: var(--rh-surface-sunk);
    border: 1px solid var(--rh-border);
    border-radius: var(--rh-r-md);
}
#subscription-panel .sub-fact__k {
    color: var(--rh-fg-muted);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.03em;
    margin-bottom: 4px;
}
#subscription-panel .sub-fact__v { font-weight: 600; color: var(--rh-fg); }
#subscription-panel .sub-fact__v.is-ok  { color: var(--rh-tone-green-ink); }
#subscription-panel .sub-fact__v.is-bad { color: var(--rh-danger); }

/* ── Renewal banner ──────────────────────────────────────────────────────────
   Two states, and JS used to write four literals for each of them. Renewing is
   reassurance (ok); ending is a warning, NOT a danger — nothing has gone wrong
   and the owner chose it. */
#subscription-panel .sub-renew {
    padding: 14px 16px;
    border-radius: var(--rh-r-lg);
    margin-bottom: 14px;
    border: 1px solid var(--rh-border);
    background: var(--rh-surface-sunk);
}
#subscription-panel .sub-renew__h { font-size: var(--rh-t-md); font-weight: 800; color: var(--rh-fg); }
#subscription-panel .sub-renew__s { font-size: var(--rh-t-2xs); margin-top: 3px; color: var(--rh-fg-muted); }
#subscription-panel .sub-renew.is-ok   { background: var(--rh-tone-green-soft); border-color: var(--rh-tone-green-ink); }
#subscription-panel .sub-renew.is-ok   .sub-renew__h { color: var(--rh-tone-green-ink); }
#subscription-panel .sub-renew.is-warn { background: var(--rh-warn-soft); border-color: var(--rh-warn-border); }
#subscription-panel .sub-renew.is-warn .sub-renew__h { color: var(--rh-warn); }
#subscription-panel .sub-renew.is-warn .sub-renew__s { color: var(--rh-warn); }

/* ── Plan cards ──────────────────────────────────────────────────────────────
   Six inline onmouseover/onmouseout handlers, one pair per card — and the
   Starter pair set the SAME colour on both, so it had been a no-op since the
   day it was written. A :hover rule does it, and gives keyboard users a focus
   ring the inline version could never provide. */
#subscription-panel .sub-plans { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
@media (max-width: 720px) { #subscription-panel .sub-plans { grid-template-columns: 1fr; } }
#subscription-panel .sub-plan {
    border: 1px solid var(--rh-border);
    border-radius: var(--rh-r-lg);
    padding: 14px;
    text-align: center;
    cursor: pointer;
    background: var(--rh-surface);
    transition: border-color var(--rh-dur) var(--rh-ease), box-shadow var(--rh-dur) var(--rh-ease);
}
#subscription-panel .sub-plan:hover { border-color: var(--rh-accent); box-shadow: var(--rh-sh-sm); }
#subscription-panel .sub-plan:focus-visible { outline: none; box-shadow: var(--rh-ring); }
/* The store's CURRENT plan. Two states on one control — hover means "you could
   pick this", is-on means "this is what you have" — so the current card keeps
   its accent border on hover instead of pretending to be a target. */
#subscription-panel .sub-plan.is-on { border: 2px solid var(--rh-accent); padding: 13px; }
#subscription-panel .sub-plan.is-on .sub-plan__n { color: var(--rh-accent-ink); }
#subscription-panel .sub-plan__n { font-size: 11px; font-weight: 700; color: var(--rh-fg-muted); letter-spacing: 1px; }
#subscription-panel .sub-plan__p { font-size: 1.3rem; font-weight: 800; margin: 6px 0; color: var(--rh-fg); }
#subscription-panel .sub-plan__p small { font-size: var(--rh-t-2xs); font-weight: 400; }
#subscription-panel .sub-plan__b { font-size: 10px; color: var(--rh-fg-subtle); margin-bottom: 2px; }
#subscription-panel .sub-plan__m { font-size: 11px; color: var(--rh-fg-muted); }
#subscription-panel .sub-plan__x { font-size: 10px; color: var(--rh-tone-violet-ink); font-weight: 600; margin-top: 3px; }

#subscription-panel .sub-cta { margin-top: 14px; display: flex; gap: 10px; }
#subscription-panel .sub-cta .rh-btn { flex: 1 1 auto; text-decoration: none; }
#subscription-panel .sub-cta .rh-btn--danger { flex: 0 0 auto; }
@media (max-width: 640px) { #subscription-panel .sub-cta { flex-direction: column; } }

#subscription-panel .sub-terms { color: var(--rh-accent-ink); text-decoration: none; margin-left: 4px; font-weight: 600; }
#subscription-panel .sub-terms:hover { text-decoration: underline; }

/* ============================================================================
   10. SETUP GUIDE — the drawer that opens by itself on a new signup
   ============================================================================
   Not a panel: it is a fixed-position drawer that lives OUTSIDE data-view="owner",
   so none of section 3's component rules reach it and every rule here is
   id/class-scoped on its own. It matters more than its size suggests — it is the
   second thing a new merchant sees, after login.

   Moved here from a 16k <style> element inside index.html, 96 hex literals to 0.
   Class names are unchanged: the whole drawer is rendered from JS (sgRender,
   sgNav, sgFlash, the tour) and every one of these is selected or toggled by
   name.

   TWO NUMBERS ARE LOAD-BEARING AND MUST STAY EQUAL: #sg-drawer's 340px width and
   the calc(100% - 340px) below. A literal, not a var — var-in-calc failed here
   once. And the drawer RESERVES space rather than overlapping, because covering
   the sync buttons is what the first version did.

   The max-height on an open task is a HARD CLIP (overflow:hidden, and the scroll
   container is .sg-body outside it). At 640px the delivery form lost its Save
   button entirely and the task became impossible to finish. Keep it comfortably
   above the tallest task. */

#sg-root { position: fixed; inset: 0; z-index: 99998; pointer-events: none; font-family: inherit; }
#sg-root * { box-sizing: border-box; }

/* ── floating launcher pill (docked state) ──────────────────────────────── */
#sg-launcher {
    position: fixed; right: 22px; bottom: 22px;
    pointer-events: auto; display: none;
    align-items: center; gap: 11px;
    background: var(--rh-accent); color: var(--rh-accent-fg);
    border: none; cursor: pointer;
    padding: 11px 16px 11px 12px;
    border-radius: var(--rh-r-full);
    box-shadow: var(--rh-sh-md);
    font-family: inherit; font-size: 13.5px; font-weight: 700;
    transition: transform .18s ease, box-shadow .18s ease;
}
#sg-launcher:hover { transform: translateY(-2px); box-shadow: var(--rh-sh-md); }
#sg-launcher:focus-visible { outline: none; box-shadow: var(--rh-ring); }
#sg-launcher .sg-ring { position: relative; width: 34px; height: 34px; flex: 0 0 34px; }
#sg-launcher .sg-ring svg { transform: rotate(-90deg); }
#sg-launcher .sg-ring-num {
    position: absolute; inset: 0;
    display: flex; align-items: center; justify-content: center;
    font-size: 10.5px; font-weight: 800; color: var(--rh-accent-fg);
}
#sg-launcher .sg-l-txt { display: flex; flex-direction: column; line-height: 1.15; text-align: left; }
#sg-launcher .sg-l-txt small { font-weight: 600; opacity: .85; font-size: 10.5px; }
#sg-launcher.sg-pulse { animation: sgPulse 2.4s ease-in-out infinite; }
@keyframes sgPulse {
    0%, 100% { box-shadow: var(--rh-sh-md); }
    50%      { box-shadow: var(--rh-sh-md), 0 0 0 6px var(--rh-accent-soft); }
}

/* ── the drawer ─────────────────────────────────────────────────────────── */
#sg-drawer {
    position: fixed; top: 0; right: 0; height: 100%;
    width: 340px; max-width: 100vw; pointer-events: auto;
    background: var(--rh-surface);
    box-shadow: -14px 0 44px rgba(13, 16, 14, .22);
    display: flex; flex-direction: column;
    transform: translateX(105%);
    transition: transform .34s cubic-bezier(.22, 1, .36, 1);
}
#sg-drawer.sg-in { transform: translateX(0); }
.dashboard { width: 100%; transition: width .34s cubic-bezier(.22, 1, .36, 1); }
@media (min-width: 1080px) { body.sg-docked .dashboard { width: calc(100% - 340px); } }

/* The header is the brand gradient in both themes, like the Subscription hero:
   it is the one place the owner should see their product, not their chrome. */
.sg-head {
    padding: 20px 22px 16px;
    background: linear-gradient(135deg, var(--rh-g-600), var(--rh-g-800));
    color: var(--rh-accent-fg);
    position: relative; flex-shrink: 0;
}
.sg-head h2 { margin: 0; font-size: 19px; font-weight: 800; letter-spacing: -.2px; }
.sg-head p { margin: 4px 0 0; font-size: 12.5px; color: rgba(255, 255, 255, .82); line-height: 1.5; }
.sg-min {
    position: absolute; top: 14px; right: 14px;
    width: 30px; height: 30px;
    border: none; border-radius: var(--rh-r-md);
    background: rgba(255, 255, 255, .15); color: var(--rh-accent-fg);
    cursor: pointer; font-size: 15px;
    display: flex; align-items: center; justify-content: center;
    transition: background .15s;
}
.sg-min:hover { background: rgba(255, 255, 255, .28); }
.sg-min:focus-visible { outline: none; box-shadow: 0 0 0 2px rgba(255, 255, 255, .7); }

/* progress bar */
.sg-prog-wrap { margin-top: 15px; }
.sg-prog-top { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 6px; }
.sg-prog-top b { font-size: 12.5px; font-weight: 700; }
.sg-prog-top span { font-size: 11.5px; color: rgba(255, 255, 255, .78); font-weight: 600; }
.sg-prog-track { height: 7px; border-radius: var(--rh-r-full); background: rgba(255, 255, 255, .22); overflow: hidden; }
.sg-prog-fill {
    height: 100%; border-radius: var(--rh-r-full);
    background: linear-gradient(90deg, var(--rh-g-300), var(--rh-g-200));
    width: 0; transition: width .5s cubic-bezier(.22, 1, .36, 1);
}

.sg-body { flex: 1; overflow-y: auto; padding: 14px 16px 20px; background: var(--rh-surface-sunk); }

/* ── task card ──────────────────────────────────────────────────────────── */
.sg-task {
    background: var(--rh-surface);
    border: 1px solid var(--rh-border);
    border-radius: 13px; margin-bottom: 11px; overflow: hidden;
    transition: border-color .18s, box-shadow .18s;
}
.sg-task.sg-open { border-color: var(--rh-accent); box-shadow: var(--rh-sh-sm); }
.sg-task.sg-done { background: var(--rh-tone-green-soft); border-color: var(--rh-tone-green-ink); }
.sg-task-row { display: flex; align-items: center; gap: 12px; padding: 13px 14px; cursor: pointer; user-select: none; }
.sg-check {
    flex: 0 0 24px; width: 24px; height: 24px;
    border-radius: 50%; border: 2px solid var(--rh-border-strong);
    display: flex; align-items: center; justify-content: center;
    font-size: 12px; color: var(--rh-accent-fg); background: var(--rh-surface);
    transition: .2s;
}
.sg-task.sg-done .sg-check { background: var(--rh-accent); border-color: var(--rh-accent); transform: scale(1); }
.sg-check i { opacity: 0; transform: scale(.4); transition: .2s; }
.sg-task.sg-done .sg-check i { opacity: 1; transform: scale(1); }
.sg-task-ic { flex: 0 0 20px; text-align: center; color: var(--rh-accent-ink); font-size: 15px; }
.sg-task.sg-done .sg-task-ic { color: var(--rh-fg-muted); }
.sg-task-t { flex: 1; min-width: 0; }
.sg-task-t .sg-t-title { display: block; font-size: 13.5px; font-weight: 700; color: var(--rh-fg); line-height: 1.3; }
.sg-task.sg-done .sg-t-title { color: var(--rh-fg-muted); text-decoration: none; }
.sg-task-t .sg-t-sub { display: block; font-size: 11.5px; color: var(--rh-fg-muted); margin-top: 1px; line-height: 1.35; }
.sg-opt {
    font-size: 9.5px; font-weight: 800; letter-spacing: .4px;
    color: var(--rh-fg-muted); background: var(--rh-surface-sunk);
    padding: 2px 6px; border-radius: var(--rh-r-xs); text-transform: uppercase; margin-left: 6px;
}
.sg-chev { flex: 0 0 auto; color: var(--rh-fg-subtle); font-size: 12px; transition: transform .22s; }
.sg-task.sg-open .sg-chev { transform: rotate(180deg); }

/* expanded body — see the hard-clip note at the top of this section */
.sg-task-exp { max-height: 0; overflow: hidden; transition: max-height .3s ease; }
.sg-task.sg-open .sg-task-exp { max-height: 1600px; }
.sg-exp-inner { padding: 2px 16px 16px 50px; }
.sg-exp-inner p.sg-desc { font-size: 12.5px; color: var(--rh-fg-muted); line-height: 1.6; margin: 0 0 12px; }
.sg-exp-inner p.sg-desc b { color: var(--rh-fg); }

/* ── buttons ────────────────────────────────────────────────────────────── */
.sg-btn {
    display: inline-flex; align-items: center; gap: 7px;
    background: var(--rh-accent); color: var(--rh-accent-fg);
    border: none; border-radius: 9px;
    padding: 9px 15px; font-family: inherit; font-size: 12.5px; font-weight: 700;
    cursor: pointer; transition: transform .12s, background .15s; text-decoration: none;
}
.sg-btn:hover { background: var(--rh-accent-hover); transform: translateY(-1px); }
.sg-btn:focus-visible { outline: none; box-shadow: var(--rh-ring); }
.sg-btn.sg-btn-blue { background: var(--rh-tone-blue-ink); }
.sg-btn.sg-btn-blue:hover { background: var(--rh-tone-blue-ink); filter: brightness(0.92); }
.sg-btn.sg-btn-ghost { background: var(--rh-surface); color: var(--rh-fg); border: 1.5px solid var(--rh-border-strong); }
.sg-btn.sg-btn-ghost:hover { background: var(--rh-surface-hover); color: var(--rh-fg); }
.sg-choice-row { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }

/* ── handover mode ───────────────────────────────────────────────────────
   A store handed over from a prospect demo arrives with its products, answers
   and FAQ ALREADY built. The generic checklist then buries the one thing
   actually left — putting the widget on their site — which is the step with a
   0% completion rate. So it gets the whole screen. */
.sg-hero {
    background: linear-gradient(160deg, var(--rh-g-600), var(--rh-g-800));
    color: var(--rh-accent-fg);
    border-radius: var(--rh-r-xl); padding: 20px 18px; margin: 0 0 16px;
}
.sg-hero h4 { margin: 0 0 7px; font-size: 16.5px; font-weight: 800; letter-spacing: -.01em; }
.sg-hero p { margin: 0 0 14px; font-size: 12.5px; line-height: 1.6; color: rgba(255, 255, 255, .88); }
.sg-hero p b { color: var(--rh-accent-fg); }
.sg-hero .sg-choice-row { margin-bottom: 0; }
.sg-hero .sg-btn { background: var(--rh-n-0); color: var(--rh-g-800); }
.sg-hero .sg-btn:hover { background: var(--rh-g-50); }
.sg-hero .sg-btn.sg-btn-blue {
    background: rgba(255, 255, 255, .14); color: var(--rh-accent-fg);
    box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, .42);
}
.sg-hero .sg-btn.sg-btn-blue:hover { background: rgba(255, 255, 255, .24); filter: none; }
.sg-hero .sg-markdone { color: var(--rh-accent-fg); opacity: .92; padding-top: 12px; }

.sg-rest-head {
    display: flex; align-items: center; gap: 9px; margin: 4px 0 9px;
    font-size: 10.5px; font-weight: 800; letter-spacing: .08em;
    text-transform: uppercase; color: var(--rh-fg-muted);
}
.sg-rest-head::after { content: ""; flex: 1; height: 1px; background: var(--rh-border); }
.sg-markdone {
    background: none; border: none; color: var(--rh-accent-ink);
    font-family: inherit; font-size: 12px; font-weight: 700; cursor: pointer;
    padding: 8px 0 0; display: inline-flex; align-items: center; gap: 6px;
}
.sg-markdone:hover { text-decoration: underline; }
.sg-undo {
    background: none; border: none; color: var(--rh-fg-muted);
    font-family: inherit; font-size: 11.5px; font-weight: 600; cursor: pointer; padding: 8px 0 0;
}
.sg-undo:hover { color: var(--rh-fg); text-decoration: underline; }

/* ── inline forms ───────────────────────────────────────────────────────── */
.sg-q { margin-bottom: 11px; }
.sg-q label { display: block; font-size: 12px; font-weight: 700; color: var(--rh-fg); margin-bottom: 4px; }
.sg-q textarea, .sg-q input.sg-inp, .sg-q select.sg-inp {
    width: 100%; padding: 8px 11px;
    border-radius: var(--rh-r-md); border: 1px solid var(--rh-border-strong);
    font-size: 12.5px; font-family: inherit; resize: vertical;
    background: var(--rh-surface); color: var(--rh-fg);
}
.sg-q textarea:focus, .sg-q .sg-inp:focus { outline: none; border-color: var(--rh-accent); box-shadow: var(--rh-ring); }
.sg-q .sg-hint { font-size: 11px; color: var(--rh-fg-muted); margin-top: 3px; line-height: 1.4; }
.sg-checkrow {
    display: flex; align-items: flex-start; gap: 8px;
    font-size: 11.5px; color: var(--rh-fg-muted); margin: 4px 0 10px; line-height: 1.45;
}
/* Written from JS. The status COLOUR is a state — see window._rhStatus. */
.sg-status { font-size: 12px; font-weight: 700; margin-top: 9px; min-height: 16px; color: var(--rh-fg-muted); }
.sg-status.is-ok   { color: var(--rh-tone-green-ink); }
.sg-status.is-bad  { color: var(--rh-danger); }
.sg-status.is-busy { color: var(--rh-fg-muted); }
/* 'some saved, some not' — neither success nor failure. */
.sg-status.is-warn { color: var(--rh-warn); }

/* The progress ring's two strokes were painted in the MARKUP, which is why the
   launcher was the one part of the drawer a theme could not reach. */
#sg-launcher .sg-ring-bg { stroke: rgba(255, 255, 255, .28); }
#sg-launcher #sg-ring-fg { stroke: var(--rh-g-300); }

/* ── inline bits the task TEMPLATES build ──────────────────────────────────
   Six colour literals inside JS template strings — the one place a theme can
   never reach, and the easiest place to miss when converting a panel. */
.sg-ok    { color: var(--rh-tone-green-ink); font-weight: 700; }
.sg-warnt { color: var(--rh-warn); }
.sg-fine  { font-size: 11.5px; color: var(--rh-fg-muted); }
.sg-linkbtn {
    background: none; border: none; padding: 0;
    color: var(--rh-accent-ink); font-family: inherit;
    font-weight: 700; font-size: 11.5px; cursor: pointer;
}
.sg-well {
    background: var(--rh-surface-sunk);
    border-radius: 10px; padding: 11px 13px; font-size: 12px;
}
.sg-welllab {
    margin: 0 0 6px; font-size: 11px; font-weight: 800;
    letter-spacing: .6px; text-transform: uppercase; color: var(--rh-fg-muted);
}
.sg-wellq { margin: 0; font-size: 12.5px; color: var(--rh-fg); }

/* ── footer ─────────────────────────────────────────────────────────────── */
.sg-foot {
    flex-shrink: 0; border-top: 1px solid var(--rh-border);
    padding: 11px 18px; display: flex; align-items: center; justify-content: space-between;
    background: var(--rh-surface);
}
.sg-foot .sg-refresh, .sg-foot .sg-later {
    background: none; border: none; cursor: pointer;
    font-family: inherit; font-weight: 600;
    display: inline-flex; align-items: center; gap: 6px;
}
.sg-foot .sg-refresh { color: var(--rh-fg-muted); font-size: 11.5px; }
.sg-foot .sg-later { color: var(--rh-fg-muted); font-size: 12px; font-weight: 700; }
.sg-foot .sg-refresh:hover, .sg-foot .sg-later:hover { color: var(--rh-accent-ink); }

/* ── celebration ────────────────────────────────────────────────────────── */
.sg-done-screen { display: none; flex-direction: column; align-items: center; text-align: center; padding: 40px 26px; }
.sg-done-screen .sg-burst { font-size: 52px; animation: sgPop .5s cubic-bezier(.18, 1.4, .4, 1) both; }
@keyframes sgPop { 0% { transform: scale(.2); opacity: 0; } 60% { transform: scale(1.15); } 100% { transform: scale(1); opacity: 1; } }
.sg-done-screen h2 { font-size: 22px; color: var(--rh-fg); margin: 14px 0 6px; font-weight: 800; }
.sg-done-screen p { font-size: 13px; color: var(--rh-fg-muted); line-height: 1.6; max-width: 280px; margin: 0 0 22px; }
#sg-root.sg-complete .sg-body { display: none; }
#sg-root.sg-complete .sg-done-screen { display: flex; }
#sg-root.sg-complete .sg-foot { display: none; }

/* panel spotlight flash when a task navigates */
.sg-flash { animation: sgFlash 2.1s ease-out 1; border-radius: var(--rh-r-xl); }
@keyframes sgFlash {
    0%   { box-shadow: 0 0 0 0 rgba(39, 98, 58, 0); }
    12%  { box-shadow: 0 0 0 4px rgba(39, 98, 58, .55); }
    100% { box-shadow: 0 0 0 4px rgba(39, 98, 58, 0); }
}

/* ── Onboarding gate ─────────────────────────────────────────────────────
   The drawer used to appear 3-5s after the dashboard became interactive, so a
   new owner started clicking and the guide landed on top of what they had
   begun. On a FRESH SIGNUP only, this scrim holds the floor until they
   acknowledge it. NOT the old blocking wizard: one click dismisses it for good.
   The scrim stays a fixed dark wash in both themes — it is a shadow, not a
   surface, and a "light" scrim is not a thing. */
#sg-gate {
    position: fixed; inset: 0; z-index: 99997; background: rgba(13, 16, 14, .42);
    backdrop-filter: blur(1.5px); -webkit-backdrop-filter: blur(1.5px);
    display: none; align-items: flex-end; justify-content: center; padding-bottom: 38px;
    animation: sgGateIn .25s ease-out 1; cursor: pointer;
}
body.sg-gated #sg-gate { display: flex; }
@keyframes sgGateIn { from { opacity: 0; } to { opacity: 1; } }
#sg-gate span {
    background: var(--rh-surface); color: var(--rh-fg);
    font-size: 12.5px; font-weight: 600;
    padding: 9px 16px; border-radius: var(--rh-r-full); box-shadow: var(--rh-sh-md);
}

/* ── Sidebar tour ───────────────────────────────────────────────────────── */
#sg-tour-pop {
    position: fixed; z-index: 100001; width: 270px;
    background: var(--rh-surface); border-radius: 13px;
    box-shadow: var(--rh-sh-md); padding: 14px 15px 12px; display: none;
    border: 1px solid var(--rh-border);
}
#sg-tour-pop.on { display: block; }
#sg-tour-pop:after {
    content: ''; position: absolute; left: -7px; top: 20px; width: 0; height: 0;
    border-top: 7px solid transparent; border-bottom: 7px solid transparent;
    border-right: 7px solid var(--rh-surface);
}
.sg-tour-step {
    font-size: 10.5px; font-weight: 800; letter-spacing: .7px;
    text-transform: uppercase; color: var(--rh-fg-muted); margin: 0 0 4px;
}
.sg-tour-name {
    font-size: 14px; font-weight: 800; color: var(--rh-fg); margin: 0 0 5px;
    display: flex; align-items: center; gap: 7px;
}
.sg-tour-name i { color: var(--rh-accent-ink); font-size: 13px; }
.sg-tour-desc { font-size: 12.5px; color: var(--rh-fg-muted); line-height: 1.5; margin: 0 0 12px; }
.sg-tour-row { display: flex; gap: 8px; align-items: center; }
.sg-tour-row .sg-btn { padding: 7px 14px; font-size: 12.5px; }
.sg-tour-skip {
    background: none; border: none; color: var(--rh-fg-muted);
    font-family: inherit; font-size: 12px; cursor: pointer; padding: 6px 4px;
}
.sg-tour-skip:hover { color: var(--rh-fg); text-decoration: underline; }
#sg-tour-scrim { position: fixed; inset: 0; z-index: 99999; background: rgba(13, 16, 14, .5); display: none; }
body.sg-touring #sg-tour-scrim { display: block; }
body.sg-touring #main-sidebar { position: relative; z-index: 100000; }
#sidebar-nav a.sg-tour-on {
    background: var(--rh-accent-soft) !important;
    border-radius: 9px;
    box-shadow: 0 0 0 2px rgba(39, 98, 58, .55);
}

/* ── Unsaved-changes confirm (Appearance) ───────────────────────────────
   Save = green, Don't save = red. Robin's explicit call, so both stay FILLED.
   The discard fill is --rh-danger-solid, which does NOT lighten in dark mode:
   --rh-danger does (it is tuned for text on a dark ground), and white on that
   lighter red measures about 2.6:1. A filled destructive button needs a fill
   dark enough for white text in BOTH themes. */
#sg-confirm {
    position: fixed; inset: 0; z-index: 100002; background: rgba(13, 16, 14, .45);
    display: none; align-items: center; justify-content: center; padding: 20px;
}
#sg-confirm.on { display: flex; }
.sg-confirm-box {
    background: var(--rh-surface); border: 1px solid var(--rh-border);
    border-radius: 15px; max-width: 390px; width: 100%;
    padding: 24px 24px 20px; box-shadow: var(--rh-sh-md);
}
.sg-confirm-box h3 { margin: 0 0 8px; font-size: 17px; color: var(--rh-fg); font-weight: 800; }
.sg-confirm-box p { margin: 0 0 20px; font-size: 13.5px; color: var(--rh-fg-muted); line-height: 1.55; }
.sg-confirm-row { display: flex; gap: 10px; justify-content: flex-end; flex-wrap: wrap; }
.sg-cf-btn {
    border: none; border-radius: 9px; padding: 10px 18px;
    font-family: inherit; font-size: 13.5px; font-weight: 700; cursor: pointer;
}
.sg-cf-btn:focus-visible { outline: none; box-shadow: var(--rh-ring); }
.sg-cf-save { background: var(--rh-accent); color: var(--rh-accent-fg); }
.sg-cf-save:hover { background: var(--rh-accent-hover); }
.sg-cf-discard { background: var(--rh-danger-solid); color: #ffffff; }
.sg-cf-discard:hover { background: var(--rh-danger-solid-hover); }
.sg-cf-cancel { background: var(--rh-surface-sunk); color: var(--rh-fg-muted); }
.sg-cf-cancel:hover { background: var(--rh-surface-hover); color: var(--rh-fg); }

/* Narrow screens: don't squeeze the dashboard — the drawer becomes a bottom
   sheet, and nav tasks auto-minimise it so the panel is usable. */
@media (max-width: 1079px) {
    #sg-drawer {
        top: auto; left: 0; right: 0; bottom: 0;
        width: 100%; height: min(62vh, 540px);
        border-radius: 20px 20px 0 0;
        transform: translateY(108%);
        box-shadow: 0 -14px 44px rgba(13, 16, 14, .24);
    }
    #sg-drawer.sg-in { transform: translateY(0); }
    .sg-body { padding-bottom: 14px; }
}
@media (max-width: 480px) { #sg-launcher { right: 14px; bottom: 14px; } }
@media (prefers-reduced-motion: reduce) {
    #sg-drawer, .sg-prog-fill, .sg-task-exp, #sg-launcher, .sg-btn, .sg-chev, .dashboard { transition: none !important; }
    #sg-launcher.sg-pulse, .sg-done-screen .sg-burst, .sg-flash { animation: none !important; }
}

/* ============================================================================
   11. SEPARATION — cards need an edge, and a long card needs a rule
   ============================================================================
   Robin, reading the real panels: some of them are "just a white page with text
   with little separation, hard to read". He is right and it was measurable, not
   a matter of taste: a white card on the old n-50 ground separated at 1.067:1,
   so the only thing holding a card apart from the page was a 1px n-200 border
   (1.26:1) and a shadow tuned almost to nothing.

   Three levers, all at token or component level so every panel gains at once:
   the ground went one step deeper (style.css), the shadows went up (section 1),
   and the card EDGE is one step stronger here. Plus the thing he actually asked
   for by name — a LINE under a card's heading, so a long card stops being one
   undivided block of text. */

:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .test-panel,
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-item,
#appearance-panel .ap-card,
.sg-task {
    border-color: var(--rh-border-strong);
}

/* A heading rule. `.ap-card > .ap-desc` already had one and the Appearance cards
   are the ones that read best, which is the whole argument for generalising it.

   Scoped to a heading that is a card's FIRST child, so it divides a card header
   from the card's body and never draws a stray line mid-content. The margin
   collapse matters: the rule sits below the heading's own bottom margin, so the
   gap above the line stays tight and the gap below it does the separating. */
/* The line goes under the whole header block, so where a heading has its own
   description the rule sits under the DESCRIPTION. This one needs no `:has` and
   is the common case. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .test-panel > h3:first-child + .rh-sub,
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .test-panel > h2:first-child + .rh-sub {
    padding-bottom: var(--rh-s-3);
    border-bottom: 1px solid var(--rh-border);
    margin-bottom: var(--rh-s-3);
}

/* A bare heading with no description takes the line itself. Written as a
   NEGATIVE `:has` on purpose: a browser without `:has` support drops this whole
   rule and those cards simply keep the old undivided look. The first cut had it
   the other way round — line on every heading, then removed again by `:has` —
   which in the same browser would have drawn TWO lines. Fail toward the old
   behaviour, never toward a broken one. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .test-panel > h3:first-child:not(:has(+ .rh-sub)),
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .test-panel > h2:first-child:not(:has(+ .rh-sub)) {
    padding-bottom: var(--rh-s-3);
    border-bottom: 1px solid var(--rh-border);
    margin-bottom: var(--rh-s-3);
}

/* A standalone divider, for a card that groups two things and says so. */
:is(#products-panel, #owner-analytics-panel, #admin-rollup-panel, .rh-panel) .rh-hr {
    border: 0;
    border-top: 1px solid var(--rh-border);
    margin: var(--rh-s-4) 0;
}
