/* The Resale Edit — app stylesheet.
   Design rationale, accessibility contrast numbers, brand-guideline
   references and the history behind individual rules live in docs/CHANGELOG.md
   (repo-only, not deployed), under the 2026-09-11 "CSS comment cleanup"
   entry and the brand-rework entries it references. Keep this file's own
   comments terse. */

/* 1. Theme variables & reset
   -------------------------------------------------------------------------
   THREE themes (accessibility Stage 7, 2026-09-07): the bare :root is the
   LIGHT theme and the default — a fresh visitor with no saved preference
   gets light, NOT their OS setting. `:root[data-theme="dark"]` redefines
   only the role tokens. "System" is resolved to light/dark in JS
   (components/head.php pre-paint script + js/theme.js) which stamps
   data-theme accordingly, so there's exactly one dark block to maintain.
   Brand palette values (--ink/--charcoal/--peach/--blush/--ivory) are
   FIXED — they're the identity; the role tokens below theme-shift.
   ------------------------------------------------------------------------- */
:root {
    /* Raw brand palette (docs/THE_RESALE_EDIT_BRAND_GUIDELINES.md) — fixed. */
    --ink: #243336;
    --charcoal: #4A5050;
    --peach: #D09083;
    --blush: #F0C9C0;
    --ivory: #FEF9F5;
    --white: #FFFFFF;

    --font-stack: "Public Sans", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

    /* --- role tokens: LIGHT --- */
    --bg-dark: var(--ink);
    --bg-light: #FEF9F5;
    --surface: #FFFFFF;          /* cards, inputs, popovers */
    --surface-alt: #F4F1EF;      /* section headers, muted panels */
    --surface-2: #ECEEF1;        /* pills, hover states, faint fills */
    --surface-sunk: #FAFAFA;     /* code blocks, the very lightest wells */
    --text-dark: var(--ink);
    /* Muted body text — the one documented AA-not-AAA exception (§11 3-tier
       hierarchy would collapse onto Charcoal at true 7:1). */
    --text-muted: #5C6363;
    --border-color: #E5DEDA;
    --border-soft: #E5DEDA;
    --primary: var(--ink);
    --slate: var(--charcoal);
    --focus-ring: var(--ink);
    --focus-core: var(--ink);    /* inner ring of the :focus-visible shadow */
    --focus-halo: var(--ivory);  /* outer halo */
    --vinted-pink: #e534eb;
    --vinted-light: #fee3ff;
    --ebay-blue: #0066cc;
    --info-text: #0A4F8F;
    --info-bg: #E5F1FA;
    --green-success: #136040;
    --green-success-hover: #0F4E34;
    --success-bg: #EAF6EF;
    --warn-amber: #6F4A06;
    --warn-bg: #fff4e0;
    --warn-border: #f0c777;
    --danger-red: #8F1E1A;
    --danger-bg: #fdecec;
    --danger-border: #CF7B77;
    --overlay: rgba(0, 0, 0, 0.5);
    --shadow-card: 0 2px 12px rgba(0, 0, 0, 0.05);
    --shadow-pop: 0 6px 16px rgba(36, 51, 54, 0.18);

    /* Primary BUTTON — Action Coral, separate from --primary (Ink). */
    --btn-primary-bg: #9C5B4F;
    --btn-primary-hover: #824A40;
    --btn-primary-active: #6F3F37;
    --btn-primary-text: #FFFFFF;

    /* Icon system V1 (components/icons.php) — the coral accent stroke, one
       element per two-tone icon. The icon's other strokes use currentColor.
       --icon-success is the green used only by the success/submit/live glyphs. */
    --icon-accent: #CB5F49;
    --icon-success: #1E9E6A;

    /* Control-edge colour — ~3.3:1 on white, meets 1.4.11 (§7/§8 over §12). */
    --border-strong: #8E9391;

    /* Marketplace accents — a 3px left stripe on a surface, never a fill. */
    --mkt-vinted: #D426DA;
    --mkt-ebay:   #0066CC;
    --mkt-depop:  #1E1E1E;
    --mkt-causee: #6F42C1;

    color-scheme: light;
}

/* --- role tokens: DARK (accessibility Stage 7). "Warm dark" — a near-black
   with an ink undertone so Peach/Blush read as accents. Contrast verified:
   text 14.8:1, secondary 9.7:1, muted 6.5:1 (the same AA exception), the
   Action Coral button 8:1 (better than light). --- */
:root[data-theme="dark"] {
    --bg-light: #1C1917;
    --surface: #252220;
    --surface-alt: #2E2A27;
    --surface-2: #302C29;
    --surface-sunk: #211E1C;
    --text-dark: #F2EBE5;
    --text-muted: #A79C94;
    --border-color: #38332F;
    --border-soft: #38332F;
    --primary: #F2EBE5;
    --slate: #C9BFB8;
    --focus-ring: #F2EBE5;
    --focus-core: #F2EBE5;
    --focus-halo: #1C1917;
    --vinted-pink: #E972ED;
    --vinted-light: #3A2233;
    --ebay-blue: #4D9BE8;
    --info-text: #6FB2EF;
    --info-bg: #1F2A33;
    --green-success: #57C08C;
    --green-success-hover: #3FA876;
    --success-bg: #1E2E27;
    --warn-amber: #E0A94A;
    --warn-bg: #322A1B;
    --warn-border: #5C4A22;
    --danger-red: #EC8078;
    --danger-bg: #33211F;
    --danger-border: #8F4A44;
    --overlay: rgba(0, 0, 0, 0.68);
    --shadow-card: 0 2px 14px rgba(0, 0, 0, 0.4);
    --shadow-pop: 0 8px 22px rgba(0, 0, 0, 0.55);
    --btn-primary-bg: #E0A08F;
    --btn-primary-hover: #EDB4A4;
    --btn-primary-active: #F0C3B6;
    --btn-primary-text: #1C1917;
    --icon-accent: #E88C74;
    --icon-success: #57C08C;
    --border-strong: #5C554F;
    --mkt-vinted: #E972ED;
    --mkt-ebay:   #4D9BE8;
    --mkt-depop:  #E4E4E4;
    --mkt-causee: #A98AE4;
    color-scheme: dark;
}

:root {
    /* Corner-radius scale — one ladder, applied everywhere (2026-09-07,
       tightened ~25% 2026-09-07). card > panel > control > sm, plus a
       full pill. Nothing should carry a hand-picked px radius outside this set. */
    --radius-card: 10px;     /* main cards, inventory items, table wrap */
    --radius-panel: 8px;     /* secondary panels, banners, expanders, menus */
    --radius-control: 6px;   /* inputs, selects, textareas, buttons, media */
    --radius-sm: 4px;        /* thumbnails <=75px, tiny compact controls */
    --radius-pill: 999px;    /* pills, tags, badges, toggle chips */
}

* { box-sizing: border-box; }
body { margin: 0; font-family: var(--font-stack); color: var(--text-dark); background: var(--bg-light); }

/* Deliberate high-contrast keyboard focus everywhere — never suppress.
   Ink ring + Ivory halo so it stays visible on any surface; the transparent
   outline is the Windows High-Contrast-Mode fallback. */
:focus-visible {
    outline: 2px solid transparent;
    outline-offset: 2px;
    box-shadow: 0 0 0 2px var(--focus-halo), 0 0 0 5px var(--focus-core);
    border-radius: 4px;
}

/* Icon system V1 (components/icons.php / js/icons.js) — inline two-tone line
   icons that replaced the UI emoji. Sized in em so they track the text they
   sit beside; main strokes follow currentColor, the coral accent is
   var(--icon-accent). Buttons/labels that hold an icon + text get a small gap
   via the flex helper below. */
.re-icon {
    width: 1.05em;
    height: 1.05em;
    flex: 0 0 auto;
    display: inline-block;
    vertical-align: -0.16em;
    overflow: visible;
    /* Gap to the label that follows. em-scaled so it tracks the type size,
       plus a flat 5px so it doesn't read cramped in the small card buttons.
       Zeroed below for the no-label cases (icon-only controls, trailing). */
    margin-right: calc(0.42em + 5px);
}
/* No label after the icon → no trailing gap. `.re-icon--bare` is set on the
   JS mini icon-only buttons (photo reorder / delete / per-photo download). */
