/* ==========================================================================
   Planogram theme, round 2 — everything here is behind the ?ui=v2 flag.

   EVERY RULE IN THIS FILE STARTS WITH [data-ui="v2"]. The `--ui-*` variables exist only
   there, so with the flag off they are undefined, every `var(--ui-*, <old colour>)` in the
   app falls back to the colour it always had, and the page is what it was.
   tests/test_ui_flag.py holds the file to that, rule by rule.

   Loaded last in <head>, after style.css, so that a rule here wins a tie.
   Spec: the round-2 brief; method and proof: docs/design/bevis-merge.md.
   ========================================================================== */


/* ---------- 2.2 Tokens ----------------------------------------------------
   Planogram's own palette. The first sixteen are the brief's; the six after them are
   the ones the brief's palette needs to meet 4.5:1 for TEXT: --ui-success (#16a34a) is
   3.3:1 on white and --ui-warning 3.2:1, fine for a fill or a border and not for words,
   and white on a blue that is light enough to read as a link on a dark surface is not
   readable either. So text gets its own shade of each, and a fill keeps the brief's. */
[data-ui="v2"] {
    --ui-bg: #f8fafc;
    --ui-surface: #ffffff;
    --ui-border: #e2e8f0;
    --ui-text: #0f172a;
    --ui-text-secondary: #475569;
    --ui-muted: #94a3b8;            /* icons, rules, placeholders — never body text (2.6:1) */
    --ui-primary: #2563eb;
    --ui-primary-hover: #1d4ed8;
    --ui-primary-soft: #dbeafe;
    --ui-danger: #dc2626;
    --ui-success: #16a34a;
    --ui-warning: #d97706;
    --ui-table-head-bg: #f1f5f9;
    --ui-table-head-text: #334155;
    --ui-focus: #2563eb;

    --ui-on-primary: #ffffff;       /* text on a primary or danger fill */
    --ui-link: #1d4ed8;             /* primary as text: 6.7:1 on white, 5.6:1 on --ui-primary-soft */
    --ui-danger-text: #dc2626;
    --ui-success-text: #15803d;
    --ui-warning-text: #b45309;
    --ui-logo: #ffc107;             /* Tecko yellow: the logo mark and nothing else */
}

/* Dark: the selector the app has always used for dark ([data-theme="dark"], set by
   Settings → setTheme()), combined with the flag. */
[data-ui="v2"][data-theme="dark"] {
    --ui-bg: #0f172a;
    --ui-surface: #1e293b;
    --ui-border: #334155;
    --ui-text: #f1f5f9;
    --ui-text-secondary: #cbd5e1;
    --ui-muted: #64748b;
    --ui-primary: #2563eb;          /* a fill under white text: 5.2:1, same as light */
    --ui-primary-hover: #1d4ed8;
    --ui-primary-soft: #1e3a5f;
    --ui-danger: #dc2626;
    --ui-success: #16a34a;
    --ui-warning: #d97706;
    --ui-table-head-bg: #273449;
    --ui-table-head-text: #e2e8f0;
    --ui-focus: #60a5fa;

    --ui-on-primary: #ffffff;
    --ui-link: #93c5fd;
    --ui-danger-text: #fca5a5;
    --ui-success-text: #86efac;
    --ui-warning-text: #fcd34d;
    --ui-logo: #ffc107;
}

/* The tokens the app already reads — 2,854 `var(--…)` uses, mostly --gray-*, --tecko-*
   and --primary* — re-pointed at the palette, so those uses follow the theme without
   being touched one by one. Same element as the definitions above (<html>), so a bridge
   variable such as --primary: var(--tecko-accent) resolves against these. */
[data-ui="v2"] {
    --app-bg: var(--ui-bg);
    --tecko-bg-primary: var(--ui-surface);
    --tecko-bg-secondary: var(--ui-bg);
    --tecko-bg-tertiary: var(--ui-table-head-bg);
    --tecko-card-bg: var(--ui-surface);
    --tecko-text-primary: var(--ui-text);
    --tecko-text-secondary: var(--ui-text-secondary);
    --tecko-text-muted: var(--ui-text-secondary);
    --tecko-text-inverse: var(--ui-on-primary);
    --tecko-dark-grey: var(--ui-text);
    --tecko-grey: var(--ui-text-secondary);
    --tecko-light-grey: var(--ui-border);
    --tecko-border-light: var(--ui-border);
    --tecko-border-dark: var(--ui-muted);

    --theme-accent: var(--ui-primary);
    --theme-accent-dark: var(--ui-primary-hover);
    --theme-accent-light: var(--ui-primary-soft);
    --theme-accent-text: var(--ui-on-primary);
    --tecko-accent: var(--ui-primary);
    --tecko-accent-dark: var(--ui-primary-hover);
    --tecko-accent-light: var(--ui-primary-soft);
    --tecko-accent-text: var(--ui-on-primary);
    --tecko-yellow: var(--ui-primary);
    --tecko-yellow-light: var(--ui-primary-soft);
    --tecko-yellow-dark: var(--ui-primary-hover);
    --tecko-success: var(--ui-success);
    --tecko-warning: var(--ui-warning);
    --tecko-error: var(--ui-danger);
    --tecko-shadow-accent: 0 0 0 3px color-mix(in srgb, var(--ui-focus) 35%, transparent);

    --tecko-table-header-bg: var(--ui-table-head-bg);
    --tecko-table-header-text: var(--ui-table-head-text);
    --tecko-table-border: var(--ui-border);
    --tecko-table-stripe: var(--ui-bg);
    --tecko-table-hover: var(--ui-primary-soft);

    --primary: var(--ui-primary);
    --primary-dark: var(--ui-primary-hover);
    --primary-light: var(--ui-primary-soft);
    --primary-600: var(--ui-primary);
    --primary-700: var(--ui-primary-hover);
    --primary-100: var(--ui-primary-soft);
    --primary-50: var(--ui-primary-soft);
    --success: var(--ui-success);
    --warning: var(--ui-warning);
    --danger: var(--ui-danger);
    --accent: var(--ui-primary);
    --text-muted: var(--ui-text-secondary);
    --surface-2: var(--ui-bg);
    --gray-50: var(--ui-bg);
    --gray-100: var(--ui-bg);
    --gray-200: var(--ui-border);
    --gray-300: var(--ui-border);
    --gray-400: var(--ui-text-secondary);   /* used as text in 60+ places; --ui-muted is 2.6:1 */
    --gray-500: var(--ui-text-secondary);
    --gray-600: var(--ui-text-secondary);
    --gray-700: var(--ui-text);
    --gray-800: var(--ui-text);
    --gray-900: var(--ui-text);
}

[data-ui="v2"] body:not([data-ui-surface="dark"]) {
    background: var(--ui-bg);
    color: var(--ui-text);
}

[data-ui="v2"] :focus-visible {
    outline: 2px solid var(--ui-focus);
    outline-offset: 2px;
}

/* Tecko yellow is the logo's, and only the logo's. */
[data-ui="v2"] .nav-brand a::before {
    content: "";
    display: inline-block;
    width: 0.7em;
    height: 0.7em;
    margin-right: 0.45em;
    border-radius: 3px;
    background: var(--ui-logo);
    vertical-align: 0.02em;
}

/* ---------- 2.1 The design system's Poppins and 1.5 (style.css set Inter and 1.55 until v1 went) ---------- */
[data-ui="v2"] {
    --tecko-font-primary: 'Poppins', sans-serif;
    --tecko-leading-normal: 1.5;
}

/* ---------- 2.3 Typography --------------------------------------------------------
   Poppins everywhere, one scale, line height 1.4–1.5. Every px/rem font-size in the app
   reads var(--ui-fs-N) (scripts/tokenize_type.py; the `, <old size>` fallbacks went with
   v1 in 7.1), so these six are the whole scale. Below 10 px (labels drawn on the planogram at its zoom)
   and above 28 px (display figures) were left as they are. */
[data-ui="v2"] {
    --ui-font: 'Poppins', sans-serif;
    --ui-fs-12: 12px;
    --ui-fs-13: 13px;
    --ui-fs-14: 14px;
    --ui-fs-16: 16px;
    --ui-fs-20: 20px;
    --ui-fs-24: 24px;

    --tecko-font-primary: var(--ui-font);
    --tecko-text-xs: 12px;
    --tecko-text-sm: 13px;
    --tecko-text-base: 14px;
    --tecko-text-lg: 16px;
    --tecko-text-xl: 20px;
    --tecko-text-2xl: 24px;
    --tecko-text-3xl: 24px;
    --tecko-leading-tight: 1.4;
    --tecko-leading-snug: 1.4;
    --tecko-leading-normal: 1.5;
    /* the density setting keeps its spacing; its type joins the scale */
    --d-font-xs: 12px;
    --d-font-sm: 13px;
    --d-font-base: 14px;
    --d-font-lg: 16px;
}

[data-ui="v2"] body {
    font-size: 14px;
    line-height: 1.5;
}

/* Everything in Poppins — the system stacks, 'Segoe UI' tables, Barlow Condensed in the
   export header — except icons (Phosphor is a font) and code. */
[data-ui="v2"] *:not(.ph):not(.ph-bold):not(.ph-fill):not(code):not(kbd):not(pre):not(samp) {
    font-family: var(--ui-font);
}

[data-ui="v2"] h1 { font-size: 24px; line-height: 1.4; }
[data-ui="v2"] h2 { font-size: 20px; line-height: 1.4; }
[data-ui="v2"] h3 { font-size: 16px; line-height: 1.4; }
[data-ui="v2"] h4,
[data-ui="v2"] h5,
[data-ui="v2"] h6 { font-size: 14px; line-height: 1.4; }
[data-ui="v2"] small { font-size: 12px; }
[data-ui="v2"] input,
[data-ui="v2"] select,
[data-ui="v2"] textarea { font-size: 14px; line-height: 1.4; }

/* Numbers in tables: right-aligned, every digit the same width so a column reads down.
   ExcelTable marks its own (td.cell-number / cell-currency); every other table gets
   .ui-num from ui-flag.js, decided per column. */
[data-ui="v2"] td,
[data-ui="v2"] th { line-height: 1.4; font-variant-numeric: tabular-nums; }
[data-ui="v2"] td.cell-number,
[data-ui="v2"] td.cell-currency,
[data-ui="v2"] td.ui-num,
[data-ui="v2"] th.ui-num { text-align: right; }

/* ---------- 2.4 Buttons: three types -------------------------------------------------
   Primary (--ui-primary, white text), secondary (surface, border, text), destructive
   (--ui-danger). The audit counted seven button colours: blue, green (+ Gondola, Save
   Version, Release), purple (Hide demo, storage, the floor-plan journey), navy (export,
   3D) and dark blue (store portal, confirmation) — here they are three.
   `[data-ui="v2"] body` in front of each selector lifts it above the pages' own <style>
   blocks, which come after this file and would otherwise win a tie.
   The outline is an inset shadow, not a border: a border would make every secondary
   button 2 px larger than it is with the flag off. */
[data-ui="v2"] body .btn,
[data-ui="v2"] body .btn-secondary,
[data-ui="v2"] body .btn-outline,
[data-ui="v2"] body .tecko-btn,
[data-ui="v2"] body .tecko-btn-secondary,
[data-ui="v2"] body .pk-btn,
[data-ui="v2"] body .cancel-btn,
[data-ui="v2"] body .demo-switch button {
    background: var(--ui-surface);
    color: var(--ui-text);
    border-color: transparent;
    box-shadow: inset 0 0 0 1px var(--ui-border);
    border-radius: 6px;
    font-weight: 500;
}
[data-ui="v2"] body .btn:hover,
[data-ui="v2"] body .btn-secondary:hover,
[data-ui="v2"] body .btn-outline:hover,
[data-ui="v2"] body .tecko-btn:hover,
[data-ui="v2"] body .pk-btn:hover,
[data-ui="v2"] body .cancel-btn:hover,
[data-ui="v2"] body .demo-switch button:hover {
    background: var(--ui-bg);
    color: var(--ui-text);
    box-shadow: inset 0 0 0 1px var(--ui-muted);
}

[data-ui="v2"] body .btn-primary,
[data-ui="v2"] body .btn-success,
[data-ui="v2"] body .btn.primary,
[data-ui="v2"] body .btn-save,
[data-ui="v2"] body .save-btn,
[data-ui="v2"] body .confirm-btn,
[data-ui="v2"] body .submit-btn,
[data-ui="v2"] body .tecko-btn-primary,
[data-ui="v2"] body .jp-btn.primary,
[data-ui="v2"] body .pk-btn.primary,
[data-ui="v2"] body .demo-switch button.active {
    background: var(--ui-primary);
    color: var(--ui-on-primary);
    border-color: transparent;
    box-shadow: none;
}
[data-ui="v2"] body .btn-primary:hover,
[data-ui="v2"] body .btn-success:hover,
[data-ui="v2"] body .btn.primary:hover,
[data-ui="v2"] body .btn-save:hover,
[data-ui="v2"] body .save-btn:hover,
[data-ui="v2"] body .confirm-btn:hover,
[data-ui="v2"] body .submit-btn:hover,
[data-ui="v2"] body .tecko-btn-primary:hover,
[data-ui="v2"] body .jp-btn.primary:hover,
[data-ui="v2"] body .pk-btn.primary:hover,
[data-ui="v2"] body .demo-switch button.active:hover {
    background: var(--ui-primary-hover);
    color: var(--ui-on-primary);
    box-shadow: none;
}

[data-ui="v2"] body .btn-danger,
[data-ui="v2"] body .tecko-btn-danger,
[data-ui="v2"] body button.btn-danger {
    background: var(--ui-danger);
    color: var(--ui-on-primary);
    border-color: transparent;
    box-shadow: none;
}
[data-ui="v2"] body .btn-danger:hover,
[data-ui="v2"] body .tecko-btn-danger:hover,
[data-ui="v2"] body button.btn-danger:hover {
    background: color-mix(in srgb, var(--ui-danger) 85%, black);
    color: var(--ui-on-primary);
}

[data-ui="v2"] body .btn:disabled,
[data-ui="v2"] body .btn[disabled] {
    opacity: 0.5;
    cursor: not-allowed;
}

/* Row buttons ("Open" in Projects, "Open"/"Del" in Chains & Stores, Edit/Del in the
   product tables) are text buttons: a table full of filled buttons is a table of
   buttons. Every Del still asks first — tests/test_ui_buttons.py holds each handler to
   its confirm(). */
[data-ui="v2"] body .excel-table tbody td .btn,
[data-ui="v2"] body .excel-table tbody td.cell-actions button {
    background: transparent;
    color: var(--ui-link);
    border-color: transparent;
    box-shadow: none;
    padding: 2px 6px;
    font-weight: 500;
}
[data-ui="v2"] body .excel-table tbody td .btn:hover,
[data-ui="v2"] body .excel-table tbody td.cell-actions button:hover {
    background: var(--ui-primary-soft);
    color: var(--ui-link);
    text-decoration: underline;
}
[data-ui="v2"] body .excel-table tbody td .btn-danger,
[data-ui="v2"] body .excel-table tbody td.cell-actions button.btn-danger {
    background: transparent;
    color: var(--ui-danger-text);
}
[data-ui="v2"] body .excel-table tbody td .btn-danger:hover,
[data-ui="v2"] body .excel-table tbody td.cell-actions button.btn-danger:hover {
    background: color-mix(in srgb, var(--ui-danger) 12%, transparent);
    color: var(--ui-danger-text);
}