.icon-btn-flat > .re-icon,
.modal-close > .re-icon,
.re-icon--bare,
.re-icon--trailing { margin-right: 0; }
.modal-close > .re-icon { vertical-align: -0.22em; width: 1.15em; height: 1.15em; }
.icon-btn-flat > .re-icon { vertical-align: middle; width: 1.55em; height: 1.55em; }
/* a trailing icon (label then icon) flips the gap to the left */
.re-icon--trailing { margin-left: calc(0.42em + 5px); }
/* on a coloured ground (status pills, filled buttons) the coral accent can
   muddy — force the whole glyph to the ground's text colour instead. */
.re-icon.is-mono * { stroke: currentColor; }
/* slightly larger where an icon leads a section heading */
h1 > .re-icon, h2 > .re-icon, h3 > .re-icon, summary > .re-icon { width: 1.15em; height: 1.15em; }

/* 2. Core layout & navigation header */
header {
    background: var(--bg-light);
    color: var(--slate);
    border-bottom: 3px solid var(--border-color);
    padding: 18px max(18px, calc((100vw - 1050px) / 2));
    display: flex;
    flex-direction: column;
    gap: 15px;
}
.header-top { display: flex; justify-content: space-between; align-items: center; width: 100%; gap: 15px; }

/* Brand wordmark: Peach-on-Ivory is below WCAG normal-text contrast but is
   exempt as part of a logo/brand name — do not reuse text-sized elsewhere. */
.brand-wordmark { margin: 0; font-size: 21px; font-weight: 800; display: flex; align-items: baseline; gap: 7px; white-space: nowrap; }
.wordmark-eyebrow { font-size: 11px; font-weight: 700; letter-spacing: 0.1em; color: var(--slate); }
.wordmark-resale { color: var(--text-dark); }
.wordmark-edit { color: var(--peach); }

.brand-mark { max-height: 40px; display: block; }
/* Decorative mark gives way first on the narrowest phones. */
@media (max-width: 380px) {
    .brand-mark { display: none; }
    .brand-wordmark { font-size: 18px; }
}

/* Header triggers: brand mark + Search/Settings/Hamburger — one shared
   icon-button style, real 40px+ touch target. */
.header-triggers { display: flex; align-items: center; gap: 8px; }

.icon-btn-flat, #menuToggle {
    background: transparent;
    border: 0;
    width: 40px;
    height: 40px;
    padding: 0;
    margin: 0;
    font-size: 16px;
    cursor: pointer;
    border-radius: var(--radius-control);
    transition: 0.15s;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--slate);
    font-weight: 700;
}
.icon-btn-flat:hover, #menuToggle:hover { background: var(--surface-alt); color: var(--text-dark); }
/* Filled Peach surface (Ink-on-Peach 4.99:1) marks the open panel. */
.icon-btn-flat.active { background: var(--peach); color: var(--ink); }

/* Header "listings to take down" count (S5) — the delist worklist badge.
   Hidden at 0 via the `hidden` attribute; the count sits as a small
   danger-coloured pill over the icon's top-right. */
.delist-badge { position: relative; color: var(--danger-red); }
.delist-badge:hover { color: var(--danger-red); background: var(--danger-bg); }
.delist-badge-count {
    position: absolute;
    top: 2px;
    right: 2px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: var(--radius-pill);
    background: var(--danger-red);
    color: #fff;
    font-size: 10px;
    font-weight: 800;
    line-height: 16px;
    text-align: center;
}

#menuToggle { display: none; }

/* Nav — one plain text-link list, left-bordered drawer on mobile / bottom-
   bordered row on desktop. Single Ink indicator marks the current view. */
.header-nav { display: flex; gap: 4px; flex-wrap: wrap; width: 100%; margin-top: 5px; }
.header-nav .tab-link {
    border: 0;
    border-left: 4px solid transparent;
    border-radius: var(--radius-control);
    padding: 13px 14px;
    font-weight: 700;
    font-size: 14px;
    cursor: pointer;
    transition: 0.15s;
    display: flex;
    align-items: center;
    gap: 10px;
    justify-content: flex-start;
    text-align: left;
    background: none;
    color: var(--slate);
}
.header-nav .tab-link:hover { background: var(--surface-alt); color: var(--text-dark); }
.header-nav .tab-link.active { background: var(--surface-alt); color: var(--text-dark); border-left-color: var(--primary); }


.tabs { display: none !important; }

/* 3. Main structural elements & cards */
main { display: block; }
/* #createTabSection is one tab panel among several (the others are
   .tab-section); it keeps the width/padding the old bare <main> rule gave it. */
#createTabSection { max-width: 1050px; margin: 24px auto; padding: 0 16px 60px; }

/* Skip link — first focusable element, visually hidden until focused (2.4.1). */
.skip-link {
    position: absolute;
    left: 12px;
    top: 12px;
    z-index: 10001;
    background: var(--text-dark);
    color: var(--bg-light);
    padding: 10px 16px;
    border-radius: var(--radius-control);
    font-weight: 700;
    text-decoration: none;
    transform: translateY(-160%);
    transition: transform 0.15s;
}
.skip-link:focus { transform: translateY(0); }

/* Screen-reader-only: in the a11y tree, off-screen visually. */
.visually-hidden {
    position: absolute !important;
    width: 1px; height: 1px;
    margin: -1px; padding: 0; border: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}
/* main gets no focus outline of its own when focused programmatically. */
main:focus { outline: none; }
.card { background: var(--surface); border: 1px solid var(--border-soft); border-radius: var(--radius-card); padding: 20px; margin-bottom: 18px; box-shadow: var(--shadow-card); }
h2 { font-size: 19px; margin: 0 0 12px; }
.hint { color: var(--text-muted); font-size: 14px; line-height: 1.5; }
/* A .hint sitting on a Soft-Grey fill: Muted is 4.45:1 there (under AA) —
   bump to Charcoal (7.3:1). Same technique as .fields > [style*="span 2"]. */
.hint[style*="surface-alt"] { color: var(--slate); }
.hidden { display: none !important; }
/* Must stay !important — the machine-readable <article data-*-schema> blocks
   the browser-extension reads are kept in the DOM via [hidden]. */
[hidden] { display: none !important; }
.section-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 15px; }
.pill { background: var(--surface-2); padding: 5px 10px; border-radius: var(--radius-pill); font-size: 13px; white-space: nowrap; }

/* New Item wizard (components/section_create.php + js/create.js). Three
   progressive-disclosure steps in one card — a locked step is dimmed but
   still clickable, an open step shows its body, the chevron flips. */
.wizard-step + .wizard-step { border-top: 1px solid var(--border-soft); }
.wizard-step-head {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 16px 2px;
    background: none;
    border: 0;
    cursor: pointer;
    text-align: left;
    font-size: 17px;
    font-weight: 700;
    color: var(--text-dark);
}
.wizard-step-num {
    flex: none;
    width: 26px;
    height: 26px;
    border-radius: var(--radius-pill);
    background: var(--surface-alt);
    color: var(--slate);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    font-weight: 700;
}
.wizard-step.is-open > .wizard-step-head .wizard-step-num { background: var(--primary); color: var(--bg-light); }
.wizard-step-title { flex: 1; }
.wizard-step-badge { flex: none; font-weight: 700; }
.wizard-step-chevron { flex: none; font-size: 12px; color: var(--text-muted); transition: transform 0.15s; }
.wizard-step.is-open > .wizard-step-head .wizard-step-chevron { transform: rotate(180deg); }
.wizard-step.is-locked > .wizard-step-head { opacity: 0.55; }
.wizard-step:not(.is-open) > .wizard-step-body { display: none; }
.wizard-step-body { padding: 0 2px 20px; }
@media (min-width: 560px) { .wizard-step-body { padding-left: 38px; } }

/* Step 3 summary chips — "8 photos", "1 issue noted", "Depop enabled". */
.wizard-summary { display: flex; flex-wrap: wrap; gap: 8px; margin: 2px 0 14px; }
.wizard-summary span {
    background: var(--surface-alt);
    color: var(--slate);
    border-radius: var(--radius-pill);
    padding: 5px 12px;
    font-size: 13px;
    font-weight: 600;
}

/* Low-confidence AI-mapped field flagged for manual review (api/listing-analysis.php). */
.ai-review-banner { margin-top: 8px; background: var(--warn-bg); border: 1px solid var(--warn-border); border-radius: var(--radius-panel); padding: 10px 12px; }
.ai-review-banner-text { color: var(--warn-amber); font-size: 13px; font-weight: 700; margin-bottom: 8px; }
.ai-review-candidates { display: flex; flex-wrap: wrap; gap: 6px; }
.ai-review-candidates:empty { margin-bottom: 0; }
.ai-review-candidate-btn { width: auto; background: var(--surface); border: 1px solid var(--warn-border); color: var(--warn-amber); border-radius: var(--radius-pill); padding: 5px 12px; font-size: 12px; font-weight: 600; cursor: pointer; }
.ai-review-candidate-btn:hover { background: var(--warn-bg); }
/* "✓ Looks right" — confirm a flagged field without re-selecting it. */
.ai-review-confirm-btn { width: auto; margin-top: 8px; background: var(--surface); border: 1px solid var(--warn-border); color: var(--warn-amber); border-radius: var(--radius-pill); padding: 5px 14px; font-size: 12px; font-weight: 700; cursor: pointer; }
.ai-review-confirm-btn:hover { background: var(--warn-bg); }

/* REQUIRES_INTERVENTION variant — field left blank, human must set it. Red, not amber. */
.ai-review-banner.intervention { background: var(--danger-bg); border-color: var(--danger-border); }
.ai-review-banner.intervention .ai-review-banner-text { color: var(--danger-red); }

/* Stage 2 — fact review decision queue (api/canonical-product.php's
   canonical_fact_decision_queue()). One card per outstanding decision,
   built from the SAME amber/red review-banner language as the Vinted/eBay
   mapping-review chips above — never a visually separate "AI interface".
   Amber = needs_review (a decision worth making); red ("mandatory") =
   Stage 3 genuinely cannot proceed without this one — the two are also
   distinguished by wording (the kind label + prompt text), never colour
   alone. */
.fact-review-card { border: 1px solid var(--warn-border); background: var(--warn-bg); border-radius: var(--radius-panel); padding: 14px 16px; margin-bottom: 12px; }
.fact-review-card:last-child { margin-bottom: 0; }
.fact-review-card.mandatory { border-color: var(--danger-border); background: var(--danger-bg); }
.fact-review-card-kind { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--warn-amber); margin: 0 0 4px; }
.fact-review-card.mandatory .fact-review-card-kind { color: var(--danger-red); }
.fact-review-card-label { font-size: 15px; font-weight: 700; margin: 0 0 4px; }
.fact-review-card-prompt { font-size: 14px; margin: 0 0 10px; }
.fact-review-conflict-values { display: flex; flex-direction: column; gap: 2px; font-size: 13px; margin: 0 0 10px; }
.fact-review-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.fact-review-card.mandatory .ai-review-candidate-btn,
.fact-review-card.mandatory .ai-review-confirm-btn { border-color: var(--danger-border); color: var(--danger-red); }
.fact-review-card.mandatory .ai-review-candidate-btn:hover,
.fact-review-card.mandatory .ai-review-confirm-btn:hover { background: var(--danger-bg); }
.fact-review-unknown-btn { width: auto; background: none; border: 0; color: var(--text-muted); font-size: 12px; font-weight: 600; text-decoration: underline; cursor: pointer; padding: 5px 4px; }
.fact-review-unknown-btn:hover { color: var(--slate); }
.fact-review-text-input { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.fact-review-text-input input { flex: 1 1 220px; }
.fact-review-reason { margin-top: 8px; }
.fact-review-reason summary { cursor: pointer; color: var(--text-muted); font-weight: 600; font-size: 12px; list-style: none; }
.fact-review-reason summary::-webkit-details-marker { display: none; }
.fact-review-reason p { font-size: 13px; margin: 6px 0 0; }
.fact-review-error { color: var(--danger-red); font-size: 12px; font-weight: 700; margin-top: 8px; }
.fact-review-settled-row { display: flex; justify-content: space-between; gap: 12px; padding: 7px 0; border-bottom: 1px solid var(--border-soft); font-size: 13px; }
.fact-review-settled-row:last-child { border-bottom: 0; }
.fact-review-settled-row .fact-review-settled-label { color: var(--text-muted); }
.fact-review-all-clear { display: flex; align-items: center; gap: 8px; font-weight: 700; color: var(--slate); }
/* Stage 4 (mapping review) — same card language as Stage 2 above, plus one
   small marketplace badge (js/mapping-review.js) so a mixed Vinted/eBay/
   Depop queue stays scannable. */
.mapping-review-market { display: inline-block; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: var(--text-muted); border: 1px solid var(--border-soft); border-radius: var(--radius-pill); padding: 1px 8px; margin-right: 6px; vertical-align: middle; }
.fact-review-card.mandatory .mapping-review-market { color: var(--danger-red); border-color: var(--danger-border); }

.pagination-bar { display: flex; align-items: center; justify-content: center; gap: 15px; margin-top: 16px; }

/* 4. Form components & buttons */
input, textarea, select {
    width: 100%;
    padding: 11px 12px;
    border: 1px solid var(--slate);
    border-radius: var(--radius-control);
    font: inherit;
    background: var(--surface);
    color: var(--text-dark);
}
input:focus, textarea:focus, select:focus { border-color: var(--primary); }
textarea { resize: vertical; }

/* Constrained WYSIWYG editor (js/rich-text.js) — the eBay listing
   description. The editable area is styled like the final listing so it
   doubles as the preview. */
.rich-text { border: 1px solid var(--slate); border-radius: var(--radius-control); background: var(--surface); overflow: hidden; }
.rich-text-bar { display: flex; flex-wrap: wrap; gap: 4px; padding: 6px; background: var(--surface-alt); border-bottom: 1px solid var(--border-soft); }
.rich-text-btn {
    width: auto; padding: 4px 9px; font-size: 12px; font-weight: 650; line-height: 1.4;
    color: var(--text-dark); background: var(--ivory); border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm); cursor: pointer;
}
.rich-text-btn:hover { background: var(--surface-2); }
.rich-text-btn:disabled { opacity: 0.5; cursor: not-allowed; }
.rich-text-area {
    min-height: 180px; max-height: 460px; overflow-y: auto; padding: 12px 14px;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    font-size: 14px; line-height: 1.55; color: var(--text-dark); background: var(--surface);
}
.rich-text-area:focus { outline: none; }
.rich-text:focus-within { border-color: var(--primary); }
.rich-text-area.is-disabled { background: var(--surface-2); color: var(--text-muted); }
.rich-text-area > :first-child { margin-top: 0; }
.rich-text-area > :last-child { margin-bottom: 0; }
.rich-text-area h3 { font-size: 15px; margin: 14px 0 6px; }
.rich-text-area h4 { font-size: 13px; margin: 12px 0 4px; }
.rich-text-area p { margin: 0 0 10px; }
.rich-text-area ul, .rich-text-area ol { margin: 0 0 10px; padding-left: 22px; }
.rich-text-area a { color: var(--primary); }
/* display:grid (not block) — a block label lets the width:100% input share an
   inline formatting context with its own label text; on some devices that
   squeezed number fields 2-up (the "Cost Price" mobile bug). See CHANGELOG. */
label { display: grid; font-weight: 700; margin: 10px 0; }
label input, label textarea, label select { margin-top: 5px; font-weight: 400; }

button { font: inherit; }
.primary, .secondary, .danger { border: 2px solid transparent; border-radius: var(--radius-control); padding: 11px 16px; font-weight: 750; cursor: pointer; transition: 0.15s; }
/* PRIMARY = Action Coral. Green (--green-success) is reserved for
   success/confirmation text + .tag-ready, never a brand button. */
.primary { background: var(--btn-primary-bg); color: var(--btn-primary-text); }
.primary:hover { background: var(--btn-primary-hover); }
.primary:active { background: var(--btn-primary-active); }
.primary:disabled { opacity: 0.45; cursor: not-allowed; }
.secondary { background: var(--surface); color: var(--text-dark); border-color: var(--border-strong); border-width: 1px; }
.secondary:hover { background: var(--surface-alt); }
.secondary:disabled { opacity: 0.45; }
/* Plain text-styled button — a low-emphasis inline action ("skip", "dismiss")
   that reads as a link, not a control. Used by the onboarding wizard and the
   New Item first-visit tip. */
.link-button {
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    color: var(--btn-primary-bg);
    font-weight: 600;
    cursor: pointer;
    text-decoration: underline;
}
.link-button:hover { color: var(--btn-primary-hover); }

/* First-run tip above the New Item wizard (components/section_create.php,
   js/create.js initFirstRunTip()). Dismissible, remembered per browser. */