/* ---------- 2.5 Panels follow the theme; the 3D views stay dark ------------------------
   Gondola Info, Load analysis (the same .gondola-info-panel chrome) and the version diff
   were a fixed dark box over a light editor, whatever the theme. Under the flag they are
   surface, border and text like every other panel, so they turn dark only in dark mode. */
[data-ui="v2"] body .gondola-info-panel {
    background: var(--ui-surface);
    color: var(--ui-text);
    border: 1px solid var(--ui-border);
    box-shadow: 0 12px 24px -8px rgba(15, 23, 42, .18);
}
[data-ui="v2"] body .gondola-info-panel .gip-top,
[data-ui="v2"] body .gondola-info-panel .gip-footer {
    background: var(--ui-surface);
    color: var(--ui-text);
    border-color: var(--ui-border);
}
[data-ui="v2"] body .gondola-info-panel .gip-header {
    color: var(--ui-text);
    border-bottom-color: var(--ui-border);
}
[data-ui="v2"] body .gondola-info-panel .gip-header .gip-close { color: var(--ui-text-secondary); }
[data-ui="v2"] body .gondola-info-panel .gip-header .gip-close:hover { color: var(--ui-text); background: var(--ui-bg); }
[data-ui="v2"] body .gondola-info-panel .gip-header .gip-copy {
    color: var(--ui-text);
    background: var(--ui-surface);
    border-color: var(--ui-border);
}
[data-ui="v2"] body .gondola-info-panel .gip-header .gip-copy:hover { background: var(--ui-bg); border-color: var(--ui-muted); color: var(--ui-text); }
[data-ui="v2"] body .gondola-info-panel .gip-tab { color: var(--ui-text-secondary); }
[data-ui="v2"] body .gondola-info-panel .gip-tab:hover { color: var(--ui-text); background: var(--ui-bg); }
[data-ui="v2"] body .gondola-info-panel .gip-tab.active,
[data-ui="v2"] body .gondola-info-panel .gip-tab-single { color: var(--ui-link); background: var(--ui-primary-soft); }
[data-ui="v2"] body .gondola-info-panel .gip-stats,
[data-ui="v2"] body .gondola-info-panel .la-nolimit { color: var(--ui-text-secondary); }
[data-ui="v2"] body .gondola-info-panel thead th {
    background: var(--ui-table-head-bg);
    color: var(--ui-table-head-text);
    border-bottom-color: var(--ui-border);
    border-right-color: var(--ui-border);
}
[data-ui="v2"] body .gondola-info-panel thead th .gip-col-resize:hover,
[data-ui="v2"] body .gondola-info-panel thead th .gip-col-resize.active { background: var(--ui-primary); }
[data-ui="v2"] body .gondola-info-panel tbody td { border-bottom-color: var(--ui-border); border-right-color: var(--ui-border); }
[data-ui="v2"] body .gondola-info-panel tbody tr:nth-child(even) { background: var(--ui-bg); }
[data-ui="v2"] body .gondola-info-panel tbody tr:hover { background: var(--ui-primary-soft); }
[data-ui="v2"] body .gondola-info-panel tbody tr.gip-selected { background: var(--ui-primary-soft); }
[data-ui="v2"] body .gondola-info-panel tbody tr.gip-selected td { color: var(--ui-text); }
[data-ui="v2"] body .gondola-info-panel tbody tr.gip-facing-group:not(.gip-facing-first) { background: var(--ui-bg); }
[data-ui="v2"] body .gondola-info-panel tbody tr.gip-facing-group:not(.gip-facing-first) td,
[data-ui="v2"] body .gondola-info-panel .col-loc,
[data-ui="v2"] body .gondola-info-panel .col-sku,
[data-ui="v2"] body .gondola-info-panel .col-facings,
[data-ui="v2"] body .gondola-info-panel .col-stack { color: var(--ui-text-secondary); }
[data-ui="v2"] body .gondola-info-panel .col-desc,
[data-ui="v2"] body .gondola-info-panel .col-qty,
[data-ui="v2"] body .gondola-info-panel .col-fixture { color: var(--ui-text); }
[data-ui="v2"] body .gondola-info-panel .col-shelf,
[data-ui="v2"] body .gondola-info-panel .gip-subtotal-row td,
[data-ui="v2"] body .gondola-info-panel .gip-fixture-separator td,
[data-ui="v2"] body .gondola-info-panel .gip-fac-link { color: var(--ui-link); }
[data-ui="v2"] body .gondola-info-panel .gip-subtotal-row td,
[data-ui="v2"] body .gondola-info-panel .gip-fixture-separator td { border-top-color: var(--ui-border); }
[data-ui="v2"] body .gondola-info-panel .gip-fac-link:hover { background: var(--ui-primary-soft); }
[data-ui="v2"] body .gondola-info-panel .la-ok { color: var(--ui-success-text); }
[data-ui="v2"] body .gondola-info-panel .la-over,
[data-ui="v2"] body .gondola-info-panel .la-missing { color: var(--ui-danger-text); }
[data-ui="v2"] body .load-info-panel .gip-stats .la-sf { color: var(--ui-text); }
[data-ui="v2"] body .load-info-panel .gip-stats input {
    background: var(--ui-surface);
    color: var(--ui-text);
    border-color: var(--ui-border);
}

/* AI Placement was already light; its indigo accents and #445 headings join the palette,
   and in dark mode the panel follows. */
[data-ui="v2"] body .ai-panel { background: var(--ui-surface); color: var(--ui-text); border-color: var(--ui-border); }
[data-ui="v2"] body .ai-section { border-bottom-color: var(--ui-border); }
[data-ui="v2"] body .ai-fold { border-top-color: var(--ui-border); }
[data-ui="v2"] body .ai-section > h4,
[data-ui="v2"] body .ai-fold > summary { color: var(--ui-text-secondary); }
[data-ui="v2"] body .ai-moved { color: var(--ui-link); background: var(--ui-primary-soft); }
[data-ui="v2"] body .ai-chip { color: var(--ui-link); background: var(--ui-primary-soft); border-color: transparent; }
[data-ui="v2"] body .ai-chip:hover { border-color: var(--ui-primary); }
[data-ui="v2"] body .ai-chip span { color: var(--ui-text-secondary); }
[data-ui="v2"] body .ai-grip:hover { background: var(--ui-primary-soft); }

/* The export configurator's header was navy (#1a3a6b) with pale-blue crumbs on a page
   with no theme at all. Under the flag: a surface bar like every other page's, the
   primary action a primary button. */
[data-ui="v2"] body .topbar:not(main .topbar) {
    background: var(--ui-surface);
    color: var(--ui-text);
    border-bottom: 1px solid var(--ui-border);
}
[data-ui="v2"] body .topbar-left .bc,
[data-ui="v2"] body .topbar-left .bc a { color: var(--ui-text-secondary); }
[data-ui="v2"] body .topbar-left .title { color: var(--ui-text); }
[data-ui="v2"] body .topbar .btn-primary { background: var(--ui-primary); color: var(--ui-on-primary); }
[data-ui="v2"] body .topbar .btn-primary:hover { background: var(--ui-primary-hover); }

/* The 3D viewer and the store in 3D stay dark: a lit model reads best on dark, and these
   are views, not forms. They take the theme's button types and Poppins all the same —
   the --ui-* below are a dark set scoped to the page's content, so the 2.4 rules draw
   dark secondary buttons here and blue primary ones. */