.first-run-tip {
    display: flex;
    gap: 12px;
    align-items: flex-start;
    background: var(--surface-alt);
    border-left: 3px solid var(--peach);
    border-radius: var(--radius-panel);
    padding: 14px 16px;
    margin-bottom: 16px;
}
.first-run-tip-body { flex: 1; min-width: 0; }
.first-run-tip-body p { margin: 0 0 8px; line-height: 1.55; color: var(--text-dark); }
.first-run-tip-body p:last-child { margin-bottom: 0; }
.first-run-tip-head { display: flex; align-items: center; gap: 8px; font-size: 15px; }
.first-run-tip-head .re-icon { width: 1.2em; height: 1.2em; margin-right: 0; color: var(--icon-accent); }
/* Action Coral — AA on --surface-alt in both themes (see brand guide). */
.first-run-tip-kicker { color: var(--btn-primary-bg); font-weight: 600; }
.first-run-tip-kicker strong { color: var(--btn-primary-bg); font-weight: 800; }
.first-run-tip-dismiss { flex: none; }
/* Marketplace-tinted action button: white surface + Ink text (AAA) + a
   marketplace-coloured left stripe as the identity cue (brand guide §16). */
.btn-mkt {
    background: var(--surface);
    color: var(--text-dark);
    border: 1px solid var(--border-strong);
    border-left: 4px solid var(--mkt-accent, var(--slate));
    border-radius: var(--radius-control);
    padding: 11px 16px;
    font-weight: 700;
    cursor: pointer;
    transition: 0.15s;
}
.btn-mkt:hover { background: var(--surface-alt); }
.btn-mkt:disabled { opacity: 0.45; cursor: not-allowed; }
.mkt-vinted { --mkt-accent: var(--mkt-vinted); }
.mkt-ebay   { --mkt-accent: var(--mkt-ebay); }
.mkt-depop  { --mkt-accent: var(--mkt-depop); }
.mkt-causee { --mkt-accent: var(--mkt-causee); }
/* Destructive actions — defined, not yet adopted by any markup. */
.danger { background: var(--danger-bg); color: var(--danger-red); border-color: var(--danger-border); }
.danger:hover { filter: brightness(0.96); }
.big { min-height: 48px; }

/* 5. Interactive widgets & photo controls */
.photo-buttons { display: flex; gap: 10px; flex-wrap: wrap; margin: 14px 0; }
.photo-buttons button { flex: 1; min-width: 170px; }
.photo-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(184px, 1fr)); gap: 16px; margin: 16px 0; }
.photo-card { min-width: 0; }
.photo-card img { display: block; width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: var(--radius-control); background: var(--surface-2); cursor: zoom-in; }

/* Step-3 "which photos to send to the AI" strip (js/create.js
   renderAnalysePhotoPicker) — small checkable thumbs, checkbox top-left. */
.analyse-photo-strip { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 8px; }
.analyse-photo-strip label { position: relative; width: 66px; height: 66px; cursor: pointer; }
.analyse-photo-strip img { width: 100%; height: 100%; object-fit: cover; border-radius: var(--radius-sm); border: 1px solid var(--border-strong); background: var(--surface-2); }
.analyse-photo-strip input { position: absolute; top: 4px; left: 4px; margin: 0; }
.analyse-photo-strip label:has(input:not(:checked)) img { opacity: 0.35; }

/* One row under each preview thumbnail: move left | download | delete |
   move right (js/create.js renderPreviews). 44px min target + 8px gaps
   clears WCAG 2.5.5 (AAA); the move buttons carry the brand blush/peach,
   the file actions are neutral outlines with no fill. */
.photo-actions { display: flex; gap: 8px; margin-top: 8px; }
.photo-actions button {
    flex: 1 1 0;
    min-width: 40px;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-control);
    border: 1px solid var(--border-strong);
    background: var(--surface);
    color: var(--text-dark);
    cursor: pointer;
}
.photo-actions button:hover:not(:disabled) { background: var(--surface-alt); }
.photo-actions button:disabled { opacity: 0.35; cursor: default; }
.photo-actions .photo-action-move { border-color: var(--peach); background: var(--ivory); color: var(--ink); }
.photo-actions .photo-action-move:hover:not(:disabled) { background: var(--blush); }
.photo-actions .photo-action-delete:hover:not(:disabled) { border-color: var(--danger-red); color: var(--danger-red); }

/* Material checklist on the "Item details" step (js/canonical-intake.js
   renderCtxMaterials) — 2 columns on mobile, 4 on desktop; the checkbox
   sits left of each label via .radio-label. */
.intake-material-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 14px; margin: 2px 0 4px; }
.intake-material-grid .radio-label { font-size: 13px; gap: 8px; }
@media (min-width: 640px) { .intake-material-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.model-image { display: block; max-width: 600px; width: 100%; margin-top: 16px; border-radius: var(--radius-panel); }
.model-actions, .actions, .photo-footer { display: flex; align-items: center; justify-content: space-between; gap: 12px; }

/* Mobile-first: one input per row; multi-column only opts in at desktop
   width (media queries near the bottom of this file). */
.fields { display: grid; grid-template-columns: 1fr; gap: 4px 15px; }
.price-grid { display: grid; grid-template-columns: 1fr; gap: 10px; }
/* Intentionally empty at base — the 5-tile layout is desktop-only (below). */
.price-grid-5 { }
.checklist { display: grid; grid-template-columns: 1fr; gap: 5px 15px; margin: 15px 0; }
.checklist label { font-weight: 400; }
.checklist input { width: auto; margin-right: 8px; }
.success { color: var(--green-success); font-weight: 650; }

/* 6. Tabulated views, lists & tables */
.inventory-item {
    background: var(--surface);
    border: 1px solid var(--border-soft);
    padding: 20px;
    border-radius: var(--radius-card);
    display: flex;
    flex-direction: column;
    gap: 12px;
    box-shadow: var(--shadow-card);
}
.inventory-item h3 { margin: 0 0 5px; font-size: 19px; }
.inventory-meta { display: flex; gap: 15px; font-size: 13px; color: var(--text-muted); flex-wrap: wrap; }
/* "⏸️ Not Yet" hold flag (js/drafts.js). */
.draft-on-hold { border-left: 4px solid var(--warn-amber); background: var(--warn-bg); }
/* "🌐 Vinted draft ready" flag — Vinted listing filled out (not submitted). */
.draft-vinted-prepped { border-left: 4px solid var(--ebay-blue); }

.list-actions { display: flex; align-items: center; gap: 15px; flex-wrap: wrap; margin-top: 10px; padding-top: 15px; border-top: 1px dashed var(--border-color); }
.list-actions label { margin: 0; font-weight: 700; font-size: 14px; display: inline-flex; align-items: center; gap: 8px; }
.list-actions input { max-width: 120px; padding: 8px; border: 1px solid var(--border-color); border-radius: var(--radius-control); }
.list-actions button { border: 0; border-radius: var(--radius-control); padding: 9px 16px; font-size: 14px; font-weight: bold; cursor: pointer; }

.stacked-list { display: flex; flex-direction: column; gap: 15px; }

/* To List "Price Recommendations" + AI rationale panel (js/drafts.js).
   White surface, a thick Peach left rule as the brand highlight (not a
   grey fill), Charcoal body text — every line clears AAA. The rationale
   was 11px #888 italic on #fafafa (3.4:1, AA fail). */
.draft-price-block {
    flex: 1 1 220px;
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-left: 5px solid var(--peach);
    border-radius: var(--radius-panel);
    padding: 12px 14px;
    font-size: 13.5px;
    line-height: 1.55;
    color: var(--slate);
}
.draft-price-reason {
    margin-top: 8px;
    font-size: 13px;
    font-style: italic;
    line-height: 1.55;
    color: var(--slate);
}

/* Draft card field groups — per-platform title/description as a readonly,
   copyable textarea + an explicit Copy button. */
.draft-field-group { background: var(--surface-alt); border: 1px solid var(--border-soft); border-radius: var(--radius-panel); padding: 12px; display: flex; flex-direction: column; gap: 10px; }
/* Charcoal (--slate), not --text-muted: on --surface-alt, Muted is 4.45:1
   (just under AA). Same reason wherever this note recurs below. */
.draft-field-group-label { font-size: 11px; font-weight: 800; letter-spacing: 0.02em; text-transform: uppercase; color: var(--slate); }
.draft-field-row-head { display: flex; justify-content: space-between; align-items: center; gap: 8px; margin-bottom: 4px; }
.draft-field-row-head span { font-size: 12px; font-weight: 700; color: var(--text-dark); }
.draft-field-value { width: 100%; resize: vertical; min-height: 2.4em; border: 1px solid var(--border-color); border-radius: var(--radius-control); padding: 8px 10px; font: inherit; font-size: 13px; color: var(--text-dark); background: var(--surface); }
.draft-field-copy-btn { border: 1px solid var(--border-color); border-radius: var(--radius-control); padding: 5px 10px; font-size: 11px; font-weight: 700; cursor: pointer; background: var(--surface); }
.draft-field-copy-btn:hover { background: var(--surface-2); }

/* Shared To List / Active photo block (js/listing-photos.js): visible
   thumbnail + a clip()-hidden full-size gallery the Vinted extension reads. */
.listing-photos { position: relative; }
.listing-photo-main { width: 100px; height: 100px; object-fit: cover; border-radius: var(--radius-control); border: 1px solid var(--border-color); cursor: zoom-in; display: block; }
.listing-photo-empty { width: 100px; height: 100px; background: var(--surface-alt); border-radius: var(--radius-control); display: flex; align-items: center; justify-content: center; font-size: 12px; color: var(--slate); }
.listing-photo-gallery {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0; border: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
}
/* "🖼️ All N" toggle un-clips the gallery into a visible grid. */
.listing-photo-gallery.is-revealed {
    position: static;
    width: auto; height: auto;
    margin: 8px 0 0; padding: 0;
    overflow: visible;
    clip: auto;
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}
.listing-photos-toggle {
    display: inline-block;
    margin-top: 6px;
    padding: 4px 10px;
    font-size: 11px;
    font-weight: 700;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    background: var(--surface);
    color: var(--slate);
    cursor: pointer;
    white-space: nowrap;
}
.listing-photos-toggle:hover { background: var(--surface-alt); }
.draft-photo-item { display: flex; flex-direction: column; align-items: center; gap: 5px; }
.draft-photo-item img { width: 100px; height: 100px; object-fit: cover; border-radius: var(--radius-control); }
.draft-photo-actions { display: flex; gap: 4px; }
.draft-photo-actions button { border: 0; border-radius: var(--radius-sm); padding: 3px 8px; font-size: 11px; cursor: pointer; background: var(--border-soft); }
.draft-photo-actions button:hover { background: var(--border-color); }
/* Bigger, clearer buttons once the gallery is actually on screen. */
.listing-photo-gallery.is-revealed .draft-photo-actions button { font-size: 15px; padding: 6px 12px; }

/* Sourcing-trip "this trip so far" grid — fixed column count + ~half-size
   thumbs (a real haul is 35-100+ items). 3 cols phone → 5 wide screen. */
.trip-capture-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px 6px; justify-items: center; }
@media (min-width: 480px) { .trip-capture-grid { grid-template-columns: repeat(4, 1fr); } }
@media (min-width: 700px) { .trip-capture-grid { grid-template-columns: repeat(5, 1fr); } }
.trip-capture-tile { display: flex; flex-direction: column; align-items: center; gap: 4px; width: 100%; cursor: pointer; }
.trip-capture-tile img { width: 75px; height: 75px; object-fit: cover; border-radius: var(--radius-sm); border: 1px solid var(--border-color); cursor: zoom-in; }
.trip-capture-placeholder { width: 75px; height: 75px; display: flex; align-items: center; justify-content: center; background: var(--danger-bg); border-radius: var(--radius-sm); font-size: 22px; }
.trip-capture-label { font-size: 10px; text-align: center; font-weight: 700; line-height: 1.25; word-break: break-word; }
.trip-capture-tile.tile-analysing img { opacity: 0.45; }
.trip-capture-status { font-size: 11px; line-height: 1; }

.table-container { width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; margin-top: 15px; border-radius: var(--radius-card); border: 1px solid var(--border-soft); }
table { width: 100%; border-collapse: collapse; text-align: left; background: var(--surface); font-size: 14px; min-width: 800px; }
th, td { padding: 12px 16px; border-bottom: 1px solid var(--border-soft); vertical-align: middle; }
th { background: var(--surface-alt); font-weight: 700; color: var(--slate); }
tr:last-child td { border-bottom: 0; }

.copy-btn-compact {
    background: var(--surface);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-control);
    padding: 6px 12px;
    font-size: 12px;
    font-weight: 700;
    cursor: pointer;
    transition: 0.15s;
    white-space: nowrap;
    margin-right: 4px;
}
.copy-btn-compact:hover { background: var(--surface-2); }

/* 7. Shared composite patterns — extracted from inline style="..." repeated 3+ times. */
.tab-section { max-width: 1050px; margin: 24px auto; padding: 0 16px; }

/* Fixed full-viewport modal shell. */
.modal-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: var(--overlay);
    z-index: 9999;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 15px;
}
.modal-box { width: 100%; max-width: 500px; margin: 0; position: relative; }
.modal-close {
    position: absolute;
    top: 12px;
    right: 12px;
    /* 2.5.8 (AA) — was font-size:20px with no padding, a ~20px hit area. */
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: var(--radius-control);
    background: none;
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
}

/* BI dashboard stat cards (section_intel.php). */
.stat-tile { margin: 0; background: var(--surface-alt); border: 1px solid var(--border-soft); }
.stat-tile-value { margin: 5px 0 0; font-size: 24px; }
/* Charcoal, not Muted — see .draft-field-group-label. */
.stat-tile .hint { color: var(--slate); }

/* "Total value"-style header pill — generic app chrome, app tint not a marketplace's. */
.value-badge { background: var(--surface-alt); color: var(--primary); font-weight: bold; font-size: 14px; padding: 6px 12px; margin: 0; border-radius: var(--radius-pill); }

/* Checkbox/radio label pairs — one shared class: 28px box, 10px gap, whole row clickable. */
.radio-label { font-weight: 500; margin: 0; display: flex; align-items: center; gap: 10px; cursor: pointer; line-height: 1.3; }
.radio-input { width: auto; margin: 0; }

/* Radio/checkbox GROUP — real <fieldset>/<legend> for grouping semantics
   (1.3.1), reset to look exactly like the plain heading + rows it replaced. */
.group-fieldset { border: 0; margin: 0; padding: 0; min-inline-size: 0; }
.group-fieldset > legend { display: block; float: none; width: auto; padding: 0; margin-bottom: 6px; font-weight: 650; font-size: inherit; line-height: 1.3; }

/* Default for ANY checkbox/radio: appearance:none + hand-drawn tick/dot so it's
   a white box with a coloured mark, not a filled box. Sized in em so the
   "compact" exceptions below scale box+border+mark with one font-size. */
input[type="checkbox"], input[type="radio"] {
    appearance: none;
    -webkit-appearance: none;
    width: 1.8em;
    height: 1.8em;
    min-width: 1.8em;
    font-size: 16px;
    margin: 0;
    border: 0.15em solid var(--slate);
    border-radius: 0.25em;
    background: var(--surface);
    cursor: pointer;
    flex-shrink: 0;
    position: relative;
    vertical-align: middle;
}
input[type="radio"] { border-radius: 50%; }
/* Tick/dot via background-image, centred by background-position (no manual offsets). */
input[type="checkbox"], input[type="radio"] {
    background-repeat: no-repeat;
    background-position: center;
    background-size: 65% 65%;
}
input[type="checkbox"]:checked, input[type="radio"]:checked { border-color: var(--btn-primary-bg); }
input[type="checkbox"]:checked {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239C5B4F' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='4 13 9.5 18.5 20 6'/%3E%3C/svg%3E");
}
/* radial-gradient dot (self-centring, and accepts var() unlike a url() data-URI).
   Needs a real colour stop THEN transparent, or it paints the whole box square. */
input[type="radio"]:checked {
    background-image: radial-gradient(circle closest-side, var(--btn-primary-bg) 0%, var(--btn-primary-bg) 97%, transparent 100%);
}
/* Compact exception — the select-mode bundle row checkbox (~20px box). */
.bundle-checkbox { font-size: 11px; }

/* "£x.xx suggested" hint shown next to an unticked "Listed on <Platform>"
   checkbox in the cross-post form (js/listing-price-actions.js) — plain
   Charcoal, no background/border. Replaced the separate Depop
   intended-price panel (2026-09-07). */
.list-platform-suggested {
    font-size: 13px;
    color: var(--slate);
    white-space: nowrap;
}

/* Tap-to-toggle condition/flaw chips (js/condition-tags.js). Fixed-palette
   pairing (Ivory / Blush ground, Ink text) so it renders identically and
   accessibly in both themes — same approach as .chip-active, .tag-live and
   the photo move-buttons. Ink-on-Ivory ~14:1, Ink-on-Blush ~10:1 (AAA);
   the --border-strong edge clears 1.4.11 at ~3:1. */