[data-ui="v2"] body[data-ui-surface="dark"] main {
    --ui-bg: #1a1d25;
    --ui-surface: #232833;
    --ui-border: #3a3f4b;
    --ui-text: #e5e7eb;
    --ui-text-secondary: #cbd5e1;
    --ui-muted: #6b7484;
    --ui-primary-soft: #1e3a5f;
    --ui-link: #93c5fd;
    --ui-table-head-bg: #273449;
    --ui-table-head-text: #e2e8f0;
}
[data-ui="v2"] body[data-ui-surface="dark"] .topbar .btn,
[data-ui="v2"] body[data-ui-surface="dark"] .editbar .btn {
    background: var(--ui-surface);
    color: var(--ui-text);
    border-color: transparent;
    box-shadow: inset 0 0 0 1px var(--ui-border);
}
[data-ui="v2"] body[data-ui-surface="dark"] .topbar .btn:hover,
[data-ui="v2"] body[data-ui-surface="dark"] .editbar .btn:hover { background: #2f3542; color: #fff; }
[data-ui="v2"] body[data-ui-surface="dark"] .topbar .btn.primary,
[data-ui="v2"] body[data-ui-surface="dark"] .topbar .btn.active {
    background: var(--ui-primary);
    color: var(--ui-on-primary);
    box-shadow: none;
}
[data-ui="v2"] body[data-ui-surface="dark"] .topbar .btn.primary:hover,
[data-ui="v2"] body[data-ui-surface="dark"] .topbar .btn.active:hover { background: var(--ui-primary-hover); }

/* ---------- 2.6 Tables: one style -------------------------------------------------------
   Projects and Products (ExcelTable, pg-grid), Chains & Stores (ExcelTable + its .at-*
   tables) and Analytics (its own .data-table.compact) were four implementations with four
   looks: saturated blue heads, white head text, heavy grey zebra. Under the flag: a quiet
   head (--ui-table-head-bg / --ui-table-head-text), 1 px --ui-border, zebra in --ui-bg,
   and no column wider than its content + 24 px (12 px each side) or 480 px. */
[data-ui="v2"] .excel-table-container {
    --excel-header-bg: var(--ui-table-head-bg);
    --excel-header-hover: var(--ui-border);
    --excel-header-sorted: var(--ui-border);
    --excel-header-border: var(--ui-border);
    --excel-row-hover: var(--ui-primary-soft);
    --excel-row-selected: var(--ui-primary-soft);
    --excel-group0-bg: var(--ui-table-head-bg);
    --excel-group0-hover: var(--ui-border);
    --excel-group0-border: var(--ui-border);
    --excel-group1-bg: var(--ui-bg);
    --excel-group1-text: var(--ui-link);
    --excel-group1-hover: var(--ui-primary-soft);
    --excel-group1-border: var(--ui-border);
    --excel-group1-count-bg: var(--ui-primary-soft);
    --excel-group1-count-text: var(--ui-link);
    --excel-group2-bg: var(--ui-surface);
    --excel-group2-text: var(--ui-link);
    --excel-group2-hover: var(--ui-primary-soft);
    --excel-group2-border: var(--ui-border);
    --excel-group2-count-bg: var(--ui-primary-soft);
    --excel-group2-count-text: var(--ui-link);
    --excel-indent1-border: var(--ui-border);
    --excel-indent2-border: var(--ui-border);
    --excel-subheader-bg: var(--ui-table-head-bg);
    --excel-subheader-hover: var(--ui-border);
    --excel-subheader-sorted: var(--ui-border);
    --excel-subheader-border: var(--ui-border);
    --excel-subheader-border-r: var(--ui-border);
    --excel-count-bg: var(--ui-table-head-bg);
    --excel-count-text: var(--ui-text-secondary);
    border: 1px solid var(--ui-border);
    box-shadow: none;
}
[data-ui="v2"] {
    --pgt-grid: var(--ui-border);
    --pgt-band: var(--ui-bg);
    --pgt-band-alt: var(--ui-surface);
    --pgt-text: var(--ui-text);
    --pgt-hover: var(--ui-primary-soft);
    --pgt-selected: var(--ui-primary-soft);
    --pgt-head-bg: var(--ui-table-head-bg);
    --pgt-head-bg-hover: var(--ui-border);
    --pgt-head-text: var(--ui-table-head-text);
    --pgt-chrome-bg: var(--ui-table-head-bg);
}

/* Heads */
[data-ui="v2"] body .excel-table th,
[data-ui="v2"] body table.pg-grid th,
[data-ui="v2"] body .data-table th,
[data-ui="v2"] body .data-table.compact th,
[data-ui="v2"] body .at-table th,
[data-ui="v2"] body .at-detail-table th,
[data-ui="v2"] body .at-notif-log-table th,
[data-ui="v2"] body .confirm-table th {
    background: var(--ui-table-head-bg);
    color: var(--ui-table-head-text);
    border: 0;
    border-bottom: 1px solid var(--ui-border);
    font-weight: 600;
}
[data-ui="v2"] body .excel-table th:hover,
[data-ui="v2"] body .excel-table th.sorted { background: var(--ui-border); color: var(--ui-text); }
[data-ui="v2"] body .excel-table thead tr + tr th { background: var(--ui-surface); }
[data-ui="v2"] body .excel-col-filter { background: var(--ui-surface); color: var(--ui-text); border-color: var(--ui-border); }

/* Cells: hairlines, zebra, width */
[data-ui="v2"] body .excel-table td,
[data-ui="v2"] body table.pg-grid td,
[data-ui="v2"] body .data-table td,
[data-ui="v2"] body .data-table.compact td,
[data-ui="v2"] body .at-table td,
[data-ui="v2"] body .at-detail-table td,
[data-ui="v2"] body .at-notif-log-table td,
[data-ui="v2"] body .confirm-table td {
    border: 0;
    border-bottom: 1px solid var(--ui-border);
    color: var(--ui-text);
    background: var(--ui-surface);
}
[data-ui="v2"] body .excel-table tbody tr.excel-data-row:nth-child(even) td,
[data-ui="v2"] body table.pg-grid tbody tr:nth-child(even) > td,
[data-ui="v2"] body .data-table tbody tr:nth-child(even) td,
[data-ui="v2"] body .data-table.compact tbody tr:nth-child(even) td,
[data-ui="v2"] body .at-table tbody tr:nth-child(even) td,
[data-ui="v2"] body .at-detail-table tbody tr:nth-child(even) td,
[data-ui="v2"] body .at-notif-log-table tbody tr:nth-child(even) td,
[data-ui="v2"] body .confirm-table tbody tr:nth-child(even) td { background: var(--ui-bg); }
[data-ui="v2"] body .excel-table tbody tr.excel-data-row:hover td,
[data-ui="v2"] body table.pg-grid tbody tr:hover > td,
[data-ui="v2"] body .data-table tbody tr:hover td,
[data-ui="v2"] body .at-table tbody tr:hover td { background: var(--ui-primary-soft); }

[data-ui="v2"] body .excel-table :is(th, td),
[data-ui="v2"] body table.pg-grid :is(th, td),
[data-ui="v2"] body .data-table :is(th, td),
[data-ui="v2"] body .at-table :is(th, td),
[data-ui="v2"] body .at-detail-table :is(th, td),
[data-ui="v2"] body .at-notif-log-table :is(th, td),
[data-ui="v2"] body .confirm-table :is(th, td) {
    padding-left: 12px;
    padding-right: 12px;
    max-width: 480px;
    overflow: hidden;
    text-overflow: ellipsis;
}
[data-ui="v2"] body .data-table.compact .col-shelf,
[data-ui="v2"] body .data-table.compact .subtotal-label { color: var(--ui-link); }
[data-ui="v2"] body .data-table.compact tbody tr.subtotal-row td {
    background: var(--ui-table-head-bg) !important;
    color: var(--ui-text-secondary);
    border-color: var(--ui-border);
}
/* Content + 24 px means the table is as wide as its columns, not stretched to the box:
   a stretched table hands the spare width to every column, and Image became 180 px. */
[data-ui="v2"] body .excel-table { min-width: 0; width: max-content; }
/* A filter <input> has a built-in width of ~20 characters, which became every column's
   minimum (Image was 250 px for a 36 px thumbnail). Zero width + 100 % minimum: it fills
   its column and no longer decides how wide the column is. */
[data-ui="v2"] body .excel-table .excel-col-filter { width: 0; min-width: 100%; font-size: 12px; }
/* 4b.8: Projects' table was cut off on the right. Its Category and Subcategory cells hold an
   <input> (editable in place), and an input is ~20 characters wide whatever it holds, so both
   columns were 305 px for 140 px of text and the table 1,491 px in an 862 px box. The inputs are
   their content's width now (2.6: no column wider than its content + 24 px). The table still
   scrolls sideways inside its box when it is wider (it is, at 1440 px); while there is more to
   the right, the box's right edge fades — a scrollbar is not always drawn (overlay scrollbars,
   headless screenshots), and a hard cut through a name read as a broken page. */
[data-ui="v2"] body .proj-cat-input { width: auto; field-sizing: content; min-width: 4ch; max-width: 456px; }
@property --proj-more { syntax: '<length>'; inherits: false; initial-value: 0px; }
@keyframes proj-more { from, 96% { --proj-more: 40px; } to { --proj-more: 0px; } }
[data-ui="v2"] body :is(#planograms-container, #floorplans-container) > .excel-table-container {
    animation: proj-more linear both;
    animation-timeline: scroll(self inline);
    mask-image: linear-gradient(to right, #000 calc(100% - var(--proj-more)), rgba(0, 0, 0, 0.2));
}

/* ---------- 2.8 A product without a photo is a neutral carton --------------------------
   It was its colour all over (amber by default) with a dashed white outline. Now an
   off-white carton with a hairline edge and its SKU on the front; the product's colour
   stays as a narrow band across the top — the inline background of .placed-product,
   showing through a transparent top border. The same carton in planogram-3d.js and
   store-3d.js. A carton is a physical thing, so it stays light in dark mode. */
[data-ui="v2"] body .placed-product-noimage {
    background-color: #f8fafc;
    background-clip: padding-box;
    border: 1px solid var(--ui-border);
    border-top: 3px solid transparent;
    border-radius: 1px;
    color: #334155;
}
[data-ui="v2"] body .placed-product-noimage + .placed-product-noimage { border-left: 1px solid var(--ui-border); }
[data-ui="v2"] body .placed-product-noimage .noimage-sku { color: #334155; font-weight: 600; }
[data-ui="v2"] body .placed-product-noimage .noimage-dims { color: #475569; }

/* ---------- Contrast (measured with scripts/contrast.py under the flag) ------------------
   Fixes for pairs below 4.5:1 that the theme itself made, or that one rule clears. What is
   left is listed in docs/design/bevis-merge.md. */
/* the view switch and Load More took --excel-header-bg as a fill under white text; the
   head is now pale, so they are a primary button */
[data-ui="v2"] body .excel-view-toggle button.active,
[data-ui="v2"] body .excel-load-more button { background: var(--ui-primary); color: var(--ui-on-primary); }
[data-ui="v2"] body .excel-load-more button:hover:not(:disabled) { background: var(--ui-primary-hover); }
/* type badges on Chains & Stores: teal 3.3:1 → dark teal */
[data-ui="v2"] body .cs-type-store-group { color: #115e59; }
[data-ui="v2"] body .cs-type-chain { color: #1e40af; }
/* the export configurator's own greys (#888 / #bbb as text) */
[data-ui="v2"] {
    --muted: var(--ui-text-secondary);
    --dim: var(--ui-text-secondary);
}
/* the 3D pages' body text is light; the navbar above them is not */
[data-ui="v2"] body[data-ui-surface="dark"] .navbar .nav-user { color: var(--ui-text); }
/* status badges: green on pale green 3.0:1 */
[data-ui="v2"] body .status-active,
[data-ui="v2"] body .excel-table td.cell-status .status-active { color: #15803d; }
[data-ui="v2"] body .cs-format-badge { color: #115e59; }
/* these badges keep a fixed pale fill in dark mode too, so their text stays dark */
[data-ui="v2"] body .cs-info-badge { color: #1e40af; }
/* the navbar's brand and active item were accent-on-accent-soft: unreadable in dark */
[data-ui="v2"] body .nav-brand a,
[data-ui="v2"] body .nav-links a.active { color: var(--ui-link); }
/* view switches (Planogram / Floor Plan …) as the 2.4 secondary/primary pair */
[data-ui="v2"] body .mode-btn { background: var(--ui-surface); color: var(--ui-text-secondary); }
[data-ui="v2"] body .mode-btn:hover { background: var(--ui-bg); color: var(--ui-text); }
[data-ui="v2"] body .mode-btn.active { background: var(--ui-primary); color: var(--ui-on-primary); }

/* ---------- 2b.1 Dark: the surfaces pages paint themselves --------------------------------
   Round 2 made the text light in dark and left the pages' own light surfaces alone — `white`,
   `#fafafa`, `#fbfcfe`, `#f7f8fa` written into each page's <style> — so light text stood on
   light panels (16.4 % of text below 4.5:1, the floor plan's sidebars, 3D Studio's list, the
   template cards). Here those surfaces take the tokens, and text that was a FILL colour used
   as text (--primary-600/700, #2563eb on a dark surface) becomes --ui-link.
   Dark only: every rule starts [data-ui="v2"][data-theme="dark"], so light v2 is as it was.
   Left light on purpose: the floor plan's drawing (a sheet, like the carton in 2.8), the
   export configurator and Excel preview (print pages, white in both themes). */

/* Floor plan / store editor: header, sidebars, tool buttons, canvas controls */
[data-ui="v2"][data-theme="dark"] .store-editor-container { background: var(--ui-bg); }
[data-ui="v2"][data-theme="dark"] .store-editor-container .editor-header,
[data-ui="v2"][data-theme="dark"] .store-editor-container .sidebar-left,
[data-ui="v2"][data-theme="dark"] .store-editor-container .sidebar-right,
[data-ui="v2"][data-theme="dark"] .store-editor-container .canvas-controls,
[data-ui="v2"][data-theme="dark"] .store-editor-container .ctrl-btn,
[data-ui="v2"][data-theme="dark"] .store-editor-container .layer-btn,
[data-ui="v2"][data-theme="dark"] .store-editor-container .stats-section,
[data-ui="v2"][data-theme="dark"] .store-editor-container .stats-section .stat,
[data-ui="v2"][data-theme="dark"] .store-editor-container .version-item {
    background: var(--ui-surface);
    color: var(--ui-text);
    border-color: var(--ui-border);
}
[data-ui="v2"][data-theme="dark"] .store-editor-container .tool-btn,
[data-ui="v2"][data-theme="dark"] .store-editor-container .element-item,
[data-ui="v2"][data-theme="dark"] .store-editor-container .planogram-item,
[data-ui="v2"][data-theme="dark"] .store-editor-container .group-item,
[data-ui="v2"][data-theme="dark"] .store-editor-container .tool-info,
[data-ui="v2"][data-theme="dark"] .store-editor-container .value-display {
    background: var(--ui-bg);
    color: var(--ui-text-secondary);
    border-color: var(--ui-border);
}
[data-ui="v2"][data-theme="dark"] .store-editor-container .tool-btn:hover,
[data-ui="v2"][data-theme="dark"] .store-editor-container .element-item:hover,
[data-ui="v2"][data-theme="dark"] .store-editor-container .planogram-item:hover,
[data-ui="v2"][data-theme="dark"] .store-editor-container .ctrl-btn:hover,
[data-ui="v2"][data-theme="dark"] .store-editor-container .section-toggle:hover,
[data-ui="v2"][data-theme="dark"] .store-editor-container .plano-cat-header:hover,
[data-ui="v2"][data-theme="dark"] .store-editor-container .plano-sub-header:hover {
    background: var(--ui-table-head-bg);
}
[data-ui="v2"][data-theme="dark"] .store-editor-container .tool-btn.active {
    background: var(--ui-primary-soft);
    border-color: var(--ui-primary);
    color: var(--ui-link);
}
[data-ui="v2"][data-theme="dark"] .store-editor-container .plano-cat-header,
[data-ui="v2"][data-theme="dark"] .store-editor-container .plano-sub-header { color: var(--ui-text-secondary); }
/* floating panels over the drawing (zone traffic, journeys, paths) */
[data-ui="v2"][data-theme="dark"] #zone-heatmap-legend,
[data-ui="v2"][data-theme="dark"] .store-editor-container .journey-panel,
[data-ui="v2"][data-theme="dark"] #traffic-panel { background: var(--ui-surface) !important; color: var(--ui-text); }

/* 3D Studio / Packshots: the library list, its tabs and the section heads */
[data-ui="v2"][data-theme="dark"] .pk-lib-head,
[data-ui="v2"][data-theme="dark"] .pk-filter-head { background: var(--ui-table-head-bg); color: var(--ui-table-head-text); }
[data-ui="v2"][data-theme="dark"] .pk-lib-tab { color: var(--ui-text); }
[data-ui="v2"][data-theme="dark"] .pk-lib-tab.active { color: var(--ui-on-primary); }
[data-ui="v2"][data-theme="dark"] .pk-lr:nth-child(even) { background: var(--ui-bg); }
[data-ui="v2"][data-theme="dark"] .pk-lr.sel,
[data-ui="v2"][data-theme="dark"] .pk-lr.viewing,
[data-ui="v2"][data-theme="dark"] .pk-lr.mp-drop { background: var(--ui-primary-soft); }
[data-ui="v2"][data-theme="dark"] .pk-lr-sku,
[data-ui="v2"][data-theme="dark"] .pk-mrow-name,
[data-ui="v2"][data-theme="dark"] .pk-posfact b { color: var(--ui-text); }
[data-ui="v2"][data-theme="dark"] .pk-lr-thumb { background: var(--ui-bg); }
[data-ui="v2"][data-theme="dark"] .pk-lr-mp,
[data-ui="v2"][data-theme="dark"] .pk-lib-mp-drop,
[data-ui="v2"][data-theme="dark"] .pk-mchip-new { background: var(--ui-primary-soft); color: var(--ui-link); border-color: var(--ui-border); }
[data-ui="v2"][data-theme="dark"] .pk-master-pane,
[data-ui="v2"][data-theme="dark"] .pk-lib-bar,
[data-ui="v2"][data-theme="dark"] #pk-prodpanel,
[data-ui="v2"][data-theme="dark"] #pk-pospanel,
[data-ui="v2"][data-theme="dark"] #pk-fixpanel { background: var(--ui-surface); }
[data-ui="v2"][data-theme="dark"] .pk-master-head { color: var(--ui-link); }
[data-ui="v2"][data-theme="dark"] .pk-lib-barrow { color: var(--ui-text-secondary); }
[data-ui="v2"][data-theme="dark"] .pk-sub,
[data-ui="v2"][data-theme="dark"] #pk-prodpanel .pk-sub,
[data-ui="v2"][data-theme="dark"] #pk-pack-controls .pk-sub,
[data-ui="v2"][data-theme="dark"] #pk-model-controls .pk-sub,
[data-ui="v2"][data-theme="dark"] #pk-pospanel .pk-sub,
[data-ui="v2"][data-theme="dark"] #pk-fixpanel .pk-sub { background: var(--ui-table-head-bg); color: var(--ui-table-head-text); }

/* Cards and forms that paint themselves white: template cards, product detail */
[data-ui="v2"][data-theme="dark"] .template-card,
[data-ui="v2"][data-theme="dark"] .product-detail-page .form-card,
[data-ui="v2"][data-theme="dark"] .product-detail-page .images-section,
[data-ui="v2"][data-theme="dark"] .product-detail-page .form-section { background: var(--ui-surface); color: var(--ui-text); border-color: var(--ui-border); }
[data-ui="v2"][data-theme="dark"] .template-card .template-type { color: var(--ui-link); }
[data-ui="v2"][data-theme="dark"] .template-card .shelf-tag { color: var(--ui-link); }

/* Fill colours used as text: tabs, tab counts, badges, links */
[data-ui="v2"][data-theme="dark"] .proj-tab.active,
[data-ui="v2"][data-theme="dark"] .proj-tab.active .proj-tab-count,
[data-ui="v2"][data-theme="dark"] .detail-tab.active,
[data-ui="v2"][data-theme="dark"] .detail-tab.active .tab-count,
[data-ui="v2"][data-theme="dark"] .sd-tab.active,
[data-ui="v2"][data-theme="dark"] .sd-tab.active .sd-tab-count,
[data-ui="v2"][data-theme="dark"] .owner-tab.active,
[data-ui="v2"][data-theme="dark"] .badge-sm,
[data-ui="v2"][data-theme="dark"] .assign-badge.chain,
[data-ui="v2"][data-theme="dark"] .store-link,
[data-ui="v2"][data-theme="dark"] .sd-breadcrumb a,
[data-ui="v2"][data-theme="dark"] .sd-info-sub a,
[data-ui="v2"][data-theme="dark"] .invite-header h1 { color: var(--ui-link); }
/* these two carry their colour inline */
[data-ui="v2"][data-theme="dark"] .excel-table td.cell-number > span[style*="color"],
[data-ui="v2"][data-theme="dark"] #model3d-studio-link { color: var(--ui-link) !important; }
[data-ui="v2"][data-theme="dark"] .store-editor-container .stat-value { color: var(--ui-text); }
[data-ui="v2"][data-theme="dark"] .tab-nav .tab-btn,
[data-ui="v2"][data-theme="dark"] .int-tabs button { color: var(--ui-text-secondary); }
[data-ui="v2"][data-theme="dark"] .tab-nav .tab-btn.active { color: var(--ui-link); }
[data-ui="v2"][data-theme="dark"] .int-tabs button.on { color: var(--ui-on-primary); }
[data-ui="v2"][data-theme="dark"] .tab-nav .tab-btn:hover { background: var(--ui-table-head-bg); }
[data-ui="v2"][data-theme="dark"] .analytics-mode-btn { background: var(--ui-surface) !important; }
[data-ui="v2"][data-theme="dark"] .analytics-mode-btn.active { background: var(--ui-primary) !important; color: var(--ui-on-primary) !important; }

/* Status colours on their pale dark-mode tints */
[data-ui="v2"][data-theme="dark"] .pill.active,
[data-ui="v2"][data-theme="dark"] .excel-table td.cell-status .status-active { color: var(--ui-success-text); }
[data-ui="v2"][data-theme="dark"] .msg.error { color: var(--ui-danger-text); }
[data-ui="v2"][data-theme="dark"] .sd-alert-info { background: var(--ui-primary-soft); }
[data-ui="v2"][data-theme="dark"] .sd-stat.green,
[data-ui="v2"][data-theme="dark"] .sd-stat.amber { background: var(--ui-surface); }
[data-ui="v2"][data-theme="dark"] .sd-stat.amber .sv { color: var(--ui-warning-text); }

/* Master packaging: the grey zero badge */
[data-ui="v2"][data-theme="dark"] .mp-badge.zero { background: var(--ui-table-head-bg); color: var(--ui-text-secondary); }

/* Replacements' status map and Storage's table heads */
[data-ui="v2"][data-theme="dark"] .rep-statusmap,
[data-ui="v2"][data-theme="dark"] .rep-body { background: var(--ui-surface); }
[data-ui="v2"][data-theme="dark"] .rep-statustable th,
[data-ui="v2"][data-theme="dark"] .rep-title span { color: var(--ui-text-secondary); }
[data-ui="v2"][data-theme="dark"] .tab-pane th { background: var(--ui-table-head-bg); color: var(--ui-table-head-text); }
[data-ui="v2"][data-theme="dark"] .forbidden-why code { background: var(--ui-table-head-bg); }

/* Integrations' muted grey, the 3D viewer's drawer labels */
[data-ui="v2"][data-theme="dark"] .int-wrap .muted,
[data-ui="v2"][data-theme="dark"] #pane-pim .muted,
[data-ui="v2"][data-theme="dark"] main > div > span.muted { color: var(--ui-text-secondary); }
[data-ui="v2"] .design-drawer .dd-section-title,
[data-ui="v2"] .design-drawer .dd-note,
[data-ui="v2"] .design-drawer .dd-row em,
[data-ui="v2"] .filter-drawer .fd-section-label { color: #8b95a7; }

/* ---------- 2b.1 Light: what was left below 4.5:1, colour only ---------------------------
   No size, spacing or layout changes. Both themes unless the selector says dark. */
/* the export configurator's own :root greys beat round 2's [data-ui] ones on a tie */
[data-ui="v2"]:root { --muted: var(--ui-text-secondary); --dim: var(--ui-text-secondary); }
[data-ui="v2"] .page-info .pi-meta,
[data-ui="v2"] .page > div[style*="color:#bbb"] { color: var(--ui-text-secondary) !important; }
[data-ui="v2"] .page-info.hd-band .pi-meta { color: rgba(255,255,255,.85) !important; }
/* the export's product without a photo: the 2.8 carton — off-white, its colour a band on top */
[data-ui="v2"] .gr-prod .noimg {
    background: #f8fafc;
    background-clip: padding-box;
    border-top: 3px solid transparent;
    box-sizing: border-box;
    color: #334155;
    text-shadow: none;
}
/* the floor plan's measurements and selected tool */
[data-ui="v2"] #dimensions-layer text { fill: #4b5563; }
[data-ui="v2"] .store-editor-container .tool-btn.active { color: #1565c0; }
/* fill colours as text on their own tint */
[data-ui="v2"] .badge-sm { color: var(--ui-link); }
[data-ui="v2"] .storage-tabs .tab-btn.active { color: var(--ui-link); border-bottom-color: var(--ui-primary); }
[data-ui="v2"] .sd-stat.amber .sv { color: var(--ui-warning-text); }
[data-ui="v2"] .msg.error { color: #b91c1c; }      /* --ui-danger is 4.4:1 on its own pink */
[data-ui="v2"][data-theme="dark"] .msg.error { color: var(--ui-danger-text); }
[data-ui="v2"][data-theme="dark"] .msg.error { background: color-mix(in srgb, var(--ui-danger) 18%, var(--ui-surface)); }
/* greys a shade too light for text */
[data-ui="v2"] .int-wrap .muted,
[data-ui="v2"] #pane-pim .muted,
[data-ui="v2"] main.container > div > span.muted,
[data-ui="v2"] .rep-statustable th,
[data-ui="v2"] .rep-title span { color: var(--ui-text-secondary); }
[data-ui="v2"] .op-bar .op-what,
[data-ui="v2"] .op-bar .op-who { color: #9ca3af; }

/* ---------- 2b.2 Login ----------------------------------------------------------------
   The page had its own look: a blue-violet gradient and the name in accent blue. Under the
   flag it is the app's: --ui-bg behind a white card with a --ui-border hairline, the logo
   mark and the name in --ui-text, Poppins, the 2.4 primary button, and an error box in
   --ui-danger on a pale ground. ui-flag.js is already the first script in the page's head,
   so the flag remembered in localStorage applies before anybody has signed in. */
[data-ui="v2"] body:has(> .login-container) { background: var(--ui-bg); font-family: 'Poppins', sans-serif; }
[data-ui="v2"] .login-container {
    background: var(--ui-surface);
    border: 1px solid var(--ui-border);
    box-shadow: 0 1px 3px rgba(15, 23, 42, .06);
}
[data-ui="v2"] .login-header h1 { color: var(--ui-text); font-size: 24px; font-weight: 600; }
[data-ui="v2"] .login-header h1::before {
    content: "";
    display: inline-block;
    width: 0.7em;
    height: 0.7em;
    margin-right: 0.45em;
    border-radius: 3px;
    background: var(--ui-logo);
    vertical-align: 0.02em;
}
[data-ui="v2"] .login-header p { color: var(--ui-text-secondary); }
[data-ui="v2"] .login-form label { color: var(--ui-text-secondary); }
[data-ui="v2"] .login-form input { border-color: var(--ui-border); background: var(--ui-surface); color: var(--ui-text); }
[data-ui="v2"] .login-form input:focus { border-color: var(--ui-focus); box-shadow: 0 0 0 3px color-mix(in srgb, var(--ui-focus) 25%, transparent); }
/* 4b.8 (ported to round 5, whose base is master without 4b): "Remember me for 30 days" stood
   far from its box. The page's own `.login-form input { width: 100% }` stretched the checkbox
   to fill the label beside the text; the box is its own size now, and box and text sit together
   in their one label, 8 px apart (the label's gap). */
[data-ui="v2"] .login-form .login-remember input[type="checkbox"] { width: auto; flex: none; margin: 0; padding: 0; }
[data-ui="v2"] .login-error {
    background: #fef2f2;
    color: #b91c1c;              /* --ui-danger as text is 4.4:1 on this pink; one shade darker */
    border-left-color: var(--ui-danger);
}
[data-ui="v2"][data-theme="dark"] .login-error {
    background: color-mix(in srgb, var(--ui-danger) 16%, var(--ui-surface));
    color: var(--ui-danger-text);
}

/* ---------- 2b.3 3D Studio: filter names that fit ----------------------------------------
   "All packaging" was cut to "All packagi…" at 1440 px: two selects a row in a 246 px
   library leave 76 px for text in Poppins 14 px, and "All specific types" needs 117. The
   names lose the "All " (studio.js: "Packaging · alle", in the muted style of a placeholder
   while nothing is chosen), the selects keep the page's own 12 px, and the library is 312 px
   wide, so the longest, "Specific type · alle", has room. */
[data-ui="v2"] .pk-library { width: 312px; }
[data-ui="v2"] body .pk-lib-filters .pk-filter {
    font-size: 12px;
    padding: 4px 22px 4px 6px;
    text-overflow: clip;
}
[data-ui="v2"] body .pk-lib-filters .pk-filter:has(option[value=""]:checked) { color: var(--ui-text-secondary); }
[data-ui="v2"] body .pk-lib-filters .pk-filter option { color: var(--ui-text); }

/* ---------- 2b.4 3D viewer: no "Product colors" legend -----------------------------------
   It counted units by each product's `color` field ("435 / 9"). Since 2.8 a product without
   a photo is a neutral carton and the colour only a band, so the swatches match nothing
   drawn and the counts answer no question. Under the flag it is not shown. */
[data-ui="v2"] #legend { display: none; }

/* ---------- 2b.5 Zone Traffic panel: one line per zone -----------------------------------
   Long zone names wrapped and pushed their score onto a second line. Now the name is cut
   with an ellipsis (whole in the tooltip, store_editor.html) and the score right-aligned. */
[data-ui="v2"] #zone-heatmap-legend .zt-row { gap: 8px; align-items: baseline; }
[data-ui="v2"] #zone-heatmap-legend .zt-name {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
[data-ui="v2"] #zone-heatmap-legend .zt-val {
    flex: 0 0 auto;
    white-space: nowrap;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* ---------- 2b.6 Analytics: the tab strip as a table head --------------------------------
   Inventory / Sales / Shelves / Space sat on a saturated blue bar with white text, the look
   2.6 took off the table heads. Now the same quiet head: --ui-table-head-bg, head text, and
   the active tab underlined in --ui-primary. The Top/Bottom switch on the right follows. */
[data-ui="v2"] body .analytics-panel .tab-bar,
[data-ui="v2"][data-theme="dark"] body .analytics-panel .tab-bar {
    background: var(--ui-table-head-bg);
    border-bottom: 1px solid var(--ui-border);
}
[data-ui="v2"] body .analytics-panel .tab-btn { color: var(--ui-text-secondary); }
[data-ui="v2"] body .analytics-panel .tab-btn:hover { color: var(--ui-text); }
[data-ui="v2"] body .analytics-panel .tab-btn.active {
    color: var(--ui-table-head-text);
    border-bottom-color: var(--ui-primary);
}
[data-ui="v2"] body .analytics-panel .tab-sub-filter { background: var(--ui-surface); border: 1px solid var(--ui-border); }
[data-ui="v2"] body .analytics-panel .filter-btn { color: var(--ui-text-secondary); }
[data-ui="v2"] body .analytics-panel .filter-btn:hover { color: var(--ui-text); }
[data-ui="v2"] body .analytics-panel .filter-btn.active { background: var(--ui-primary-soft); color: var(--ui-link); }
[data-ui="v2"] body .analytics-panel .tab-sub-sep { background: var(--ui-border); }

/* ---------- 2b.1, continued: panels that appear after a click -----------------------------
   routes.txt shoots pages as they load; scripts/routes-states.txt opens Analytics with a
   planogram, Store Analytics, the Zone Traffic panel and Storage's checks. Same rule: dark
   only, surfaces to tokens. Store Analytics writes its tiles' tints inline, so those are
   matched by the inline value. */
[data-ui="v2"][data-theme="dark"] .a-stats-bar b { color: var(--ui-text); }
/* the page's own dark rule paints these var(--gray-800), which round 2 points at --ui-text */
[data-ui="v2"][data-theme="dark"] .chart-card { background: var(--ui-surface); }
[data-ui="v2"][data-theme="dark"] .shelf-performance-chart svg text[fill="#1e40af"] { fill: var(--ui-link); }
[data-ui="v2"][data-theme="dark"] .analytics-panel svg text[fill="#ef4444"] { fill: var(--ui-danger-text); }
[data-ui="v2"][data-theme="dark"] .chart-card .chart-title,
[data-ui="v2"][data-theme="dark"] .space-chart-explain,
[data-ui="v2"][data-theme="dark"] .space-chart-explain .explain-item { background: var(--ui-table-head-bg); color: var(--ui-text-secondary); }
[data-ui="v2"][data-theme="dark"] .space-chart-explain b,
[data-ui="v2"][data-theme="dark"] .space-chart-explain .explain-label { color: var(--ui-text); }
[data-ui="v2"][data-theme="dark"] .space-chart-explain b.text-danger { color: var(--ui-danger-text); }
[data-ui="v2"][data-theme="dark"] #storeAnalyticsBody [style*="background:#f0fdf4"],
[data-ui="v2"][data-theme="dark"] #storeAnalyticsBody [style*="background:#fef2f2"],
[data-ui="v2"][data-theme="dark"] #storeAnalyticsBody [style*="background:#eff6ff"],
[data-ui="v2"][data-theme="dark"] #storeAnalyticsBody [style*="background:#fffbeb"] { background: var(--ui-surface) !important; }
[data-ui="v2"][data-theme="dark"] #storeAnalyticsBody [style*="color:#dc2626"],
[data-ui="v2"][data-theme="dark"] #storeAnalyticsBody [style*="color:#ef4444"] { color: var(--ui-danger-text) !important; }
[data-ui="v2"][data-theme="dark"] #storeAnalyticsBody [style*="color:#16a34a"],
[data-ui="v2"][data-theme="dark"] #storeAnalyticsBody [style*="color:#065f46"] { color: var(--ui-success-text) !important; }
[data-ui="v2"][data-theme="dark"] #storeAnalyticsBody [style*="color:#b45309"],
[data-ui="v2"][data-theme="dark"] #storeAnalyticsBody [style*="color:#f59e0b"] { color: var(--ui-warning-text) !important; }
[data-ui="v2"][data-theme="dark"] #storeAnalyticsBody a { color: var(--ui-link) !important; }
[data-ui="v2"][data-theme="dark"] #zone-heatmap-legend button { color: var(--ui-text); background: var(--ui-bg) !important; border-color: var(--ui-border) !important; }
[data-ui="v2"][data-theme="dark"] .check-row.hit-warning,
[data-ui="v2"][data-theme="dark"] .check-row.hit-error { background: var(--ui-surface); }
[data-ui="v2"][data-theme="dark"] .check-findings { background: var(--ui-bg); }
[data-ui="v2"][data-theme="dark"] .check-count[style*="#0f766e"] { color: var(--ui-success-text) !important; }
[data-ui="v2"][data-theme="dark"] .check-count[style*="#b45309"] { color: var(--ui-warning-text) !important; }
[data-ui="v2"][data-theme="dark"] .check-count[style*="#b42318"] { color: var(--ui-danger-text) !important; }
/* the shared tooltip is var(--gray-800) under white text: --ui-text, light, in dark */
[data-ui="v2"][data-theme="dark"] .tooltip { background: var(--ui-table-head-bg); color: var(--ui-text); }
/* the same mapping (--gray-700/800/900 → --ui-text) under Analytics' own dark backgrounds */
[data-ui="v2"][data-theme="dark"] .data-table.compact tbody tr.subtotal-row td { background: var(--ui-table-head-bg) !important; }
[data-ui="v2"][data-theme="dark"] .data-table.compact tbody tr.grandtotal-row td { background: var(--ui-border) !important; color: var(--ui-text); }
[data-ui="v2"][data-theme="dark"] .col-legend { background: var(--ui-surface); }
[data-ui="v2"][data-theme="dark"] .heatmap-tooltip { background: var(--ui-table-head-bg); color: var(--ui-text); }
[data-ui="v2"][data-theme="dark"] #storeAnalyticsBody [style*="color:var(--ui-primary"],
[data-ui="v2"][data-theme="dark"] #storeAnalyticsBody [style*="color:#2563eb"] { color: var(--ui-link) !important; }


/* ==========================================================================
   Round 3 — navigation and information architecture. (`.ui-v2-only` on the markup is
   a leftover name from when v1 stood beside it; nothing reads it since 7.1.)
   ========================================================================== */

/* ---------- 3.1 Top menu: six primaries, the active one underlined ---------- */
[data-ui="v2"] body .navbar {
    min-height: 56px;
    padding-top: 0;
    padding-bottom: 0;
    align-items: stretch;
    gap: 24px;
    background: var(--ui-surface);
    box-shadow: inset 0 -1px 0 var(--ui-border);
}
[data-ui="v2"] body .nav-brand { display: flex; align-items: center; white-space: nowrap; }
[data-ui="v2"] body .nav-links-v2 {
    align-items: stretch;
    gap: 4px;
    margin: 0 auto 0 0;
    padding: 0;
}
[data-ui="v2"] body .nav-links-v2 li { display: flex; }
[data-ui="v2"] body .nav-links-v2 a {
    padding: 0 12px;
    border-radius: 0;
    background: none;
    color: var(--ui-text-secondary);
    font-size: var(--ui-fs-14);
    font-weight: 500;
    white-space: nowrap;
    box-shadow: inset 0 -2px 0 transparent;
}
[data-ui="v2"] body .nav-links-v2 a:hover {
    background: none;
    color: var(--ui-text);
    box-shadow: inset 0 -2px 0 var(--ui-border);
}
[data-ui="v2"] body .nav-links-v2 a.active,
[data-ui="v2"] body .nav-links-v2 a.active:hover {
    background: none;
    color: var(--ui-text);
    font-weight: 600;
    box-shadow: inset 0 -2px 0 var(--ui-primary);
}
[data-ui="v2"] body .nav-links-v2 a:focus-visible { outline-offset: -2px; }
[data-ui="v2"] body .navbar .nav-auth { align-items: center; white-space: nowrap; }

/* ---------- 3.2 Retired: a tab under Products, a count on Products ---------- */
[data-ui="v2"] body .nav-links-v2 .nav-badge {
    display: inline-block;
    min-width: 18px;
    margin-left: 6px;
    padding: 0 5px;
    border-radius: 9px;
    background: var(--ui-warning-text);
    color: var(--ui-on-primary);
    font-size: var(--ui-fs-12);
    font-weight: 600;
    line-height: 18px;
    text-align: center;
}
[data-ui="v2"] body .nav-links-v2 .nav-badge[hidden] { display: none; }

/* ---------- 3.3 Menus: one dropdown (static/js/ui-menu.js) ---------- */
[data-ui="v2"] body .ui-menu { position: relative; display: inline-flex; }
[data-ui="v2"] body .ui-menu-list {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    z-index: 1200;
    min-width: 200px;
    padding: 4px;
    background: var(--ui-surface);
    border: 1px solid var(--ui-border);
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);
    display: flex;
    flex-direction: column;
    text-align: left;
}
[data-ui="v2"] body .ui-menu-list[hidden] { display: none; }
[data-ui="v2"] body .ui-menu-list.ui-menu-right { left: auto; right: 0; }
[data-ui="v2"] body .ui-menu-list [role="menuitem"] {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    margin: 0;
    padding: 7px 10px;
    border: 0;
    border-radius: 5px;
    background: none;
    box-shadow: none;
    color: var(--ui-text);
    font: inherit;
    font-size: var(--ui-fs-14);
    font-weight: 400;
    line-height: 1.4;
    text-align: left;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
}
[data-ui="v2"] body .ui-menu-list [role="menuitem"]:hover,
[data-ui="v2"] body .ui-menu-list [role="menuitem"]:focus-visible {
    background: var(--ui-bg);
    color: var(--ui-text);
    box-shadow: none;
}
[data-ui="v2"] body .ui-menu-list [role="menuitem"][aria-current="page"] { color: var(--ui-link); font-weight: 600; }
[data-ui="v2"] body .ui-menu-list [role="menuitem"] i { font-size: 1.05em; color: var(--ui-text-secondary); }
[data-ui="v2"] body .ui-menu-list hr { margin: 4px 0; border: 0; border-top: 1px solid var(--ui-border); }
[data-ui="v2"] body .ui-menu-head {
    display: flex;
    flex-direction: column;
    gap: 1px;
    padding: 8px 10px 10px;
    margin-bottom: 4px;
    border-bottom: 1px solid var(--ui-border);
    font-size: var(--ui-fs-13);
    color: var(--ui-text-secondary);
    white-space: nowrap;
}
[data-ui="v2"] body .ui-menu-head strong { color: var(--ui-text); font-size: var(--ui-fs-14); font-weight: 600; }

/* the user menu's button: the name, like a top-menu item */
[data-ui="v2"] body .nav-user-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 36px;
    padding: 0 10px;
    border: 0;
    border-radius: 6px;
    background: none;
    color: var(--ui-text);
    font: inherit;
    font-size: var(--ui-fs-14);
    font-weight: 500;
    cursor: pointer;
}
[data-ui="v2"] body .nav-user-btn:hover,
[data-ui="v2"] body .ui-menu.open .nav-user-btn { background: var(--ui-bg); }
[data-ui="v2"] body .nav-user-btn.active { box-shadow: inset 0 -2px 0 var(--ui-primary); border-radius: 6px 6px 0 0; }
[data-ui="v2"] body .nav-user-btn i { color: var(--ui-text-secondary); }

/* ---------- 3.4 Breadcrumbs: Primary › Object › View (partials/crumbs.html) ---------- */
[data-ui="v2"] body .ui-crumbs {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0;
    min-width: 0;
    font-size: var(--ui-fs-13);
    line-height: 1.4;
    color: var(--ui-text-secondary);
}
[data-ui="v2"] body .ui-crumbs a,
[data-ui="v2"] body .toolbar-meta .ui-crumb-primary {
    color: var(--ui-link);
    text-decoration: none;
    font-weight: 500;
}
[data-ui="v2"] body .ui-crumbs a:hover,
[data-ui="v2"] body .toolbar-meta .ui-crumb-primary:hover { text-decoration: underline; }
[data-ui="v2"] body .ui-crumbs .ui-crumb-object {
    max-width: 40ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
[data-ui="v2"] body .ui-crumb-sep { padding: 0 8px; color: var(--ui-text-secondary); }
[data-ui="v2"] body .ui-crumb-view { color: var(--ui-text); font-weight: 500; }
/* on the 3D pages' dark top bar */
[data-ui="v2"] body[data-ui-surface="dark"] .topbar .ui-crumbs { color: #b8c4d6; }
[data-ui="v2"] body[data-ui-surface="dark"] .topbar .ui-crumbs a { color: #93c5fd; }
[data-ui="v2"] body[data-ui-surface="dark"] .topbar .ui-crumb-sep { color: #8b93a3; }
[data-ui="v2"] body[data-ui-surface="dark"] .topbar .ui-crumb-view { color: #fff; }
/* product detail: the crumb stands where "← Back to Products" stood */
[data-ui="v2"] body .product-detail-page .header-left .ui-crumbs { margin-bottom: 4px; }
/* floor plan: the crumb is the header's name */
[data-ui="v2"] body .store-editor-container .editor-header .ui-crumbs { font-size: var(--ui-fs-14); }
[data-ui="v2"] body .store-editor-container .editor-header .ui-crumb-object { font-weight: 600; }
/* the planogram editor: Editor › <name input> › Planogram, then the version, then the
   category and subcategory, which are still edited in place */
[data-ui="v2"] body .toolbar-meta { display: flex; align-items: center; }
[data-ui="v2"] body .toolbar-meta .ui-crumb-primary { order: 0; font-size: var(--ui-fs-13); padding-left: 0.5rem; }
[data-ui="v2"] body .toolbar-meta .ui-crumb-sep-1 { order: 1; }
[data-ui="v2"] body .toolbar-meta #planogram-name { order: 2; }
[data-ui="v2"] body .toolbar-meta .ui-crumb-sep-2 { order: 3; }
[data-ui="v2"] body .toolbar-meta .ui-crumb-view { order: 4; font-size: var(--ui-fs-13); }
[data-ui="v2"] body .toolbar-meta #version-indicator { order: 5; margin-left: 10px; }
[data-ui="v2"] body .toolbar-meta #planogram-category,
[data-ui="v2"] body .toolbar-meta .toolbar-separator,
[data-ui="v2"] body .toolbar-meta #planogram-subcategory { order: 6; color: var(--ui-text-secondary); }
[data-ui="v2"] body .toolbar-meta #planogram-category { margin-left: 12px; }
[data-ui="v2"] body .toolbar-meta .toolbar-separator { padding: 0 2px; }
/* the separator that stood between the subcategory and the name has nothing to separate */
[data-ui="v2"] body .toolbar-meta #planogram-subcategory + datalist + .toolbar-separator { display: none; }
[data-ui="v2"] body .toolbar-meta { flex-wrap: nowrap; white-space: nowrap; }
[data-ui="v2"] body .toolbar-meta .planogram-category-input { min-width: 6ch; }
[data-ui="v2"] body .store-editor-container .editor-header .ui-crumbs { flex-wrap: nowrap; white-space: nowrap; }
[data-ui="v2"] body .store-editor-container .editor-header .ui-crumb-object { max-width: 24ch; }
/* the 3D pages: the crumb ends in "3D", so the title that repeated it steps aside */
[data-ui="v2"] body[data-ui-surface="dark"] .topbar #title,
[data-ui="v2"] body[data-ui-surface="dark"] .topbar #store-title { display: none; }
[data-ui="v2"] body[data-ui-surface="dark"] .topbar .bc { font-size: var(--ui-fs-13); }
[data-ui="v2"] body .toolbar-meta > :not(.planogram-category-input):not(.toolbar-separator) { flex-shrink: 0; }
[data-ui="v2"] body .toolbar-meta .planogram-category-input { flex-shrink: 1; text-overflow: ellipsis; font-size: var(--ui-fs-12); }
[data-ui="v2"] body .toolbar-meta .planogram-category-input { padding: 0.25rem 0.3rem; min-width: 4ch; }
[data-ui="v2"] body .toolbar-meta .ui-crumb-sep { padding: 0 6px; }
[data-ui="v2"] body .toolbar-meta #version-indicator { margin-left: 6px; }
[data-ui="v2"] body .toolbar-meta #planogram-category { margin-left: 8px; }

/* ---------- 3.5 Page headers: one pattern ----------
   Title left (24 px) with its subtitle under it in --ui-text-secondary; the actions at the
   right, the primary last; secondary actions gathered in menus where there are many.
   A grid rather than new markup: every page's header keeps the elements it has, and the
   grid puts them where the pattern wants them. */
[data-ui="v2"] body .page-header {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: 16px;
    row-gap: 2px;
    align-items: center;
}
[data-ui="v2"] body .page-header > * { grid-column: 1; min-width: 0; }
[data-ui="v2"] body .page-header > .header-actions,
[data-ui="v2"] body .page-header > .btn,
[data-ui="v2"] body .page-header > .dropdown {
    grid-column: 2;
    grid-row: 1 / span 2;
    justify-self: end;
    align-self: center;
}
[data-ui="v2"] body .page-header h1 {
    margin: 0;
    font-size: var(--ui-fs-24);
    line-height: 1.33;
    font-weight: 600;
    color: var(--ui-text);
}
[data-ui="v2"] body .page-header .page-subtitle {
    margin: 0;
    font-size: var(--ui-fs-14);
    color: var(--ui-text-secondary);
    text-align: left;
}
[data-ui="v2"] body .page-header .header-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
[data-ui="v2"] body .page-header .ui-menu-btn { display: inline-flex; align-items: center; gap: 6px; }
[data-ui="v2"] body .page-header .ui-menu-btn i { font-size: 0.85em; }

/* ---------- 3.6 The demo filter: one segmented control, the same on Products and Stores ---------- */
[data-ui="v2"] body .demo-switch {
    display: inline-flex;
    align-self: center;
    box-sizing: border-box;
    height: 34px;
    padding: 2px;
    gap: 2px;
    border: 1px solid var(--ui-border);
    border-radius: 8px;
    background: var(--ui-bg);
    overflow: visible;
}
[data-ui="v2"] body .demo-switch button,
[data-ui="v2"] body .demo-switch button:last-child {
    height: 28px;
    padding: 0 12px;
    border: 0;
    border-radius: 6px;
    background: transparent;
    box-shadow: none;
    color: var(--ui-text-secondary);
    font-size: var(--ui-fs-13);
    font-weight: 500;
    line-height: 28px;
}
[data-ui="v2"] body .demo-switch button:hover {
    background: transparent;
    color: var(--ui-text);
    box-shadow: none;
}
[data-ui="v2"] body .demo-switch button.active,
[data-ui="v2"] body .demo-switch button.active:hover {
    background: var(--ui-surface);
    color: var(--ui-text);
    font-weight: 600;
    box-shadow: inset 0 0 0 1px var(--ui-border), 0 1px 2px rgba(15, 23, 42, 0.08);
}

/* ---------- 3.7 The editor's top bar: document · add · views · save ----------
   Left: which document (Planogram | Floor Plan, Open, New). Then "+ Add" (Gondola, Shelf,
   Base deck) with Undo/Redo. The view controls in the middle. Right: save state and
   autosave, Export, Save — Save the primary, last. The icon row under the breadcrumb is
   round 4's and is not touched here. */
[data-ui="v2"] body .toolbar-primary .btn-primary[onclick="showNewPlanogramModal()"] {
    background: var(--ui-surface);
    color: var(--ui-text);
    box-shadow: inset 0 0 0 1px var(--ui-border);
}
[data-ui="v2"] body .toolbar-primary .btn-primary[onclick="showNewPlanogramModal()"]:hover {
    background: var(--ui-bg);
    box-shadow: inset 0 0 0 1px var(--ui-muted);
}
[data-ui="v2"] body #edit-toolbar {
    padding-left: 10px;
    border-left: 1px solid var(--ui-border);
}
[data-ui="v2"] body .editor-add-menu .ui-menu-btn { display: inline-flex; align-items: center; gap: 4px; }
/* the menus open over the row below */
[data-ui="v2"] body .editor-toolbar.toolbar-primary { z-index: 11; }
/* Two rows. Row 1: the document, then adding (and undoing); Autosave at its right end.
   Row 2: the view controls, then — at the right — save state, Export, Save. Measured at
   1440 px with the properties panel open (864 px for the bar): 762 and 781 px, so neither
   row wraps; one row would need 1,085. #save-toolbar's children join the toolbar's own
   rows for this (`display: contents`), except while the editor hides it, which it does
   with an inline style. */
[data-ui="v2"] body #save-toolbar:not([style*="none"]) { display: contents !important; }
[data-ui="v2"] body .toolbar-primary > .toolbar-section:first-child { order: 0; }
[data-ui="v2"] body .toolbar-primary > #edit-toolbar { order: 1; }
[data-ui="v2"] body #save-toolbar .autosave-toggle-label { order: 2; margin-left: auto; }
[data-ui="v2"] body .toolbar-primary > .toolbar-spacer { order: 3; flex: 0 0 100%; height: 0; }
[data-ui="v2"] body #save-toolbar #view-3d-link { order: 4; }
[data-ui="v2"] body #save-toolbar #view-3d-newtab { order: 5; }
[data-ui="v2"] body #save-toolbar .editor-view-toggle { order: 6; }
[data-ui="v2"] body #save-toolbar .save-status-indicator { order: 7; margin-left: auto; }
[data-ui="v2"] body #save-toolbar #export-link { order: 8; }
[data-ui="v2"] body #save-toolbar .editor-save-btn { order: 9; }
/* Export becomes a secondary action, Save the primary */
[data-ui="v2"] body #save-toolbar #export-link {
    background: var(--ui-surface);
    color: var(--ui-text);
    box-shadow: inset 0 0 0 1px var(--ui-border);
}
[data-ui="v2"] body #save-toolbar #export-link:hover { background: var(--ui-bg); box-shadow: inset 0 0 0 1px var(--ui-muted); }
[data-ui="v2"] body #save-toolbar .editor-save-btn {
    background: var(--ui-primary);
    color: var(--ui-on-primary);
    box-shadow: none;
}
[data-ui="v2"] body #save-toolbar .editor-save-btn:hover { background: var(--ui-primary-hover); color: var(--ui-on-primary); }
/* 3.3, a viewer: no admin items, so the separator would sit right under the header's rule */
[data-ui="v2"] body .ui-menu-head + hr { display: none; }

/* ---------- 4.1 The editor's icon row: four groups, tooltips, labels when there is room ----------
   View (overlays, zoom) · Measure · Analysis · Tools, in that order, with a thin rule between
   the groups. The markup keeps its old order; `order` sorts it here by the tg-* classes, so flag
   off is untouched. The active state is the soft primary, not a filled blue square. */
[data-ui="v2"] body .toolbar-secondary { container: edtools / inline-size; }
[data-ui="v2"] body .toolbar-secondary .tool-group {
    gap: 2px;
    padding: 3px 4px;
    background: var(--ui-surface);
    border-color: var(--ui-border);
    border-radius: 8px;
}
[data-ui="v2"] body .tool-group > .tool-divider { display: none; }
[data-ui="v2"] body .tool-group > .tg-view { order: 10; }
[data-ui="v2"] body .tool-group > .tg-zoom { order: 11; }
[data-ui="v2"] body .tool-group > .tg-center { order: 12; }
[data-ui="v2"] body .tool-group > .tool-sep-measure { order: 19; }
[data-ui="v2"] body .tool-group > .tg-measure { order: 20; }
[data-ui="v2"] body .tool-group > .tool-sep-analyse { order: 29; }
[data-ui="v2"] body .tool-group > .tg-analyse { order: 30; }
[data-ui="v2"] body .tool-group > .tool-sep-tools { order: 39; }
[data-ui="v2"] body .tool-group > .tg-tools { order: 40; }
[data-ui="v2"] body .tool-group > .tool-sep {
    display: block;
    flex: 0 0 1px;
    align-self: stretch;
    margin: 4px 5px;
    background: var(--ui-border);
}
[data-ui="v2"] body .toolbar-secondary .btn-tool {
    width: auto;
    min-width: var(--d-btn-base);
    padding: 0 7px;
    gap: 6px;
    border-color: transparent;
    border-radius: 6px;
    background: transparent;
    color: var(--ui-text-secondary);
}
[data-ui="v2"] body .toolbar-secondary .btn-tool:hover { background: var(--ui-bg); color: var(--ui-text); border-color: transparent; }
[data-ui="v2"] body .toolbar-secondary .btn-tool.active,
[data-ui="v2"] body .toolbar-secondary .btn-tool.active:hover {
    background: var(--ui-primary-soft);
    border-color: transparent;
    color: var(--ui-link);
}
/* style.css sizes these two by id (36 px square, larger glyph) and fills the first when on */
[data-ui="v2"] body .toolbar-secondary #label-toggle-btn,
[data-ui="v2"] body .toolbar-secondary .tg-label-settings { width: auto; height: var(--d-btn-base); font-size: var(--d-icon-base); }
[data-ui="v2"] body .toolbar-secondary #label-toggle-btn.active { background: var(--ui-primary-soft); color: var(--ui-link); }
[data-ui="v2"] body .toolbar-secondary .btn-tool:focus-visible { outline: 2px solid var(--ui-primary); outline-offset: 1px; }
[data-ui="v2"] body .toolbar-secondary .zoom-display { color: var(--ui-text-secondary); min-width: 38px; }
/* the labels: only in windows over 1600 px, and only while the row has room for them */
[data-ui="v2"] body .btn-tool .tool-label { display: none; font-size: var(--ui-fs-12); font-weight: 500; white-space: nowrap; }
@media (min-width: 1601px) {
    @container edtools (min-width: 1300px) {
        [data-ui="v2"] body .btn-tool .tool-label { display: inline; }
    }
}
/* the tooltip (ui-nav.js): the group in small capitals over what the button does */
[data-ui="v2"] .ui-tooltip {
    position: fixed;
    z-index: 10050;
    max-width: 280px;
    padding: 6px 9px;
    border-radius: 6px;
    background: var(--ui-text);
    color: var(--ui-surface);
    font-size: var(--ui-fs-12);
    line-height: 1.4;
    pointer-events: none;
    box-shadow: 0 4px 12px rgba(15, 23, 42, 0.18);
}
[data-ui="v2"] .ui-tooltip[hidden] { display: none; }
[data-ui="v2"] .ui-tooltip-group {
    display: block;
    font-size: 0.85em;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    opacity: 0.8;
}

/* ---------- 4.2 Overlays: one menu with five checkboxes (editor-overlays.js) ----------
   The first of the View group. Placement numbers, shelf labels and dimensions are the editor's
   own switches; peg dots and the facings frame have none, so they are hidden here. Opacity,
   not display: a hidden hook can still be clicked to select its peg. */
[data-ui="v2"] body .tool-group > .tg-overlays { order: 9; }
[data-ui="v2"] body .editor-overlays-menu .ui-menu-list { min-width: 210px; }
[data-ui="v2"] body .editor-overlays-menu [role="menuitemcheckbox"] {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    padding: 7px 10px;
    border-radius: 5px;
    color: var(--ui-text);
    font-size: var(--ui-fs-14);
    white-space: nowrap;
    cursor: pointer;
}
[data-ui="v2"] body .editor-overlays-menu [role="menuitemcheckbox"]:hover { background: var(--ui-bg); }
[data-ui="v2"] body .editor-overlays-menu [role="menuitemcheckbox"] input { margin: 0; accent-color: var(--ui-primary); }
[data-ui="v2"] body .editor-overlays-menu.open #overlays-btn { background: var(--ui-primary-soft); color: var(--ui-link); }
[data-ui="v2"] body.ov-hide-peg-dots .peg-handle,
[data-ui="v2"] body.ov-hide-peg-dots .peg-dot { opacity: 0; }
[data-ui="v2"] body.ov-hide-facings-frame .peg-facing-group-border { display: none; }

/* ---------- 4.3 Shelf labels and placement numbers on the canvas ----------
   "#2 Hylde 1/5" becomes a narrow tag on the shelf edge in --ui-text-secondary, not white
   text over the shelf; placement numbers become small round badges, --ui-text on --ui-surface
   with a 1 px rule, not red. The editor only: the export's preview (html.preview-mode) and
   so the PDF draw them as before. The inline colour on the label is the shelf's contrast
   colour for the old style, hence !important. */
[data-ui="v2"]:not(.preview-mode) body .shelf > .shelf-label {
    left: 4px;
    width: auto;                /* style.css's second .shelf-label rule (a chart's) sets 50 px */
    text-align: left;
    padding: 0 5px;
    border: 1px solid var(--ui-border);
    border-radius: 3px;
    background: var(--ui-surface);
    color: var(--ui-text-secondary) !important;
    font-size: 9px;
    font-weight: 500;
    line-height: 13px;
    letter-spacing: 0;
    text-shadow: none;
    z-index: 4;                 /* over the price labels on the edge (z-index 3) */
    /* 4b.5: the strip takes the room the shelf has and is cut from the right */
    max-width: calc(100% - 8px);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
[data-ui="v2"]:not(.preview-mode) body .location-badge {
    box-sizing: border-box;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border: 1px solid var(--ui-border);
    border-radius: 999px;
    background: var(--ui-surface);
    color: var(--ui-text);
    box-shadow: none;
    font-size: 9px;
    font-weight: 600;
    line-height: 14px;
}
[data-ui="v2"]:not(.preview-mode) body .location-badge.badge-medium { min-width: 20px; height: 20px; font-size: 11px; line-height: 18px; padding: 0 5px; }
[data-ui="v2"]:not(.preview-mode) body .location-badge.badge-large { min-width: 24px; height: 24px; font-size: 13px; line-height: 22px; padding: 0 6px; }

/* ---------- 4.4 The floor plan editor's left panel and keyboard help ----------
   The tools as the planogram editor's icon row has them: grouped (Navigate · Draw · Annotate),
   icon with label, always in view — the Tools section loses its header under v2. Two columns,
   a caption over each group, a rule between groups. The other sections are an accordion with
   one open (store-editor.js). The keyboard hints leave the canvas for a "?" in the top bar
   whose list opens over the right panel, never over the plan. */
[data-ui="v2"] body .store-editor-container .fp-tools > .section-toggle { display: none; }
[data-ui="v2"] body .store-editor-container .fp-tools > .section-body { display: block !important; padding: 10px 10px 10px; }
[data-ui="v2"] body .store-editor-container .fp-tools .tool-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 2px 4px;
}
[data-ui="v2"] body .store-editor-container .fp-tool-cap {
    flex: 0 0 100%;
    margin: 6px 0 2px;
    padding-top: 6px;
    border-top: 1px solid var(--ui-border);
    color: var(--ui-text-secondary);
    font-size: var(--ui-fs-12);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}
[data-ui="v2"] body .store-editor-container .fp-cap-nav { order: 0; margin-top: 0; padding-top: 0; border-top: 0; }
[data-ui="v2"] body .store-editor-container .fp-nav { order: 1; }
[data-ui="v2"] body .store-editor-container .fp-cap-draw { order: 2; }
[data-ui="v2"] body .store-editor-container .fp-draw { order: 3; }
[data-ui="v2"] body .store-editor-container .tool-btn[data-tool="draw-zone"] { order: 4; }
[data-ui="v2"] body .store-editor-container .fp-cap-note { order: 5; }
[data-ui="v2"] body .store-editor-container .fp-note { order: 6; }
[data-ui="v2"] body .store-editor-container .fp-tools .tool-btn {
    flex: 0 0 calc(50% - 2px);
    box-sizing: border-box;
    flex-direction: row;
    justify-content: flex-start;
    gap: 7px;
    min-height: 32px;
    padding: 4px 8px;
    border: 0;
    border-radius: 6px;
    background: transparent;
    color: var(--ui-text-secondary);
    font-size: var(--ui-fs-13);
    font-weight: 500;
    text-align: left;
}
[data-ui="v2"] body .store-editor-container .fp-tools .tool-btn i[class*="ph"] { font-size: 1.1rem; }
[data-ui="v2"] body .store-editor-container .fp-tools .tool-btn:hover { background: var(--ui-bg); color: var(--ui-text); }
[data-ui="v2"] body .store-editor-container .fp-tools .tool-btn.active { background: var(--ui-primary-soft); color: var(--ui-link); }
[data-ui="v2"] body .store-editor-container .fp-tools .tool-info {
    margin-top: 8px;
    border-color: var(--ui-border);
    color: var(--ui-text-secondary);
    background: var(--ui-bg);
}
/* the accordion's headers: one rule between them, the open one in --ui-text */
[data-ui="v2"] body .store-editor-container .sidebar-left .tools-section { border-bottom-color: var(--ui-border); }
[data-ui="v2"] body .store-editor-container .sidebar-left .section-toggle { padding: 10px 12px; white-space: nowrap; }
/* the top bar gains "?": the right side keeps its width (3D, Settings, Save were already at the
   edge at 1440 px); the store code yields, with an ellipsis and the whole code in its title */
[data-ui="v2"] body .store-editor-container .editor-header { gap: 12px; }
[data-ui="v2"] body .store-editor-container .editor-header .header-left { flex: 1 1 auto; min-width: 0; gap: 12px; }
[data-ui="v2"] body .store-editor-container .editor-header .header-right { flex: 0 0 auto; gap: 8px; }
[data-ui="v2"] body .store-editor-container .editor-header .dimensions { white-space: nowrap; }
/* the layer and overlay switches keep their words (Layout, Paths); the crumb's name yields */
[data-ui="v2"] body .store-editor-container .editor-header .layer-toggle,
[data-ui="v2"] body .store-editor-container .editor-header .editor-mode-toggle { flex-shrink: 0; }
[data-ui="v2"] body .store-editor-container .editor-header .ui-crumbs { flex: 0 1 auto; min-width: 0; overflow: hidden; }
[data-ui="v2"] body .store-editor-container .editor-header .ui-crumbs .ui-crumb-object { min-width: 4ch; overflow: hidden; text-overflow: ellipsis; }
[data-ui="v2"] body .store-editor-container .editor-header .store-code {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
[data-ui="v2"] body .store-editor-container .sidebar-left .section-toggle[aria-expanded="true"] { color: var(--ui-text); }
/* the keyboard help */
[data-ui="v2"] body .store-editor-container .fp-keys-wrap { position: relative; display: inline-flex; }
[data-ui="v2"] body .store-editor-container .fp-keys-btn {
    min-width: 30px;
    font-weight: 600;
    background: var(--ui-surface);
    color: var(--ui-text);
    box-shadow: inset 0 0 0 1px var(--ui-border);
}
[data-ui="v2"] body .store-editor-container .fp-keys-btn[aria-expanded="true"] { background: var(--ui-primary-soft); color: var(--ui-link); }
[data-ui="v2"] body .store-editor-container .fp-keys {
    position: fixed;             /* top: set from the button when it opens */
    right: 8px;                  /* over the right panel (220 px), clear of the plan */
    z-index: 1300;
    width: 208px;
    box-sizing: border-box;
    padding: 10px 12px 12px;
    background: var(--ui-surface);
    border: 1px solid var(--ui-border);
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(15, 23, 42, 0.14);
    color: var(--ui-text);
    font-size: var(--ui-fs-13);
}
[data-ui="v2"] body .store-editor-container .fp-keys[hidden] { display: none; }
[data-ui="v2"] body .store-editor-container .fp-keys-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
[data-ui="v2"] body .store-editor-container .fp-keys-close { border: 0; background: none; color: var(--ui-text-secondary); cursor: pointer; padding: 2px; }
[data-ui="v2"] body .store-editor-container .fp-keys dl {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 5px 8px;
    margin: 0;
    align-items: center;
}
[data-ui="v2"] body .store-editor-container .fp-keys dd { margin: 0; color: var(--ui-text-secondary); }
[data-ui="v2"] body .store-editor-container .fp-keys kbd {
    display: inline-block;
    min-width: 18px;
    padding: 1px 5px;
    border: 1px solid var(--ui-border);
    border-radius: 4px;
    background: var(--ui-bg);
    color: var(--ui-text);
    font: 600 var(--ui-fs-12)/1.4 ui-monospace, SFMono-Regular, Menlo, monospace;
    text-align: center;
}

/* ---------- 4.5 Properties: the shelves in Statistics, the Versions heading ----------
   The shelf list is ordered and named in planogram-editor.js (statShelfNames). Versions: one
   line from the server, "v17 · kladde · seneste udgivne v13", over the list. */
[data-ui="v2"] body .version-list .version-headline {
    margin: 0 0 6px;
    padding: 0 0 6px;
    border-bottom: 1px solid var(--ui-border);
    color: var(--ui-text);
    font-size: var(--ui-fs-13);
    font-weight: 600;
    line-height: 1.4;
}

/* ---------- 4.7 AI Placement: layout only ----------
   One width (560 px, ai-placement.js AI_V2_WIDTH; the grip goes), the setup and the sections
   as one list ruled in --ui-border, and the tinted blocks (the summary's blue, the
   parameters' and tabs' grey, the indigo of the chosen tab) become the surface the other
   panels are. The amber of "things the region could not cover" stays amber: it is a warning.
   The words and what Apply does are untouched. */
[data-ui="v2"] body .ai-panel {
    box-shadow: 0 12px 24px -8px rgba(15, 23, 42, .18);
}
[data-ui="v2"] body .ai-panel .ai-grip { display: none; }
[data-ui="v2"] body .ai-panel-head,
[data-ui="v2"] body .ai-foot {
    background: var(--ui-surface);
    border-color: var(--ui-border);
}
[data-ui="v2"] body .ai-panel .muted,
[data-ui="v2"] body .ai-optimises,
[data-ui="v2"] body .ai-apply-why,
[data-ui="v2"] body .ai-row .why { color: var(--ui-text-secondary); }
[data-ui="v2"] body .ai-row .why b { color: var(--ui-text); }
[data-ui="v2"] body .ai-tabs { border-bottom-color: var(--ui-border); }
[data-ui="v2"] body .ai-tab {
    background: var(--ui-surface);
    color: var(--ui-text-secondary);
    border-color: var(--ui-border);
}
[data-ui="v2"] body .ai-tab:hover { background: var(--ui-bg); }
[data-ui="v2"] body .ai-tab.on {
    background: var(--ui-surface);
    color: var(--ui-text);
    border-color: var(--ui-border);
    border-bottom-color: var(--ui-surface);
    box-shadow: inset 0 2px 0 var(--ui-primary);
}
[data-ui="v2"] body .ai-tab small,
[data-ui="v2"] body .ai-tab.on small,
[data-ui="v2"] body .ai-cost { color: var(--ui-warning-text); }
[data-ui="v2"] body .ai-summary {
    background: var(--ui-surface);
    color: var(--ui-text);
    border-bottom: 1px solid var(--ui-border);
}
[data-ui="v2"] body .ai-why p { color: var(--ui-text); }
[data-ui="v2"] body .ai-copy:hover { background: var(--ui-bg); }
[data-ui="v2"] body .ai-params,
[data-ui="v2"] body .ai-panel details.ai-params > summary {
    background: var(--ui-surface);
    color: var(--ui-text);
    border-color: var(--ui-border);
}
[data-ui="v2"] body .ai-panel details.ai-params,
[data-ui="v2"] body .ai-panel details.ai-params[open] > summary { border-bottom-color: var(--ui-border); }
/* The setup: a list, one rule between rows, the open row on --ui-bg. */
[data-ui="v2"] body .ai-panel .ai-set,
[data-ui="v2"] body .ai-panel .ai-set:last-of-type { border-color: var(--ui-border); }
[data-ui="v2"] body .ai-panel .ai-set > summary:hover,
[data-ui="v2"] body .ai-panel .ai-set[open] > summary { background: var(--ui-bg); }
[data-ui="v2"] body .ai-filter { border-color: var(--ui-border); }
[data-ui="v2"] body .ai-filter > summary b,
[data-ui="v2"] body .ai-panel details.ai-params > summary b,
[data-ui="v2"] body .ai-facings { color: var(--ui-link); }
[data-ui="v2"] body .ai-line-name,
[data-ui="v2"] body .ai-sub { color: var(--ui-text-secondary); }
[data-ui="v2"] body .ai-row:hover,
[data-ui="v2"] body .ai-line-row:hover,
[data-ui="v2"] body .ai-values label:hover { background: var(--ui-bg); }

/* ---------- 4b.1 Labels: the fields that fit, in the user's order ----------
   renderProductLabelV2 counts the lines that fit and sets the font size inline; one field per
   line. The SKU line is never cut short: it sets the label's least width (the other lines are
   `contain: inline-size`, so they add nothing to it) and may stand out past a narrow product.
   Every other line ends in an ellipsis at the label's width. The editor only, as 4.3. */
[data-ui="v2"]:not(.preview-mode) body .product-label-v2 {
    display: block;
    width: calc(100% - 4px);
    min-width: max-content;
    max-width: none;
    max-height: none;
    padding: 1px 4px;
    white-space: nowrap;
    text-align: center;
}
[data-ui="v2"]:not(.preview-mode) body .product-label-v2 span {
    display: block;
    line-height: 1.2;
    overflow: hidden;
    text-overflow: ellipsis;
    contain: inline-size;
}
[data-ui="v2"]:not(.preview-mode) body .product-label-v2 span.label-sku {
    overflow: visible;
    text-overflow: clip;
    contain: none;
}
[data-ui="v2"]:not(.preview-mode) body .product-label-v2 .label-name { max-width: none; }

/* The Labels panel's field list: a grip to drag by, the checkbox, the name. */
[data-ui="v2"] body .label-settings-dropdown .label-field-list { margin: 4px 0 0; }
[data-ui="v2"] body .label-settings-dropdown .label-field-row {
    gap: 6px;
    padding: 3px 4px;
    border-radius: 4px;
    cursor: grab;
    user-select: none;
}
[data-ui="v2"] body .label-settings-dropdown .label-field-row.dragging { opacity: 0.5; }
[data-ui="v2"] body .label-settings-dropdown .label-field-grip { color: var(--ui-text-secondary); font-size: 14px; }

/* ---------- 4b.2 Rotation: one field, one line, only under 24 px ----------
   A label is turned only when the product is narrower than 24 px on screen (or the user chose
   90°/-90°), and then it holds the SKU alone on one line, running up the product. */
[data-ui="v2"]:not(.preview-mode) body .product-label-v2.label-turned {
    writing-mode: vertical-rl;
    width: auto;
    min-width: 0;
    height: auto;
    min-height: max-content;
    padding: 4px 1px;
}
[data-ui="v2"]:not(.preview-mode) body .product-label-v2.label-turned span { contain: none; overflow: visible; }
[data-ui="v2"]:not(.preview-mode) body .product-label-v2.label-turned-neg { transform: translate(-50%, -50%) rotate(180deg); }

/* ---------- 4b.3 Presets at the top of the Labels panel ----------
   A segmented control: Minimal · Standard · Detailed · Custom, the chosen one in the primary's
   soft fill, as the Front/Left/Right switch has it. */
[data-ui="v2"] body .label-settings-dropdown .label-presets {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 2px;
    margin: 0 0 10px;
    padding: 2px;
    border: 1px solid var(--ui-border);
    border-radius: 6px;
    background: var(--ui-bg);
}
[data-ui="v2"] body .label-settings-dropdown .label-presets button {
    padding: 4px 6px;
    border: 0;
    border-radius: 4px;
    background: transparent;
    color: var(--ui-text-secondary);
    font: inherit;
    font-size: var(--ui-fs-12);
    font-weight: 500;
    white-space: nowrap;
    cursor: pointer;
}
[data-ui="v2"] body .label-settings-dropdown .label-presets button:hover { color: var(--ui-text); }
[data-ui="v2"] body .label-settings-dropdown .label-presets button.active {
    background: var(--ui-surface);
    color: var(--ui-link);
    box-shadow: 0 0 0 1px var(--ui-border);
}

/* ---------- 4b.4 Index mode: the Legend beside the canvas ----------
   A panel over the right edge of the canvas: number, SKU, name, brand, facings for every
   placement in number order; the selected placement's row in the primary's soft fill. */
[data-ui="v2"] body .editor-main { position: relative; }
[data-ui="v2"] body .label-legend {
    position: absolute;
    right: 12px;
    bottom: 12px;
    width: 340px;
    max-width: calc(100% - 24px);
    display: flex;
    flex-direction: column;
    background: var(--ui-surface);
    border: 1px solid var(--ui-border);
    border-radius: 8px;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
    z-index: 450;               /* over the canvas, under the embedded 3D view (500) */
    font-size: var(--ui-fs-12);
    color: var(--ui-text);
}
[data-ui="v2"] body .label-legend-head {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 8px 8px 12px;
    border-bottom: 1px solid var(--ui-border);
}
[data-ui="v2"] body .label-legend-head strong { font-size: var(--ui-fs-14); font-weight: 600; }
[data-ui="v2"] body .label-legend-count { color: var(--ui-text-secondary); }
[data-ui="v2"] body .label-legend-close { margin-left: auto; }
[data-ui="v2"] body .label-legend-body { overflow: auto; min-height: 0; flex: 1; }
[data-ui="v2"] body .label-legend table { width: 100%; border-collapse: collapse; table-layout: fixed; }
[data-ui="v2"] body .label-legend th {
    position: sticky;
    top: 0;
    background: var(--ui-surface);
    color: var(--ui-text-secondary);
    font-weight: 500;
    text-align: left;
    padding: 5px 6px;
    border-bottom: 1px solid var(--ui-border);
}
[data-ui="v2"] body .label-legend td {
    padding: 4px 6px;
    border-bottom: 1px solid var(--ui-border);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
[data-ui="v2"] body .label-legend th:nth-child(1), [data-ui="v2"] body .label-legend td.num { width: 34px; text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; }
[data-ui="v2"] body .label-legend th:nth-child(2) { width: 72px; }
[data-ui="v2"] body .label-legend th:nth-child(4) { width: 56px; }
[data-ui="v2"] body .label-legend th:nth-child(5), [data-ui="v2"] body .label-legend td.fac { width: 34px; text-align: right; }
[data-ui="v2"] body .label-legend tbody tr { cursor: pointer; }
[data-ui="v2"] body .label-legend tbody tr:hover { background: var(--ui-bg); }
[data-ui="v2"] body .label-legend tbody tr.selected { background: var(--ui-primary-soft); }
[data-ui="v2"] body .label-settings-dropdown .label-index-toggle { margin: 0 0 6px; font-weight: 500; }

/* ---------- 4b.5 The shelf strip's fields, under "Shelf Labels" ---------- */
[data-ui="v2"] body .label-settings-dropdown .shelf-strip-fields { margin: 0 0 0 12px; }
[data-ui="v2"] body .label-settings-dropdown .shelf-strip-fields label { padding: 2px 0; font-size: var(--ui-fs-14); }

/* ---------- 4b.6 Coverage: the bottom 40 %, the picture showing through ----------
   The label stands on the bottom edge of the product (of the stack, when it is stretched over
   one) and is no taller than 40 % of it (LABEL_MAX_COVER, counted in JS); --ui-surface at 90 %
   so the product can be seen through it. Price labels on the shelf edge and the location badge
   are not touched. */
[data-ui="v2"]:not(.preview-mode) body .product-label-v2 {
    top: auto;
    bottom: 2px;
    transform: translateX(-50%);
    background: color-mix(in srgb, var(--ui-surface) 90%, transparent);
    border: 0;
    border-radius: 2px;
    box-shadow: none;
}
[data-ui="v2"]:not(.preview-mode) body .product-label-v2.label-turned-neg { transform: translateX(-50%) rotate(180deg); }

/* ---------- 4b.8 3D Studio's bottom bar: "Transparent PNG" on one line ----------
   The note broke over two lines because the buttons beside it took the room. It keeps its
   width and never wraps; the buttons wrap among themselves, to the right, when the pane is
   narrow. (Classes added in packshots.html; nothing else reads them.) */
[data-ui="v2"] body .pk-out-bar { gap: 8px 12px; }
[data-ui="v2"] body .pk-out-bar .pk-out-note { flex: none; white-space: nowrap; }
[data-ui="v2"] body .pk-out-bar .pk-out-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 4px;
    min-width: 0;
}

/* 4b.6, measured: every line of the label in the theme's text colours — the SKU in --ui-text,
   the rest in --ui-text-secondary — whatever colour style.css gives a field (Facings was the
   primary blue: 2.3:1 on the dark surface). On the 90 % surface over a black photo, the worst
   case, that is 14.3:1 and 6.1:1 in light. */
[data-ui="v2"]:not(.preview-mode) body .product-label-v2 span { color: var(--ui-text-secondary); }
[data-ui="v2"]:not(.preview-mode) body .product-label-v2 span.label-sku { color: var(--ui-text); }

/* ---------- 5.3 Language: in the user menu ----------
   English · Dansk as two small choices on one row; the chosen one in the primary's soft fill. */
[data-ui="v2"] body .ui-menu-list .nav-lang {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 6px 10px;
    color: var(--ui-text-secondary);
}
[data-ui="v2"] body .ui-menu-list .nav-lang button {
    padding: 3px 8px;
    border: 1px solid var(--ui-border);
    border-radius: 999px;
    background: var(--ui-surface);
    color: var(--ui-text);
    font: inherit;
    font-size: var(--ui-fs-12);
    cursor: pointer;
}
[data-ui="v2"] body .ui-menu-list .nav-lang button[aria-checked="true"] {
    background: var(--ui-primary-soft);
    border-color: var(--ui-primary);
    color: var(--ui-link);
    font-weight: 600;
}


/* ==========================================================================
   Round 6 — zones and contrast (Anders, 29/10: "the areas must be clearly separated; today
   white flows into white"). Every zone is one of four surfaces, each a step from the next,
   and a zone's edge is --ui-border-strong; --ui-border is for rows and fields INSIDE a zone.
   No colour below this line is written out except in 6.1: everything reads a token.
   ========================================================================== */

/* ---------- 6.1 Tokens ----------
   Light, from the page inwards: the app (page and canvas) #eef1f5, a section head #f1f5f9,
   a toolbar #f8fafc, a panel #fff. Dark keeps the order and the steps: the app the deepest,
   the panel the lightest, the zone edge lighter than every surface it separates. */
[data-ui="v2"] {
    --ui-app-bg: #eef1f5;
    --ui-toolbar-bg: #f8fafc;
    --ui-panel-bg: #ffffff;
    --ui-border-strong: #cbd5e1;
    --ui-section-head-bg: #f1f5f9;
    --ui-zone-shadow: 0 1px 3px rgba(15, 23, 42, .08);
    --ui-float-shadow: 0 8px 24px rgba(15, 23, 42, .16);
}
/* 6.6: the data panels' dark slab, the same in light and dark (the zebra row 4 % lighter) */
[data-ui="v2"] {
    --ui-data-panel-bg: #1e293b;
    --ui-data-panel-head-bg: #0f172a;
    --ui-data-panel-zebra: color-mix(in srgb, #fff 4%, var(--ui-data-panel-bg));
    --ui-data-panel-text: #e2e8f0;
    --ui-data-panel-muted: #94a3b8;
    --ui-data-panel-border: #334155;
    --ui-data-panel-accent: #7dd3fc;
    --ui-data-panel-warn: #fca5a5;
    --ui-data-panel-ok: #86efac;
}
[data-ui="v2"][data-theme="dark"] {
    --ui-app-bg: #0b1220;
    --ui-toolbar-bg: #172032;
    --ui-panel-bg: #1e293b;
    --ui-border-strong: #475569;
    --ui-section-head-bg: #131c2c;
    --ui-zone-shadow: 0 1px 3px rgba(0, 0, 0, .45);
    --ui-float-shadow: 0 8px 24px rgba(0, 0, 0, .55);
}
/* the 3D pages' dark content (2.5): the same dark set */
[data-ui="v2"] body[data-ui-surface="dark"] main {
    --ui-app-bg: #14171e;
    --ui-toolbar-bg: #1d212a;
    --ui-panel-bg: #232833;
    --ui-border-strong: #4b5263;
    --ui-section-head-bg: #191c24;
    --ui-zone-shadow: 0 1px 3px rgba(0, 0, 0, .45);
    --ui-float-shadow: 0 8px 24px rgba(0, 0, 0, .55);
}

/* ---------- 6.2 Editor: the app, the sheet, the bars, the panels ----------
   Behind everything the app grey, with the canvas's grid (style.css, .canvas-inner) on top of
   it; the planogram on a white sheet with a hairline and a soft shadow. The two bars over the
   canvas are toolbar grey with a strong rule under each; the panels either side are white with
   a strong rule towards the canvas. Inside a panel, each section opens with a head on the
   section grey between two rules. The sheet's edge is a ring of shadow, not a border, so the
   fixtures inside it do not move by a pixel. */
[data-ui="v2"] body .editor-main,
[data-ui="v2"] body .fixture-canvas { background: var(--ui-app-bg); }
[data-ui="v2"] body .fixtures-wrapper {
    background: var(--ui-panel-bg);
    box-shadow: 0 0 0 1px var(--ui-border-strong), var(--ui-zone-shadow);
}

[data-ui="v2"] body .editor-toolbar.toolbar-primary,
[data-ui="v2"] body .editor-toolbar.toolbar-secondary {
    background: var(--ui-toolbar-bg);
    border-bottom: 1px solid var(--ui-border-strong);
}
/* the icon row: one strip on the toolbar, its groups split by strong hairlines */
[data-ui="v2"] body .toolbar-secondary .tool-group {
    background: var(--ui-toolbar-bg);
    border-color: var(--ui-border-strong);
}
[data-ui="v2"] body .tool-group > .tool-sep { background: var(--ui-border-strong); }
/* a hover must differ from the bar it is on, which is now the old hover colour */
[data-ui="v2"] body .toolbar-secondary .btn-tool:hover { background: var(--ui-section-head-bg); }
[data-ui="v2"] body #edit-toolbar { border-left-color: var(--ui-border-strong); }
/* 7.4: the name is an <input>, which takes the browser's field colour (black) and not the
   bar's text — on the dark bar it was 1.3:1 */
[data-ui="v2"] body .planogram-title-input { color: var(--ui-text); }
/* disabled (no planogram loaded): the browser's grey disabled text is 2.1:1 on the dark bar */
[data-ui="v2"] body .planogram-title-input:disabled { color: var(--ui-text-secondary); }

[data-ui="v2"] body .product-sidebar {
    background: var(--ui-panel-bg);
    border-right: 1px solid var(--ui-border-strong);
}
[data-ui="v2"] body .properties-panel {
    background: var(--ui-panel-bg);
    border-left: 1px solid var(--ui-border-strong);
}
/* the panel's own title, level with the toolbar beside it */
[data-ui="v2"] body .properties-panel .panel-title-row {
    background: var(--ui-toolbar-bg);
    border-bottom: 1px solid var(--ui-border-strong);
}
/* Fixture, Elements, Statistics, Trays, Versions: a head between two rules. The rule under a
   section's content would double the next head's, so the head draws both and the section none. */
[data-ui="v2"] body .properties-panel .panel-section { border-bottom: 0; }
[data-ui="v2"] body .properties-panel .panel-section:last-child { border-bottom: 1px solid var(--ui-border-strong); }
[data-ui="v2"] body .properties-panel .panel-header {
    background: var(--ui-section-head-bg);
    border-top: 1px solid var(--ui-border-strong);
    border-bottom: 1px solid var(--ui-border-strong);
    color: var(--ui-text-secondary);
}
[data-ui="v2"] body .properties-panel .panel-section:first-of-type .panel-header { border-top: 0; }
/* the left panel's tabs and filter: the same head, the list below it white */
[data-ui="v2"] body .product-sidebar .sidebar-header {
    background: var(--ui-section-head-bg);
    border-bottom: 1px solid var(--ui-border-strong);
}

/* ---------- 6.3 Floor plan: the same pattern ----------
   The header a toolbar; the tool panel and the properties panel white with a strong rule
   towards the drawing; the drawing on the app grey in light (its own grid lines are the SVG's).
   Each panel section opens with a head on the section grey between two rules; heads that follow
   each other (collapsed sections) share a rule rather than doubling it (margin-top: -1px). The
   floating zoom bar is a panel: white, a strong edge, a shadow. */
[data-ui="v2"] body .store-editor-container { background: var(--ui-app-bg); }
[data-ui="v2"] body .store-editor-container .editor-header {
    background: var(--ui-toolbar-bg);
    border-bottom: 1px solid var(--ui-border-strong);
    box-shadow: none;
}
/* light only: in dark the drawing keeps its own light grey (2b.1) — the SVG's colours (labels,
   the floor's #f5f5f5 at half opacity) are drawn for a light ground and turn to mud on a dark one */
[data-ui="v2"]:not([data-theme="dark"]) body .store-editor-container .canvas-container { background: var(--ui-app-bg); }
[data-ui="v2"] body .store-editor-container .sidebar-left {
    background: var(--ui-panel-bg);
    border-right: 1px solid var(--ui-border-strong);
}
[data-ui="v2"] body .store-editor-container .sidebar-right {
    background: var(--ui-panel-bg);
    border-left: 1px solid var(--ui-border-strong);
}
[data-ui="v2"] body .store-editor-container .tools-section { border-bottom: 0; }
[data-ui="v2"] body .store-editor-container .tools-section > .section-toggle {
    box-sizing: border-box;
    width: 100%;
    margin-top: -1px;
    background: var(--ui-section-head-bg);
    border-top: 1px solid var(--ui-border-strong);
    border-bottom: 1px solid var(--ui-border-strong);
}
[data-ui="v2"] body .store-editor-container .tools-section > .section-toggle:hover { background: var(--ui-app-bg); }
[data-ui="v2"] body .store-editor-container .props-section { border-bottom: 0; }
[data-ui="v2"] body .store-editor-container .props-section > h3 {
    margin: -1px -0.75rem 0.6rem;
    padding: 0.5rem 0.75rem;
    background: var(--ui-section-head-bg);
    border-top: 1px solid var(--ui-border-strong);
    border-bottom: 1px solid var(--ui-border-strong);
}
[data-ui="v2"] body .store-editor-container .props-section > h3:first-child { margin-top: -0.6rem; }
[data-ui="v2"] body .store-editor-container .sidebar-right > .props-section:last-child { border-bottom: 1px solid var(--ui-border-strong); }
[data-ui="v2"] body .store-editor-container .canvas-controls {
    background: var(--ui-panel-bg);
    border: 1px solid var(--ui-border-strong);
    box-shadow: var(--ui-float-shadow);
}

/* ---------- 6.4 The other pages: grey page, white cards ----------
   The page is the app grey; whatever holds content is a white card with a strong edge and an
   8 px radius. Inside a card, a table's head is on the section grey with a strong rule under
   it, and its filter row a toolbar strip; the bar of filters above a table is a toolbar strip
   too. The tab strips under page titles get the strong rule; a page title without tabs under
   it gets one of its own. The top menu: white with a strong rule under it. */
[data-ui="v2"] body:not([data-ui-surface="dark"]) { background: var(--ui-app-bg); }
[data-ui="v2"] body .navbar {
    background: var(--ui-panel-bg);
    box-shadow: inset 0 -1px 0 var(--ui-border-strong);
}

[data-ui="v2"] body .excel-table-container,
[data-ui="v2"] body .settings-section,
[data-ui="v2"] body .analytics-panel,
[data-ui="v2"] body .compare-column,
[data-ui="v2"] body .chain-card,
[data-ui="v2"] body .storage-card:not(.total),
[data-ui="v2"] body .storage-status-bar,
[data-ui="v2"] body .summary-card,
[data-ui="v2"] body .template-card,
[data-ui="v2"] body .planogram-card,
[data-ui="v2"] body .form-card,
[data-ui="v2"] body .images-section,
[data-ui="v2"] body .table-container {
    background: var(--ui-panel-bg);
    border: 1px solid var(--ui-border-strong);
    border-radius: 8px;
}
/* a table with its toolbar on top: one card, the toolbar its top strip */
[data-ui="v2"] body .excel-toolbar {
    background: var(--ui-toolbar-bg);
    border: 1px solid var(--ui-border-strong);
    border-bottom: 0;
    border-radius: 8px 8px 0 0;
}
[data-ui="v2"] body .excel-toolbar + .excel-table-container { border-radius: 0 0 8px 8px; }

/* the filters above a table */
[data-ui="v2"] body .filters-bar,
[data-ui="v2"] body .a-toolbar,
[data-ui="v2"] body .proj-toolbar {
    padding: 10px 12px;
    background: var(--ui-toolbar-bg);
    border: 1px solid var(--ui-border-strong);
    border-radius: 8px;
}
[data-ui="v2"] body .filters-bar { margin-bottom: 16px; }

/* table heads and the filter row under them */
[data-ui="v2"] body .excel-table th,
[data-ui="v2"] body table.pg-grid th,
[data-ui="v2"] body .data-table th,
[data-ui="v2"] body .data-table.compact th,
[data-ui="v2"] body .at-table th,
[data-ui="v2"] body .at-detail-table th,
[data-ui="v2"] body .at-notif-log-table th,
[data-ui="v2"] body .confirm-table th {
    background: var(--ui-section-head-bg);
    border-bottom: 1px solid var(--ui-border-strong);
}
[data-ui="v2"] body .excel-table thead tr + tr th,
[data-ui="v2"] body .excel-table .excel-filter-row th {
    background: var(--ui-toolbar-bg);
    border-bottom: 1px solid var(--ui-border-strong);
}
[data-ui="v2"] body .excel-table-container { --excel-filter-bg: var(--ui-toolbar-bg); }

/* the tab strips' idle tabs: #667085 (products.html) was 4.5:1 on the old page white and is
   4.4:1 on the app grey; the secondary text token is 6.9:1 there */
[data-ui="v2"] body .tab-nav .tab-btn:not(.active) { color: var(--ui-text-secondary); }

/* page heads */
[data-ui="v2"] body .tab-nav,
[data-ui="v2"] body .proj-tabs { border-bottom-color: var(--ui-border-strong); }
[data-ui="v2"] body .page-header:not(:has(+ .tab-nav, + .proj-tabs)) {
    padding-bottom: 12px;
    border-bottom: 1px solid var(--ui-border-strong);
}

/* ---------- 6.5 Dialogs and floating panels ----------
   Every dialog (the app's .modal, Share among them), Gondola Info and Load analysis, AI
   Placement and the 3D Studio's packshot dialog: a white panel with a strong edge and the
   float shadow, its title row on the section grey with a strong rule under it (and, where
   there is one, its footer the same over it). */
[data-ui="v2"] body .modal-content,
[data-ui="v2"] body .gondola-info-panel,
[data-ui="v2"] body .ai-panel,
[data-ui="v2"] body .pk-gal {
    background: var(--ui-panel-bg);
    border: 1px solid var(--ui-border-strong);
    box-shadow: var(--ui-float-shadow);
}
[data-ui="v2"] body .modal-header,
[data-ui="v2"] body .gondola-info-panel .gip-header,
[data-ui="v2"] body .ai-panel-head,
[data-ui="v2"] body .pk-gal-head {
    background: var(--ui-section-head-bg);
    border-bottom: 1px solid var(--ui-border-strong);
    color: var(--ui-text);
}
[data-ui="v2"] body .modal-footer,
[data-ui="v2"] body .ai-foot {
    background: var(--ui-section-head-bg);
    border-top: 1px solid var(--ui-border-strong);
}

/* ---------- 6.6 The data panels are dark again, in both themes ----------
   Gondola Info ("Lokation …") and Load analysis are tables of numbers over the drawing and read
   best as a dark slab, as before round 2. Rather than restate 2.5's and 6.5's rules, the panel
   points the general tokens they read at its own, so every rule inside it turns dark at once.
   Share, AI Placement and the packshot dialog keep the light 6.5 look. --ui-data-panel-ok is
   not in the brief: the theme's green text is drawn for white and fails on the slab. */
[data-ui="v2"] body .gondola-info-panel {
    --ui-surface: var(--ui-data-panel-bg);
    --ui-panel-bg: var(--ui-data-panel-bg);
    --ui-bg: var(--ui-data-panel-zebra);
    --ui-section-head-bg: var(--ui-data-panel-head-bg);
    --ui-table-head-bg: var(--ui-data-panel-head-bg);
    --ui-table-head-text: var(--ui-data-panel-text);
    --ui-text: var(--ui-data-panel-text);
    --ui-text-secondary: var(--ui-data-panel-muted);
    --ui-muted: var(--ui-data-panel-muted);
    --ui-border: var(--ui-data-panel-border);
    --ui-border-strong: var(--ui-data-panel-border);
    --ui-link: var(--ui-data-panel-accent);
    --ui-primary: var(--ui-data-panel-accent);
    --ui-primary-soft: color-mix(in srgb, var(--ui-data-panel-accent) 16%, var(--ui-data-panel-bg));
    --ui-danger-text: var(--ui-data-panel-warn);
    --ui-success-text: var(--ui-data-panel-ok);
}