.chip-row { display: flex; flex-wrap: wrap; gap: 8px; margin: 6px 0 8px; }
.chip {
    border: 1px solid var(--border-strong);
    background: var(--ivory);
    color: var(--ink);
    border-radius: var(--radius-control);
    padding: 7px 13px;
    min-height: 34px;
    font-size: 12px;
    font-weight: 650;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s;
}
.chip:hover { border-color: var(--peach); }
.chip-active { background: var(--blush); border-color: var(--peach); }
.chip-active:hover { background: var(--peach); border-color: var(--peach); }

/* Measurements step (js/measurements.js) — diagram | label | cm (editable)
   | in (read-only calculated display, cm-only canonical editor, revised
   2026-10-05). */
.meas-row { display: grid; grid-template-columns: 40px 1fr 84px 84px; align-items: center; gap: 10px; padding: 6px 0; border-bottom: 1px solid var(--border-soft); }
.meas-row:last-child { border-bottom: 0; }
/* The brand's own measurement illustrations (images/measure/<theme>/<key>.png),
   one <img> per theme — CSS shows the one matching the viewer, so a live
   theme switch needs no re-render. js/measurement-icons.js. */
.meas-icon { width: 40px; height: 40px; flex: none; display: flex; align-items: center; justify-content: center; }
.meas-icon img, .meas-icon .meas-icon-fallback { max-width: 100%; max-height: 100%; display: block; }
.meas-icon .meas-icon-dark { display: none; }
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .meas-icon .meas-icon-light { display: none; }
    :root:not([data-theme="light"]) .meas-icon .meas-icon-dark { display: block; }
}
:root[data-theme="dark"] .meas-icon .meas-icon-light { display: none; }
:root[data-theme="dark"] .meas-icon .meas-icon-dark { display: block; }
:root[data-theme="light"] .meas-icon .meas-icon-light { display: block; }
:root[data-theme="light"] .meas-icon .meas-icon-dark { display: none; }
.meas-label { font-weight: 600; font-size: 13px; }
.meas-unit { display: flex; align-items: center; gap: 5px; font-size: 12px; color: var(--text-muted); margin: 0; }
.meas-unit input { width: 100%; }
/* The inch equivalent is a plain calculated display, not a control — no
   input border/background, so it reads visually as "shown", not "editable". */
.meas-in-value { display: inline-block; min-width: 0; }
@media (max-width: 520px) {
    .meas-row { grid-template-columns: 34px 1fr; grid-template-areas: "icon label" "icon cm" "icon in"; row-gap: 4px; }
    .meas-icon { grid-area: icon; align-self: start; width: 34px; height: 34px; }
    .meas-label { grid-area: label; }
    .meas-unit:nth-of-type(1) { grid-area: cm; }
    /* Explicit class selector, not a sibling position — the inch element
       is a <span>, not a <label> like the cm one, so ":nth-of-type(2)"
       (a leftover from when both were <label>s) no longer reliably tracks
       it; this targets it directly regardless of tag/position. */
    .meas-in { grid-area: in; }
}

/* AI-overwrite guard (js/canonical-intake.js). A field the seller typed
   gets a labelled "you set this" pill (with a title tooltip); where the AI
   disagrees, a one-line suggest chip in the amber review-banner style.
   Neutral grey, not --blush (2026-10 provenance-styling fix) — --blush
   sits in the same warm coral/pink hue family as --peach and --danger-*,
   which read as error-like for a badge that means "confirmed, nothing to
   do" rather than "needs attention". Same --surface-alt/--slate pairing
   already used for the ARCHIVED pill (js/search.js) and .tag-draft — also
   deliberately NOT the amber/cream .ai-suggest tokens, since a badged
   field can show BOTH this badge and an .ai-suggest chip at once (seller
   confirmed a value, AI still disagrees) and the two need to stay visually
   distinct in that case. */
.prov-badge {
    display: inline-block;
    margin: 0 6px;
    padding: 1px 7px;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    line-height: 1.5;
    color: var(--slate);
    background: var(--surface-alt);
    border-radius: var(--radius-sm);
    vertical-align: middle;
    cursor: help;
}
.ai-suggest {
    margin: 5px 0 2px;
    padding: 5px 9px;
    font-size: 12px;
    font-weight: 500;
    background: var(--warn-bg);
    border: 1px solid var(--warn-border);
    border-radius: var(--radius-control);
    color: var(--warn-amber);
    display: flex;
    align-items: center;
    gap: 6px;
}
.ai-suggest .re-icon { width: 15px; height: 15px; flex: none; }
.ai-suggest .link-button { font-weight: 700; }
.fields > .ai-suggest { grid-column: 1 / -1; }

/* In-page live camera (js/live-camera.js) — full-bleed over .modal-overlay. */
.live-camera-overlay { background: #000; z-index: 10000; padding: 0; }
.live-camera-box { position: relative; width: 100%; height: 100%; display: flex; flex-direction: column; }
.live-camera-video { flex: 1; width: 100%; min-height: 0; object-fit: cover; background: #000; }
.live-camera-controls { display: flex; align-items: center; justify-content: space-between; gap: 15px; padding: 18px 20px calc(18px + env(safe-area-inset-bottom)); background: rgba(0,0,0,0.65); }
.live-camera-shutter { width: 66px; height: 66px; min-width: 66px; border-radius: 50%; border: 4px solid #fff; background: #fff; font-size: 24px; cursor: pointer; }
.live-camera-close, .live-camera-torch { background: rgba(255,255,255,0.15); color: #fff; border: 0; border-radius: var(--radius-pill); padding: 10px 16px; font-size: 13px; font-weight: 700; cursor: pointer; white-space: nowrap; }
.live-camera-torch.chip-active { background: #ffd23f; color: #111; }
.live-camera-spacer { width: 76px; }

/* Bundle multi-select checkboxes (js/bundle-tools.js) — shown only in select mode. */
.bundle-checkbox { display: none; margin-right: 10px; }
.bundle-select-mode .bundle-checkbox { display: inline-block; }
/* Drafts' re-analyse/re-price bar (js/drafts.js renderBulkReanalyseBar) is
   its own set of top-of-list actions — hidden while a bulk selection is in
   progress so "Move to Not Yet" reads as THE action, not one of several. */
.bundle-select-mode #bulkReanalyseBar { display: none; }


/* Accordion header button — sits INSIDE the card's <h2> so the heading
   stays in the a11y tree; a native <button> gives keyboard + role for free.
   Styled to be visually identical to the plain heading text it replaced. */
.toggle-trigger {
    cursor: pointer;
    user-select: none;
    width: 100%;
    font: inherit;
    color: inherit;
    letter-spacing: inherit;
    text-align: left;
    background: none;
    border: 0;
    padding: 0;
    display: flex;
    align-items: center;
    gap: 8px;
}
/* Platform-card / section headers carry the same glyph Settings uses. The
   flex `gap` above spaces it, so kill the icon's own trailing margin. */
.toggle-trigger > .re-icon,
.toggle-trigger > #vintedCardIcon > .re-icon { margin-right: 0; width: 1.15em; height: 1.15em; }
#vintedCardIcon { align-items: center; }

/* Retail Product Lookup — "Identify your item" (components/section_create.php
   + js/retail-lookup.js). */
.retail-lookup { border: 1px solid var(--border-soft); border-radius: var(--radius-panel); padding: 14px 16px; background: var(--surface-alt); }
.retail-found { border: 1px solid var(--border-strong); background: var(--surface); border-radius: var(--radius-panel); padding: 12px 14px; }
/* credibility tint — high (retailer's own site) reads as a confident success;
   medium a neutral panel; low a caution the seller must eyeball. */
.retail-found-high { border-color: var(--green-success); background: var(--success-bg); }
.retail-found-low { border-color: var(--warn-border); background: var(--warn-bg); }
.retail-found-headrow { display: flex; gap: 8px; align-items: baseline; justify-content: space-between; flex-wrap: wrap; margin-bottom: 2px; }
.retail-found-heading { font-weight: 750; }
.retail-found-high .retail-found-heading { color: var(--green-success); }
.retail-cred-chip { font-size: 11px; font-weight: 700; letter-spacing: 0.02em; padding: 2px 8px; border-radius: 999px; white-space: nowrap; }
.retail-cred-chip.is-high { background: var(--green-success); color: #fff; }
.retail-cred-chip.is-medium { background: var(--surface-alt); color: var(--text-muted); border: 1px solid var(--border-strong); }
.retail-cred-chip.is-low { background: var(--warn-bg); color: var(--warn-amber); border: 1px solid var(--warn-border); }
.retail-source-host { font-size: 12px; color: var(--text-muted); margin-bottom: 4px; word-break: break-all; }
.retail-source-link { display: inline-block; margin-top: 8px; font-size: 13px; font-weight: 650; }
.retail-check-hint { margin: 10px 0 0; font-size: 12px; color: var(--text-muted); }
.retail-found-body { display: flex; gap: 12px; align-items: flex-start; }
.retail-found-img { flex: none; width: 76px; height: 76px; object-fit: cover; border-radius: 8px; border: 1px solid var(--border-soft); background: var(--surface-alt); }
.retail-found-main { min-width: 0; flex: 1; }
.retail-found-title { font-weight: 700; font-size: 15px; }
.retail-found-facts { margin: 8px 0 0; display: flex; flex-direction: column; gap: 4px; }
.retail-fact { display: flex; gap: 8px; font-size: 13px; }
.retail-fact dt { flex: none; width: 96px; color: var(--text-muted); font-weight: 650; margin: 0; }
.retail-fact dd { margin: 0; }
.retail-actions { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 12px; align-items: center; }
.retail-notfound { border: 1px solid var(--border-strong); border-radius: var(--radius-panel); padding: 12px 14px; background: var(--surface); }
.retail-others { margin: 4px 0 0; padding-left: 18px; font-size: 13px; display: flex; flex-direction: column; gap: 3px; }
.retail-used { margin: 0; font-weight: 650; color: var(--green-success); }

/* Per-platform edit cards (components/section_result.php + js/create.js
   renderPlatformCards()). A left accent stripe per marketplace, a
   review-flag summary + optional "Run analysis" button on the collapsed
   header. */
.platform-card { border-left: 4px solid var(--mkt-accent, var(--border-strong)); }
.platform-card-vinted { --mkt-accent: var(--mkt-vinted); }
.platform-card-ebay   { --mkt-accent: var(--mkt-ebay); }
.platform-card-depop  { --mkt-accent: var(--mkt-depop); }
.platform-card-causee { --mkt-accent: var(--mkt-causee); }
.platform-card-head { align-items: center; }
.platform-flag-summary { display: inline-flex; flex-wrap: wrap; gap: 6px; vertical-align: middle; }
.platform-flag-summary:empty { display: none; }
.platform-run-analysis { flex: none; white-space: nowrap; }
.platform-status-body { margin-top: 12px; }

/* Review-surfacing UX pass (2026-09-12) — the "Fix"/"Check" pill on a
   collapsed platform card header is a real <button>, not static text, so a
   flagged field is always one click from its own resolution mechanism (see
   navigateToMarketplaceField() in js/create.js). Same pill look as its
   .pill ancestor, just interactive. */
.platform-flag-chip { border: none; padding: 0; margin: 0 0 0 4px; font: inherit; color: inherit; background: transparent; cursor: pointer; text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 2px; }
.platform-flag-chip:hover, .platform-flag-chip:focus-visible { text-decoration-thickness: 2px; }

/* A field/control that is itself the subject of an open Stage 2/4 decision —
   same "amber = check, deep blush = blocked" language .retail-found-low
   already uses, applied directly to the control so the field, not just a
   nearby banner, is visibly the thing to fix. Cleared as soon as the
   decision resolves (renderPicklistReviewBanner() / applyEbayFields() etc). */
.field-needs-attention { border-color: var(--warn-border) !important; background: var(--warn-bg); }
.field-needs-attention.is-blocked { border-color: var(--danger-border) !important; background: var(--danger-bg); }

/* Temporary strong highlight applied by navigateToMarketplaceField() /
   focusMappingDecision() / focusFactDecision() the moment a "Fix"/"Check"
   link lands the user on the actual unresolved control or decision card —
   a few seconds only (removed by the calling JS), so the eye finds the
   right spot without a permanent second visual language on top of
   .field-needs-attention / .fact-review-card's own styling. */
.review-target-flash { outline: 3px solid var(--danger-red); outline-offset: 2px; }

/* Activity stream in the Current Status card. */
.activity-stream { list-style: none; margin: 6px 0 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.activity-stream li { font-size: 13px; line-height: 1.5; padding: 6px 10px; background: var(--surface-alt); border-radius: var(--radius-control); }
.activity-stream li.hint { background: none; padding: 2px 0; }
.activity-when { font-variant-numeric: tabular-nums; color: var(--text-muted); margin-right: 8px; }

/* 8. In-app modal PDF viewer */
#modalEnlargedPdfWrapper {
    width: 90%;
    height: 85%;
    overflow-x: auto;
    overflow-y: hidden;
    border-radius: var(--radius-panel);
    box-shadow: 0 4px 20px rgba(0,0,0,0.5);
    -webkit-overflow-scrolling: touch;
}
#modalEnlargedPdf {
    width: 100%;
    height: 100%;
    border: 0;
}

@media(max-width: 768px) {
    /* Zoom in on mobile to push the QR code space toward centre. */
    #modalEnlargedPdf { width: 175%; }
}

/* 9. Responsiveness & adaptive views */
@media(min-width: 769px) {
    header { flex-direction: row; align-items: center; justify-content: space-between; gap: 20px; }
    .header-top { width: auto; }
    .header-nav { width: auto; margin-top: 0; }

    .header-nav .tab-link { border-left: 0; border-bottom: 3px solid transparent; border-radius: 0; padding: 14px 12px; }
    .header-nav .tab-link.active { background: none; border-bottom-color: var(--primary); }
    .header-nav .tab-link:hover { background: none; color: var(--text-dark); }
}

@media(max-width: 768px) {
    #menuToggle { display: inline-flex; }
    .header-nav { display: none; flex-direction: column; gap: 4px; }
    .header-nav.open { display: flex; }
    .header-nav .tab-link { width: 100%; text-align: left; }

    #createTabSection { margin: 15px auto; padding: 0 10px 50px; }
    .card { padding: 16px; }
    .photo-footer, .model-actions, .actions { align-items: stretch; flex-direction: column; }
    .photo-footer .primary, .actions button, .model-actions button { width: 100%; }
}

/* Field grids opt UP into columns only at desktop width. .price-grid caps
   at 2-up (four short £ tiles read better as 2x2 than one cramped row). */
@media(min-width: 820px) {
    .fields, .checklist { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .price-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .price-grid-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }
}
@media(min-width: 1000px) {
    .price-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* Neutralise an inline `grid-column: span 2` on the 1-col mobile grid — it
   otherwise spawns a phantom 2nd track wide enough to overflow the viewport. */
.fields > [style*="span 2"] { grid-column: auto !important; }
@media(min-width: 820px) {
    .fields > [style*="span 2"] { grid-column: span 2 !important; }
}

/* Physical-item flaw row (js/canonical-intake.js) — mobile-first like every field grid. */
.pi-flaw-row { grid-template-columns: 1fr; gap: 6px; margin-bottom: 10px; }
@media(min-width: 820px) {
    .pi-flaw-row { grid-template-columns: 1fr 1fr 2fr auto; align-items: center; margin-bottom: 4px; }
}

/* "Listed on <Platform>?" row (js/listing-price-actions.js) — stacked on
   mobile; fixed-width fields (a price needs ~6 chars) side by side with room. */
.listing-actions-rows { display: flex; flex-direction: column; gap: 8px; flex: 1 1 220px; min-width: 0; }
.list-platform-row { display: flex; flex-direction: column; align-items: stretch; gap: 8px; }
/* Dotted rule between each platform group so eBay's 2nd line (its ID field)
   stays anchored to the eBay row above it. */
.list-platform-row + .list-platform-row { border-top: 1px dotted var(--slate); padding-top: 10px; }
.list-platform-price-label { display: flex; align-items: center; gap: 6px; }
.list-platform-price-input { width: 90px; flex: none; }
.list-platform-ebayid-input { width: 160px; max-width: 100%; flex: none; }
.list-platform-link-input { width: 100%; min-width: 180px; flex: 1 1 220px; }
@media(min-width: 560px) {
    .list-platform-row { flex-direction: row; align-items: center; flex-wrap: wrap; gap: 10px; }
}
/* Live-platform row extras (Active board): age + stale marker + View link. */
.list-platform-age { font-size: 12px; color: var(--text-muted); white-space: nowrap; }
.list-platform-age.is-stale { color: var(--danger-red); font-weight: 700; }
.list-platform-view { font-size: 12px; color: var(--info-text); white-space: nowrap; }

/* One field + one action button (Active board Sale Log / Relist rows). */
.field-with-action { display: flex; flex-direction: column; align-items: stretch; gap: 10px; }
.field-with-action label { margin: 0; flex: 1; }
@media(min-width: 560px) {
    .field-with-action { flex-direction: row; align-items: center; }
    .field-with-action > button { flex: none; }
}

/* Shared card layout — To List (js/drafts.js) + Active (js/active.js) render
   the same stacked structure via js/listing-card.js. */
.listing-card-body { display: flex; flex-direction: column; gap: 15px; }
.listing-card-head { display: flex; justify-content: space-between; align-items: flex-start; flex-wrap: wrap; gap: 10px; }
.listing-card-head h3 { margin: 0; font-size: 18px; display: flex; align-items: center; flex-wrap: wrap; gap: 4px; }
/* Photo + price-recommendations side by side; wraps below on a narrow phone. */
.listing-card-media { display: flex; flex-wrap: wrap; gap: 15px; align-items: flex-start; }

.active-sale-actions { flex-direction: column; gap: 10px; }
@media(min-width: 900px) {
    .active-sale-actions { flex-direction: row; align-items: flex-start; }
    .active-sale-actions > .field-with-action { flex: 1; }
}

/* 10. Status tags, expanders, tabs & banners */
/* Custom autocomplete dropdown (js/autocomplete.js). position:fixed with
   JS-computed left/top/width — an ancestor details.expander has
   overflow:hidden and would clip an absolutely-positioned panel. */
.autocomplete-panel {
    position: fixed;
    z-index: 3000;
    background: var(--surface);
    border: 1px solid var(--slate);
    border-radius: var(--radius-panel);
    max-height: 240px;
    overflow-y: auto;
    box-shadow: var(--shadow-pop);
}
.autocomplete-option { padding: 10px 12px; font-size: 14.5px; cursor: pointer; color: var(--text-dark); }
.autocomplete-option:hover, .autocomplete-option.active { background: var(--surface-alt); }

.btn-row { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }

.tag { display: inline-flex; align-items: center; gap: 6px; font-size: 11.5px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.03em; padding: 4px 11px; border-radius: var(--radius-pill); }
.tag-ready { background: var(--success-bg); color: var(--green-success); }
.tag-review { background: var(--warn-bg); color: var(--warn-amber); }
.tag-action { background: var(--danger-bg); color: var(--danger-red); }
.tag-live { background: var(--blush); color: var(--ink); }
.tag-sold { background: var(--slate); color: var(--bg-light); }

/* Small marketplace identity badge on cards — white pill, Ink text (AAA),
   marketplace-coloured border + left stripe. Replaces the pink-on-pink
   "Vinted" pill (2.9:1). */
.badge-mkt {
    display: inline-flex; align-items: center; gap: 4px;
    background: var(--surface); color: var(--text-dark);
    border: 1px solid var(--border-strong);
    border-left: 3px solid var(--mkt-accent, var(--slate));
    padding: 3px 10px; border-radius: var(--radius-pill);
    font-size: 11.5px; font-weight: 700;
}
/* Charcoal, not Muted — see .draft-field-group-label. */
.tag-draft { background: var(--surface-alt); color: var(--slate); }

/* Native <details> expander — keyboard + screen-reader friendly, no JS. */
details.expander { background: var(--surface); border: 1px solid var(--border-soft); border-radius: var(--radius-panel); overflow: hidden; }
details.expander + details.expander { margin-top: 10px; }
details.expander summary { list-style: none; cursor: pointer; padding: 14px 16px; font-weight: 700; font-size: 14px; display: flex; align-items: center; gap: 10px; color: var(--slate); }
details.expander summary::-webkit-details-marker { display: none; }
details.expander summary::marker { content: ""; }
/* NHS-style +/− circle at the row end (service-manual.nhs.uk/design-system/components/expander). */
details.expander summary::after {
    content: "+";
    margin-left: auto;
    width: 22px;
    height: 22px;
    min-width: 22px;
    border-radius: 50%;
    border: 2px solid var(--slate);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 15px;
    font-weight: 700;
    line-height: 1;
    color: var(--slate);
}
details.expander[open] summary::after { content: "−"; }
details.expander .expander-body { padding: 0 16px 16px; border-top: 1px solid var(--border-soft); padding-top: 14px; }
/* Charcoal, not Muted — see .draft-field-group-label. */
details.expander summary .count { background: var(--surface-alt); color: var(--slate); font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: var(--radius-pill); }

/* Shared tabs component — Drafts Ready/Not Yet, Postage Picking/Posting. */
.view-tabs { display: flex; gap: 2px; border-bottom: 2px solid var(--border-soft); }
.view-tabs button { background: none; border: 0; padding: 11px 16px; font-weight: 700; font-size: 13.5px; color: var(--text-muted); cursor: pointer; border-bottom: 3px solid transparent; margin-bottom: -2px; }
.view-tabs button.active { color: var(--primary); border-bottom-color: var(--primary); }

/* Non-modal auto-dismissing status toast — the keyboard-safe replacement
   for alert() (js/utils.js toast()). Does not trap or move focus. */
.a11y-toast {
    position: fixed;
    left: 50%;
    bottom: calc(20px + env(safe-area-inset-bottom));
    transform: translateX(-50%);
    max-width: min(92vw, 440px);
    background: var(--text-dark);
    color: var(--bg-light);
    padding: 12px 18px;
    border-radius: var(--radius-panel);
    font-size: 14px;
    font-weight: 600;
    line-height: 1.4;
    text-align: center;
    box-shadow: var(--shadow-pop);
    z-index: 10002;
}
.a11y-toast-error { background: var(--danger-red); color: var(--bg-light); }

.banner { border-radius: var(--radius-panel); padding: 14px 16px; display: flex; gap: 12px; align-items: flex-start; font-size: 14px; }
.banner-success { background: var(--success-bg); border: 1px solid var(--green-success); color: var(--green-success); }
.banner-info { background: var(--surface-alt); border: 1px solid var(--border-color); color: var(--text-dark); }
.banner strong { display: block; margin-bottom: 2px; }

/* ============================================================
   Accessibility Stage 6 (2026-09-07) — system preference media
   queries (motion / contrast / forced-colors) + the 2.5.8 AA
   target-size floor. A user-selectable dark / high-contrast
   THEME is deliberately deferred to Stage 7 (needs a palette
   decision — see docs/ACCESSIBILITY_AUDIT.md §6).
   ============================================================ */

/* 2.3.3 (AAA) + honouring a system "reduce motion" setting. Every
   transition in this file is small and <=0.15s, so cutting them all
   is invisible to anyone who has not asked for it. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        transition-duration: 0.01ms !important;
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        scroll-behavior: auto !important;
    }
}

/* Honouring a system "increase contrast" setting — firm up the
   subtle borders, collapse muted text onto Charcoal, drop the
   decorative shadows. Only touches users who have opted in. */
@media (prefers-contrast: more) {
    :root {
        --border-soft: var(--border-strong);
        --border-color: var(--border-strong);
        --text-muted: var(--slate);
    }
    .card, .modal-box, .a11y-toast, details.expander,
    .stat-tile { box-shadow: none !important; }
    .primary, .secondary, .danger,
    input, select, textarea { border-color: var(--text-dark) !important; }
}

/* Windows High Contrast Mode / forced-colors: the focus ring is a
   box-shadow (stripped here), so restore a real system-colour
   outline, and give the filled buttons a visible edge. */
@media (forced-colors: active) {
    :focus-visible {
        outline: 3px solid Highlight;
        outline-offset: 2px;
    }
    .primary, .secondary, .danger { border: 1px solid ButtonText; }
    .a11y-toast { border: 1px solid CanvasText; }
}

/* 2.5.8 Target Size (Minimum), WCAG 2.2 AA — a 24x24 floor on the
   compact/inline buttons flagged in the audit (O7). Dense board
   controls stay at this floor rather than the 44px AAA size
   (Q4 held); the primary actions are already ~40px tall. */
.draft-photo-actions button,
.ai-review-candidate-btn,
.ai-review-confirm-btn,
.copy-btn-compact {
    min-height: 24px;
    min-width: 24px;
}

/* 3.1.4 Abbreviations (AAA) — mark expansions consistently (Safari
   shows nothing for a bare abbr[title] otherwise). */
abbr[title] {
    text-decoration: underline dotted;
    text-underline-offset: 2px;
    cursor: help;
}
