@import url('https://fonts.googleapis.com/css2?family=Barlow:wght@400;500;600;700&family=Barlow+Condensed:wght@600;700&display=swap');

/* ── Reset & base ──────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html {
    font-size: 17px;
    /* Every scrollbar in the theme's colours, not the browser's white one in
       dark mode (#1674). Inherited, so it reaches every scroll box; one that
       wants its own look sets scrollbar-width/-color, since Chrome ignores
       ::-webkit-scrollbar once this is set. */
    scrollbar-color: var(--border) transparent;
}

/* Design tokens (:root and [data-theme="dark"]) live in tokens.css, which
   every page must link BEFORE this file. See #46. */

body {
    font-family: 'Barlow', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    background: var(--bg);
    color: var(--text);
    line-height: 1.5;
    min-height: 100vh;
}

/* Form controls don't inherit the page font: without this, every button,
   field and dropdown falls back to the browser's Arial. Size stays per class. */
button, input, select, textarea { font-family: inherit; }
/* Bike Specs: the sidebar names the page, so the heading's word takes no
   room (screen readers still read it); its "?" stays. The type tiles sit
   between the search card and the list (bike-specs.js) (3 Oct 2026). */
#page-bike-specs .page-header h1 { font-size: 0; display: flex; align-items: center; margin: 0; }
#page-bike-specs .page-header h1 .help-q { font-size: 0.9rem; margin-left: 0; }
#page-bike-specs .bike-specs-search-card { margin-bottom: 0.75rem; }
/* At 1024 wide the sidebar and the 380px card leave the list ~300px for 467px
   of columns, so it scrolled inside its box (#2352). On a screen this size the
   card also drops Subcategory, trims the cell padding and narrows to 320px;
   above 1100 the list has room. */
@media (min-width: 901px) and (max-width: 1100px) {
    #page-bike-specs .bike-specs-layout.has-detail .bike-specs-table th:nth-child(5),
    #page-bike-specs .bike-specs-layout.has-detail .bike-specs-table td:nth-child(5) { display: none; }
    #page-bike-specs .bike-specs-layout.has-detail .bike-specs-table :is(th, td) { padding-inline: 0.5rem; }
    #page-bike-specs .bike-specs-layout.has-detail .bike-specs-detail { flex-basis: 320px; }
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
/* Dashboard: the sidebar names the page, so the heading's word takes no room
   (screen readers still read it); its "?" stays (3 Oct 2026). */
#page-dashboard > h1 { font-size: 0; display: flex; align-items: center; margin: 0 0 var(--sp-2); }
#page-dashboard > h1 .help-q { font-size: 0.9rem; margin-left: 0; }
/* The Repairs card's DUE, PARTS and READY stones open the board filtered. */
#page-dashboard .borne[data-glance] { cursor: pointer; }
#page-dashboard .borne[data-glance]:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

h1 { font-size: 1.5rem; font-weight: 600; }
h2 { font-size: 1.3rem; font-weight: 600; margin-bottom: 0.75rem; }
h3 { font-size: 1.05rem; font-weight: 600; }
h1, h2, h3, h4 { color: var(--text-strong); }
/* Bold in running text only: a blanket rule would turn bold inside coloured badges white */
:is(p, li) > :is(strong, b) { color: var(--text-strong); }

/* ── Buttons ──────────────────────────────────────────────────────────────── */
.btn {
    display: inline-flex; align-items: center; gap: 0.4rem;
    padding: 0.5rem 1rem; border: none; border-radius: var(--radius);
    font-size: 0.9rem; font-weight: 500; cursor: pointer;
    transition: background 0.15s, opacity 0.15s;
}
/* .btn's display would otherwise override the hidden attribute (#2669). */
.btn[hidden] { display: none; }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }
/* A question about money (Modal.confirm's opts.big, #2007): two equal,
   thumb-sized buttons, so Cancel is as easy to hit as Yes. */
.modal-actions.modal-actions-thumb { gap: 0.75rem; }
.modal-actions.modal-actions-thumb .btn {
    flex: 1 1 0; justify-content: center; min-height: 52px;
    font-size: 1rem; font-weight: 600;
}

/* One look per job, app-wide:
   .btn-primary   the main action on a screen or modal: strong blue fill.
                  White on --accent was 3.2:1, so the fill is --ink-blue,
                  which the dark theme relights, with --on-solid ink on it.
   .btn-secondary anything else: neutral, with a border dark mode can see.
   .btn-ghost     a small undo beside a control: grey outline, no fill.
   .btn-cancel    Cancel / close without saving: red outline, no fill.
   .btn-danger    Delete, Remove, Archive: solid red fill. */
.btn-primary   {
    background: var(--ink-blue); color: var(--on-solid);
    border: 1px solid var(--accent); font-weight: 600;
}
.btn-primary:hover:not(:disabled) { background: var(--ink-blue-2); }

.btn-secondary { background: var(--bg-input); color: var(--text); border: 1px solid var(--border); }
.btn-secondary:hover:not(:disabled) { background: var(--bg-hover); }
[data-theme="dark"] .btn-secondary { border-color: var(--text-muted); }

.btn-cancel    { background: transparent; color: var(--ink-red); border: 1px solid var(--ink-red); }
.btn-cancel:hover:not(:disabled) { background: var(--danger-soft); }

/* .btn-ghost: a small undo beside the control it undoes (Take off, Switch off
   for this job, ↻, Unlink). Outline only and muted ink, so it sits quieter
   than the .btn-secondary next to it (#1919). */
.btn-ghost { background: transparent; color: var(--text-muted); border: 1px solid var(--border); }
.btn-ghost:hover:not(:disabled) { background: var(--bg-hover); color: var(--text); }
[data-theme="dark"] .btn-ghost { border-color: var(--text-muted); }

.btn-danger    { background: var(--danger); color: var(--on-solid); }
.btn-text      { background: none; color: var(--text-muted); padding: 0.4rem 0.6rem; }
.btn-text:hover { color: var(--text); }

.btn-block { width: 100%; justify-content: center; }

.btn-icon {
    display: inline-flex; align-items: center; justify-content: center;
    width: 1.6rem; height: 1.6rem; padding: 0; border: none; border-radius: var(--radius);
    background: none; color: var(--text-muted); font-size: 1rem; cursor: pointer;
    transition: background 0.15s, color 0.15s;
}
.btn-icon:hover { background: var(--danger); color: var(--on-solid); }

.table-row-actions {
    display: flex; align-items: center; gap: 0.5rem;
    margin-top: 0.5rem;
}

/* ── Inputs ───────────────────────────────────────────────────────────────── */
/* Every input except the ones that aren't boxes. This used to list the text
   types one by one, and each type left off it (tel, then date, time and an
   untyped <input>) fell back to the browser's 19px-tall white box (#855).
   :not() with a list scores as one attribute selector, so this has the same
   specificity as the old input[type="text"] and every class rule that beat it
   still does. `.form-input` has no rule of its own here; this one styles it. */
input:not([type="checkbox"], [type="radio"], [type="file"], [type="submit"],
          [type="button"], [type="reset"], [type="image"], [type="range"],
          [type="color"], [type="hidden"]), select, textarea {
    width: 100%; padding: 0.5rem 0.75rem;
    background: var(--bg-input); color: var(--text);
    border: 1px solid var(--border); border-radius: var(--radius);
    font-size: 0.9rem;
}
input:focus, select:focus, textarea:focus {
    outline: none; border-color: var(--accent);
}

/* No up/down arrows on number boxes: in a narrow one (a PO cost cell) they
   sit on top of the figure. Typing and the arrow keys still work. Bike Finder
   keeps its own box as it was. */
input[type="number"]:not(.bf-number-input) { -moz-appearance: textfield; appearance: textfield; }
input[type="number"]:not(.bf-number-input)::-webkit-outer-spin-button,
input[type="number"]:not(.bf-number-input)::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

.input-search { max-width: 260px; }

.form-group { margin-bottom: 1rem; }
.form-group label { display: block; margin-bottom: 0.3rem; font-size: 0.85rem; color: var(--text-muted); }

.error-text { color: var(--danger); font-size: 0.85rem; margin-top: 0.5rem; }

/* ── Cards ────────────────────────────────────────────────────────────────── */
.card {
    background: var(--bg-card); border: 1px solid var(--border);
    border-radius: var(--radius); padding: 1.25rem;
}
.card-stat { font-size: 2rem; font-weight: 700; margin: 0.5rem 0 0.2rem; }
.card-label { font-size: 0.875rem; color: var(--text-muted); }
.card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 1rem; margin-top: 1rem; }

/* ── Module dashboard cards ──────────────────────────────────────────────── */
.module-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 1rem;
    margin-top: 1rem;
}
.module-card {
    background: var(--bg-card); border: 1px solid var(--border);
    border-radius: var(--radius); padding: 1.25rem;
    cursor: pointer; display: flex; flex-direction: column;
    transition: box-shadow 0.15s, border-color 0.15s, transform 0.1s;
    user-select: none;
}
.module-card:hover {
    box-shadow: 0 4px 16px rgba(0,0,0,.1);
    border-color: var(--accent);
    transform: translateY(-1px);
}
.module-card-header {
    display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.75rem;
}
.module-card-icon {
    width: 1.1rem; height: 1.1rem; color: var(--accent); flex-shrink: 0;
}
.module-card-name {
    font-size: 0.75rem; font-weight: 700; text-transform: uppercase;
    letter-spacing: 0.06em; color: var(--text-muted);
}
.module-card-stat {
    font-size: 2.5rem; font-weight: 700; color: var(--text); line-height: 1;
}
.module-card-label {
    font-size: 0.875rem; color: var(--text-muted); margin-top: 0.2rem;
}
.module-card-badges {
    display: flex; flex-wrap: wrap; gap: 0.35rem; margin-top: 0.75rem;
}
.module-badge {
    font-size: 0.7rem; font-weight: 600; padding: 0.15rem 0.5rem;
    border-radius: 999px; background: var(--bg-input); color: var(--text-muted);
}
.module-badge--warn    { background: rgba(161,98,7,0.12);   color: var(--warning); }
.module-badge--danger  { background: rgba(198,40,40,0.10);  color: var(--danger); }
.module-badge--success { background: rgba(22,163,74,0.10);  color: var(--success); }
.module-badge--active  { background: rgba(79,140,255,0.10); color: var(--accent); }

/* ── Featured (Repairs) card ─────────────────────────────────────────────── */
.module-card--featured {
    grid-column: span 2;
    padding: 1.5rem 1.75rem;
}
.module-card--featured .module-card-stat { font-size: 3.5rem; }
.module-card--featured .module-card-name { font-size: 0.85rem; }
.module-card--featured .module-card-icon { width: 1.3rem; height: 1.3rem; }
@media (max-width: 520px) { .module-card--featured { grid-column: span 1; } }

/* The Repairs card's road-marker stones and col sign (#1504). The cap and
   the sign's band wear the shop's main team colour (layout.css). */
/* Four across, or two by two when there's no room: never three and a lone one. */
.dash-bornes { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0.6rem; margin-top: 0.4rem; }
@media (max-width: 360px) { .dash-bornes { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.borne {
    background: var(--bg); border: 1px solid var(--border); border-radius: 40px 40px 6px 6px;
    overflow: hidden; text-align: center; box-shadow: inset 0 -5px 0 rgba(0,0,0,.05);
}
.borne-cap {
    background: var(--team-1, #141516); color: var(--team-1-ink, #fff);
    font: 800 0.72rem 'Barlow Condensed', 'Barlow', sans-serif; letter-spacing: 0.14em;
    padding: 0.8rem 0 0.35rem;
    /* The kit's second colour under the cap, so a dark kit still reads on a dark stone. */
    border-bottom: 3px solid var(--team-2, #1fa35c);
}
.borne-val { font: 900 2.2rem/1 'Barlow Condensed', 'Barlow', sans-serif; padding-top: 0.45rem; font-variant-numeric: tabular-nums; color: var(--text-strong, var(--text)); }
.borne-lab { font-size: 0.74rem; color: var(--text-muted); padding: 0.15rem 0.2rem 0.6rem; }
.dash-col {
    margin: 0.8rem auto 0; max-width: 300px; text-align: center;
    background: #fff; color: #111; border: 3px solid #111; border-radius: 6px; overflow: hidden;
}
.dash-col[hidden] { display: none; }
.dash-col-band { height: 10px; background: var(--team-1, #141516); }
.dash-col-name { font: 900 1.35rem/1.1 'Barlow Condensed', 'Barlow', sans-serif; text-transform: uppercase; padding-top: 0.4rem; }
.dash-col-alt  { font: 800 1.7rem/1 'Barlow Condensed', 'Barlow', sans-serif; }
.dash-col-sub  { font-size: 0.76rem; color: #555; padding: 0.25rem 0.5rem 0.55rem; }

/* The top-sellers podium (#1523): steps in the shop's main team colour with
   the second as a stripe on top, first place tallest and in the middle. */
.dash-podium { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: end; gap: 0.4rem; margin-top: 0.6rem; min-height: 9.5rem; }
.dash-podium-note { grid-column: 1 / -1; align-self: center; text-align: center; color: var(--text-muted); font-size: 0.9rem; }
.pd { display: flex; flex-direction: column; align-items: center; gap: 0.15rem; text-align: center; min-width: 0; }
/* Double width like Repairs, so three product names have room; one column on a phone. */
.module-card[data-key="podium"] { grid-column: span 2; }
@media (max-width: 520px) { .module-card[data-key="podium"] { grid-column: span 1; } }
.pd-name { font-weight: 600; font-size: 0.82rem; line-height: 1.2; color: var(--text); overflow-wrap: break-word; hyphens: auto; }
.pd-count { font-size: 0.74rem; color: var(--text-muted); }
.pd-step {
    width: 100%; margin-top: 0.25rem; display: grid; place-items: center;
    background: var(--team-1, #141516); color: var(--team-1-ink, #fff);
    border-top: 3px solid var(--team-2, #1fa35c); border-radius: 6px 6px 0 0;
    font: italic 900 1.6rem/1 'Barlow Condensed', 'Barlow', sans-serif;
}
.pd-1 .pd-step { height: 5.2rem; }
.pd-2 .pd-step { height: 3.6rem; }
.pd-3 .pd-step { height: 2.5rem; }

/* On the till (#1872): every app-made order waiting to be paid. Double
   width like the podium; the list scrolls inside the card past ten lines. */
.module-card[data-key="ontill"] { grid-column: span 2; }
@media (max-width: 520px) { .module-card[data-key="ontill"] { grid-column: span 1; } }
.dash-till { margin-top: 0.5rem; }
.dash-till-note { color: var(--text-muted); font-size: 0.9rem; }
.dash-till-count { font-weight: 700; margin-bottom: 0.3rem; }
.dash-till-list { list-style: none; margin: 0; padding: 0 0.4rem 0 0; max-height: 18rem; overflow-y: auto; }
.dash-till-row {
    display: grid; grid-template-columns: 5.5rem 5rem minmax(0, 1fr) auto; gap: 0.5rem;
    align-items: baseline; padding: 0.3rem 0; border-top: 1px solid var(--border); font-size: 0.86rem;
}
.dash-till-row:first-child { border-top: 0; }
.dash-till-total { text-align: right; font-variant-numeric: tabular-nums; }
.dash-till-for { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dash-till-meta { color: var(--text-muted); font-size: 0.78rem; white-space: nowrap; }
@media (max-width: 520px) {
    .dash-till-list { max-height: none; padding-right: 0; }
    .dash-till-row { grid-template-columns: minmax(0, 1fr) auto; }
    .dash-till-for, .dash-till-meta { grid-column: 1 / -1; }
}

/* ── Card health left-border ─────────────────────────────────────────────── */
.module-card--health-green { border-left: 4px solid var(--success); }
.module-card--health-amber { border-left: 4px solid var(--warning); }

/* ── Card buttons: each card's own actions, pinned to its foot ───────────── */
.module-card-actions {
    display: flex; gap: 0.5rem; flex-wrap: wrap;
    margin-top: auto; padding-top: 1rem;
}
.module-card-action { display: inline-flex; align-items: center; gap: 0.4rem; }
.module-card-action-icon { display: inline-flex; width: 1rem; height: 1rem; flex-shrink: 0; }
.module-card-action-icon svg { width: 100%; height: 100%; }
.module-card-blurb { font-size: 0.875rem; color: var(--text-muted); line-height: 1.45; }

/* ── Help tiles: the guides, then one tile per area of the user guide ────── */
/* Narrower than the dashboard's, so three fit in the guide's reading width. */
.help-tiles { margin: 0.5rem 0 1rem; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); }
.help-tiles[hidden], .help-group-bar[hidden], .help-tools-buttons[hidden], .help-group--off { display: none; }
/* A big area (Admin reference): a tile per card, or one card alone. */
.help-card-tiles { margin: 0.5rem 0 1rem; }
.help-card-tiles .module-grid { margin-top: 0.5rem; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); }
.help-area-intro { color: var(--text-muted); }
.help-card-tiles[hidden], .help-card--off { display: none; }
.help-tile { font: inherit; color: inherit; text-align: left; width: 100%; }
.help-tile:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.help-tile--guides { cursor: default; grid-column: 1 / -1; }
.help-tile--guides:hover { transform: none; }
.help-tile-guides { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.6rem 1rem; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); }
.help-tile-guides a { font-weight: 600; }
.help-tile-what { display: block; font-size: 0.85rem; color: var(--text-muted); }
/* Demo videos (#1955): the tile is empty until Help knows which films this app holds. */
.help-tile--videos[hidden] { display: none; }
.modal-content:has(.help-video) { max-width: min(1100px, 95vw); }
.help-video { display: block; width: 100%; max-height: 72vh; background: #000; border-radius: 8px; }
.help-group-bar { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; margin: 0.5rem 0 1rem; }
.help-group-bar-title { font-size: 1.1rem; font-weight: 700; }

/* ── Upload zone ──────────────────────────────────────────────────────────── */
.upload-zone {
    border: 2px dashed var(--border); border-radius: var(--radius);
    padding: 3rem 2rem; text-align: center; cursor: pointer;
    transition: border-color 0.2s, background 0.2s;
    margin-bottom: 1.5rem;
}
.upload-zone:hover, .upload-zone.drag-over {
    border-color: var(--accent); background: rgba(79, 140, 255, 0.05);
}
.upload-hint { font-size: 0.85rem; color: var(--text-muted); margin-top: 0.5rem; }

/* ── Action bar ───────────────────────────────────────────────────────────── */
.action-bar {
    display: flex; align-items: center; justify-content: space-between;
    gap: 1rem; flex-wrap: wrap;
    padding: 1rem 0; margin-top: 1rem;
    border-top: 1px solid var(--border);
}

/* Left group: option flags (checkboxes) + mode select */
.action-bar-flags {
    display: flex; align-items: center; gap: 1.25rem; flex-wrap: wrap;
}
.action-bar-flags label {
    font-size: 0.9rem; display: flex; align-items: center; gap: 0.4rem; cursor: pointer;
}
.action-bar-flags label input[type="checkbox"] { cursor: pointer; }

/* Right group: action buttons, separated by a thin rule */
.action-bar-buttons {
    display: flex; align-items: center; gap: 0.5rem;
}
.action-bar-buttons::before {
    content: ""; display: block;
    width: 1px; height: 1.5rem;
    background: var(--border);
    margin-right: 0.25rem;
}

/* ── Inline select (width-constrained, used inside flex rows) ─────────────── */
.select-inline { width: auto; min-width: 140px; }

/* ── Utility ──────────────────────────────────────────────────────────────── */
.hidden { display: none !important; }

/* ── Placeholder ──────────────────────────────────────────────────────────── */
.placeholder-text { color: var(--text-muted); font-style: italic; padding: 2rem 0; }

/* ── Page header ──────────────────────────────────────────────────────────── */
.page-header {
    display: flex; justify-content: space-between; align-items: center;
    flex-wrap: wrap; gap: 1rem; margin-bottom: 1.25rem;
}
.page-actions { display: flex; gap: 0.5rem; align-items: center; }
/* Used Bikes: the two buttons keep their words on one line (#2699). */
#page-used-bikes .page-actions .btn { white-space: nowrap; flex: 0 0 auto; }

/* ── Mobile touch & iOS fixes ─────────────────────────────────────────────── */
@media (max-width: 768px) {
    /* Prevent iOS Safari from zooming in on focused inputs (requires font-size >= 16px) */
    input:not([type="checkbox"], [type="radio"], [type="file"], [type="submit"],
              [type="button"], [type="reset"], [type="image"], [type="range"],
              [type="color"], [type="hidden"]), select, textarea {
        font-size: 1rem;
        min-height: 44px;
    }

    /* Minimum touch target size for buttons */
    .btn { min-height: 44px; padding: 0.6rem 1rem; }
    .btn-text { min-height: 44px; }

    /* Page actions stack on small screens */
    .page-actions { flex-wrap: wrap; }
}

/* The rule above loses to any later class or id rule that sets a size of its own:
   the Repairs search box and filter dropdowns (0.82rem, #2358), the status chip
   on a repair card (0.88rem), the Bike to Work filter (.btn's 0.9rem), the
   Purchase Order location dropdown, table-cell boxes. Each left a box under 16px
   that iPhone Safari zooms into on tap (#2218). On a phone the size wins over
   all of them. 640 to 768 is left as it was: the Repairs bar's words only fit
   there at the smaller size (#2358). */
@media (max-width: 639px) {
    input:not([type="checkbox"], [type="radio"], [type="file"], [type="submit"],
              [type="button"], [type="reset"], [type="image"], [type="range"],
              [type="color"], [type="hidden"]), select, textarea {
        font-size: 1rem !important;
    }
}

/* ── Barcode Scanner ───────────────────────────────────────────────────────── */
#barcode-scanner-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.75);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1100;
}

.barcode-scanner-modal {
    background: var(--bg-card);
    /* Its edge was lost against the dark backdrop in dark mode (#1484). */
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1.25rem;
    width: min(380px, 95vw);
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.barcode-scanner-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-weight: 600;
    font-size: 1rem;
}

.barcode-scanner-close {
    background: none;
    border: none;
    color: var(--text-muted, #888);
    font-size: 1.4rem;
    cursor: pointer;
    line-height: 1;
    padding: 0 0.25rem;
}
.barcode-scanner-close:hover { color: var(--danger); }

#barcode-scanner-viewport {
    border-radius: var(--radius);
    overflow: hidden;
    background: #000;
}

/* suppress html5-qrcode's own dashboard UI */
#barcode-scanner-viewport > div > button,
#barcode-scanner-viewport #html5-qrcode-button-camera-permission,
#barcode-scanner-viewport #html5-qrcode-anchor-scan-type-change { display: none !important; }

.barcode-scanner-hint {
    font-size: 0.8rem;
    color: var(--text-muted, #888);
    text-align: center;
}

.barcode-scanner-result {
    background: var(--success);
    color: var(--on-solid);
    border-radius: var(--radius);
    padding: 0.5rem 0.75rem;
    font-weight: 600;
    font-size: 0.9rem;
    text-align: center;
}

/* Camera icon button beside search inputs */
.btn-scan {
    padding: 0 0.6rem;
    background: var(--bg-input);
    border: 1px solid var(--border, #333);
    border-radius: var(--radius);
    cursor: pointer;
    color: var(--accent);
    font-size: 1.1rem;
    line-height: 1;
    display: inline-flex;
    align-items: center;
    transition: background 0.15s;
}
.btn-scan:hover { background: var(--bg-hover); }

/* ══════════════════════════════════════════════════════════════════════════
   DESIGN SYSTEM — Utilities & shared components
   Added 2026-04-20. Prefer these over inline styles or hard-coded hex values.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Display utilities ─────────────────────────────────────────────────── */
.d-none          { display: none; }
.d-block         { display: block; }
.d-inline-block  { display: inline-block; }
.d-flex          { display: flex; }

/* ── Layout utilities ──────────────────────────────────────────────────── */
.flex            { display: flex; }
.flex-col        { display: flex; flex-direction: column; }
.flex-center     { display: flex; align-items: center; justify-content: center; }
.flex-between    { display: flex; align-items: center; justify-content: space-between; }
.flex-end        { display: flex; justify-content: flex-end; }
.flex-wrap       { flex-wrap: wrap; }
.items-center    { align-items: center; }
.items-start     { align-items: flex-start; }
.ml-auto         { margin-left: auto; }
.gap-1           { gap: var(--sp-1); }
.gap-2           { gap: var(--sp-2); }
.gap-3           { gap: var(--sp-3); }
.gap-4           { gap: var(--sp-4); }
.gap-5           { gap: var(--sp-5); }

.grid-2          { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); }

.flex-1          { flex: 1; }
.min-w-150       { min-width: 150px; }
.cursor-pointer  { cursor: pointer; }

.scroll-y         { overflow-y: auto; }
.max-h-400        { max-height: 400px; }
.relative         { position: relative; }
.absolute         { position: absolute; }
.inset-0          { position: absolute; inset: 0; }
.object-cover     { object-fit: cover; }
.rounded          { border-radius: var(--radius); }
.rounded-sm       { border-radius: var(--radius-sm); }
.rounded-t        { border-radius: var(--radius) var(--radius) 0 0; }
.flex-shrink-0    { flex-shrink: 0; }
.resize-vertical  { resize: vertical; }

/* ── Spacing utilities ─────────────────────────────────────────────────── */
.m-0             { margin: 0; }
.mt-0            { margin-top: 0; }
.mt-1            { margin-top: var(--sp-1); }
.mt-2            { margin-top: var(--sp-2); }
.mt-3            { margin-top: var(--sp-3); }
.mt-4            { margin-top: var(--sp-4); }
.mt-5            { margin-top: var(--sp-5); }
.mb-0            { margin-bottom: 0; }
.mb-1            { margin-bottom: var(--sp-1); }
.mb-2            { margin-bottom: var(--sp-2); }
.mb-3            { margin-bottom: var(--sp-3); }
.mb-4            { margin-bottom: var(--sp-4); }
.mb-5            { margin-bottom: var(--sp-5); }
.ml-1            { margin-left: var(--sp-1); }
.ml-2            { margin-left: var(--sp-2); }
.mr-1            { margin-right: var(--sp-1); }
.mr-2            { margin-right: var(--sp-2); }
.my-2            { margin-top: var(--sp-2); margin-bottom: var(--sp-2); }
.my-3            { margin-top: var(--sp-3); margin-bottom: var(--sp-3); }
.my-4            { margin-top: var(--sp-4); margin-bottom: var(--sp-4); }
.p-2             { padding: var(--sp-2); }
.p-3             { padding: var(--sp-3); }
.p-4             { padding: var(--sp-4); }
.px-2            { padding-left: var(--sp-2); padding-right: var(--sp-2); }
.py-1            { padding-top: var(--sp-1); padding-bottom: var(--sp-1); }
.py-2            { padding-top: var(--sp-2); padding-bottom: var(--sp-2); }

/* ── Width helpers (replace inline style="width:…") ───────────────────── */
.w-full          { width: 100%; }
.w-auto          { width: auto; }
.w-60            { width: 60px; }
.w-70            { width: 70px; }
.w-100           { width: 100px; }
.w-120           { width: 120px; }
.col-checkbox    { width: 2rem; }
.w-140           { width: 140px; }
.w-200           { width: 200px; }
.w-260           { width: 260px; }
.max-w-sm        { max-width: 520px; }
.max-w-md        { max-width: 720px; }

/* ── Typography utilities ─────────────────────────────────────────────── */
.text-center     { text-align: center; }
.text-right      { text-align: right; }
.text-left       { text-align: left; }
.text-muted      { color: var(--text-muted); }
.text-strong     { color: var(--text-strong); }
.text-accent     { color: var(--accent); }
.text-success    { color: var(--success); }
.text-warning    { color: var(--warning); }
.text-danger     { color: var(--danger); }
.text-info       { color: var(--info); }
.fs-xs           { font-size: 0.72rem; }
.fs-sm           { font-size: 0.82rem; }
.fs-md           { font-size: 0.9rem; }
.fs-lg           { font-size: 1.05rem; }
.fs-xl           { font-size: 1.25rem; }
.fw-500          { font-weight: 500; }
.fw-600          { font-weight: 600; }
.fw-700          { font-weight: 700; }
.nowrap          { white-space: nowrap; }
.pre-wrap        { white-space: pre-wrap; }
.truncate        { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ── Button size modifier (pairs with .btn variants) ──────────────────── */
.btn-lg          { padding: 0.7rem 1.25rem; font-size: 1rem; }
/* .btn-sm is already defined in components.css */

/* ── Status badge system (unified across modules) ─────────────────────── */
.status-badge {
    display: inline-block;
    padding: 0.15rem 0.55rem;
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 600;
    line-height: 1.4;
    text-transform: capitalize;
    background: var(--bg-input);
    color: var(--text-muted);
    white-space: nowrap;
}
.status-badge--accent   { background: var(--accent-soft);  color: var(--accent); }
.status-badge--success  { background: var(--success-soft); color: var(--success); }
.status-badge--warning  { background: var(--warning-soft); color: var(--warning); }
.status-badge--danger   { background: var(--danger-soft);  color: var(--danger); }
.status-badge--info     { background: var(--info-soft);    color: var(--info); }
.status-badge--purple   { background: var(--purple-soft);  color: var(--purple); }
.status-badge--teal     { background: var(--teal-soft);    color: var(--teal); }
.status-badge--orange   { background: var(--orange-soft);  color: var(--orange); }

/* Status dots (small coloured circle used in compact ticket lists) */
.status-dot {
    display: inline-block;
    width: 8px; height: 8px;
    border-radius: 50%;
    flex-shrink: 0;
    background: var(--text-muted);
}
.status-dot--accent   { background: var(--accent); }
.status-dot--success  { background: var(--success); }
.status-dot--warning  { background: var(--warning); }
.status-dot--danger   { background: var(--danger); }
.status-dot--info     { background: var(--info); }
.status-dot--purple   { background: var(--purple); }
.status-dot--teal     { background: var(--teal); }
.status-dot--orange   { background: var(--orange); }

/* Legacy status aliases (used by cache.js) */
.status-active   { background: var(--success-soft); color: var(--success); }
.status-pending  { background: var(--warning-soft); color: var(--warning); }
.status-draft    { background: var(--bg-input);     color: var(--text-muted); }

/* ── Import / progress status banner ──────────────────────────────────── */
.import-status {
    padding: var(--sp-2) var(--sp-3);
    border-radius: var(--radius);
    font-size: 0.88rem;
    margin-top: var(--sp-2);
    border: 1px solid var(--border);
    background: var(--bg-card);
    color: var(--text);
}
.import-status.loading { background: var(--accent-soft);  border-color: transparent; color: var(--accent); }
.import-status.success { background: var(--success-soft); border-color: transparent; color: var(--success); }
.import-status.warning { background: var(--warning-soft); border-color: transparent; color: var(--warning); }
.import-status.error   { background: var(--danger-soft);  border-color: transparent; color: var(--danger); }

/* ── Pagination bar ───────────────────────────────────────────────────── */
.pagination {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--sp-3); flex-wrap: wrap;
    margin-top: var(--sp-4);
}
.pagination-info {
    font-size: 0.85rem;
    color: var(--text-muted);
}
.pagination-btns {
    display: flex; gap: var(--sp-2); align-items: center;
}

/* ── Compact input (per-page picker etc.) ─────────────────────────────── */
.input-search--compact {
    width: auto;
    padding: var(--sp-1) var(--sp-2);
    font-size: 0.85rem;
}

/* ── Modal (generic) ──────────────────────────────────────────────────── */
.modal-backdrop {
    position: fixed; inset: 0;
    /* The same shade as the shared .modal-overlay (#1484). */
    background: rgba(0,0,0,0.5);
    display: flex; align-items: center; justify-content: center;
    z-index: 9999;
    padding: var(--sp-3);
}
.modal-panel {
    background: var(--surface-raised);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-lg);
    padding: var(--sp-5);
    width: 520px; max-width: 100%;
    max-height: 90vh; overflow-y: auto;
}
.modal-panel--wide { width: 720px; }
/* Sized as the shared dialog's h2, so Edit Bike and the Cache panels don't
   title smaller than every other pop-up (#1484). */
.modal-title    { margin: 0 0 var(--sp-3); font-size: 1.3rem; font-weight: 600; }
.modal-subtitle { margin: 0 0 var(--sp-3); font-size: 0.85rem; color: var(--text-muted); }
.modal-actions  { display: flex; justify-content: flex-end; gap: var(--sp-2); margin-top: var(--sp-4); }

/* ── Empty state (shared across pages) ────────────────────────────────── */
.cdc-empty-state {
    padding: var(--sp-6) var(--sp-4);
    text-align: center;
    color: var(--text-muted);
}
.cdc-empty-state__title {
    font-size: 1rem; font-weight: 600; color: var(--text); margin-bottom: var(--sp-2);
}
.cdc-empty-state__hint  {
    font-size: 0.88rem; color: var(--text-muted);
}

/* ── Skeleton shimmer (loading placeholder) ───────────────────────────── */
.cdc-skeleton {
    display: block;
    background: linear-gradient(90deg, var(--bg-input) 0%, var(--bg-hover) 50%, var(--bg-input) 100%);
    background-size: 200% 100%;
    animation: cdc-skel 1.3s ease-in-out infinite;
    border-radius: var(--radius-sm);
    height: 1rem;
}
@keyframes cdc-skel {
    0%   { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}

/* ── Dropdown row (used by search autocompletes) ──────────────────────── */
.dropdown-row {
    padding: var(--sp-2) var(--sp-3);
    cursor: pointer;
    border-bottom: 1px solid var(--border);
    transition: background 0.12s;
}
.dropdown-row:last-child { border-bottom: none; }
.dropdown-row:hover      { background: var(--bg-hover); }
.dropdown-empty          { padding: var(--sp-2) var(--sp-3); color: var(--text-muted); }

/* ── Close button (× inside modals / chips) ───────────────────────────── */
.btn-close {
    background: none; border: none; cursor: pointer;
    color: var(--text-muted); font-size: 1.3em; line-height: 1;
    padding: 0 var(--sp-1);
    transition: color 0.12s;
}
.btn-close:hover { color: var(--text); }

/* ── Third-party brand badges ─────────────────────────────────────────── */
.badge--donedeal { background: #e8581c; color: #fff; text-decoration: none; white-space: nowrap; }
.badge--facebook { background: #1877f2; color: #fff; }
.badge--shopify-synced   { background: #96bf48; color: #fff; }
.badge--shopify-pending  { background: var(--warning); color: var(--on-solid); }
.badge--shopify-failed   { background: var(--danger);  color: var(--on-solid); }
.badge--shopify-archived { background: var(--text-muted); color: var(--on-solid); }
.badge--photo-missing    { background: var(--warning-soft); color: var(--warning); }

/* ── Used Bikes cards ─────────────────────────────────────────────────── */
.ub-card            { padding: 0; overflow: hidden; }
.ub-card--sold      { opacity: 0.6; }
.ub-card--enquiry   { border: 2px solid var(--warning); }
.ub-card-body       { padding: var(--sp-3); }
.ub-card-header     { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--sp-2); }
.ub-card-title      { font-size: 0.95em; }
.ub-card-price      { font-size: 1.1em; font-weight: 600; margin: var(--sp-1) 0; }
.ub-card-location   { font-size: 0.8em; color: var(--text-muted); margin-bottom: var(--sp-2); }
.ub-card-contact    { font-size: 0.85em; color: var(--text-muted); margin: var(--sp-1) 0; }
.ub-card-desc       { font-size: 0.85em; color: var(--text-muted); margin: 0 0 var(--sp-2); white-space: pre-wrap; }
.ub-card-desc--enq  { margin: var(--sp-1) 0 var(--sp-2); }
.ub-card-notes      { font-size: 0.8em; color: var(--text-muted); margin: 0 0 var(--sp-2); }
.ub-card-badges     { display: flex; gap: var(--sp-1); flex-wrap: wrap; margin-bottom: var(--sp-2); }
.ub-card-actions    { display: flex; gap: var(--sp-2); flex-wrap: wrap; margin-top: var(--sp-2); }
.ub-card-actions--grouped { flex-direction: column; flex-wrap: nowrap; }
.ub-card-actions__row   { display: flex; gap: var(--sp-2); flex-wrap: wrap; align-items: center; }
/* Shopify / Adverts sit in outlined boxes, label on top, so wrapped buttons
   stay inside their section rather than sliding under the label. */
.ub-card-section        { border: 1px solid var(--border); border-radius: var(--radius); padding: var(--sp-2); }
.ub-card-actions__label { font-size: 0.7em; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); margin-right: auto; }
.ub-card-section__head  { display: flex; gap: var(--sp-1); flex-wrap: wrap; align-items: center; }
.ub-card-section__head + .ub-card-actions__row { margin-top: var(--sp-2); }
.ub-card-section--bike > .ub-card-actions__row { margin-top: var(--sp-2); }
/* Delete bike sits at the right of the price, so it never wraps onto a line of its own. */
.ub-card-price-row     { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); }
.ub-card .btn           { white-space: nowrap; }
.ub-card-channel        { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); margin-top: var(--sp-2); }
.ub-card-channel__none  { font-size: 0.8em; color: var(--text-muted); }
.ub-card-channel > .btn { min-width: 10.5em; text-align: center; }
.ub-card-section__badges { display: flex; gap: var(--sp-1); flex-wrap: wrap; justify-content: flex-end; }
.ub-card-actions__end   { margin-left: auto; }

/* Carousel + photo surfaces */
.ub-photo-none {
    width: 100%; height: 100px; background: var(--bg-input);
    border-radius: var(--radius) var(--radius) 0 0;
    display: flex; align-items: center; justify-content: center;
    color: var(--text-muted); font-size: 0.82em;
}
.ub-photo-none--short { height: 80px; }
.ub-photo-single {
    width: 100%; height: 180px; object-fit: cover;
    border-radius: var(--radius) var(--radius) 0 0;
}
.ub-carousel {
    position: relative; width: 100%; height: 180px;
    border-radius: var(--radius) var(--radius) 0 0;
    overflow: hidden; background: #000;
}
.ub-carousel-slide {
    position: absolute; inset: 0; width: 100%; height: 100%;
    object-fit: cover; opacity: 0; transition: opacity 0.2s;
}
.ub-carousel-slide.is-active { opacity: 1; }
.ub-carousel-btn {
    position: absolute; top: 50%; transform: translateY(-50%);
    background: rgba(0,0,0,0.45); color: #fff;
    border: none; border-radius: 50%;
    width: 26px; height: 26px; cursor: pointer;
    font-size: 14px; line-height: 1; z-index: 2;
}
.ub-carousel-btn--prev { left: 4px; }
.ub-carousel-btn--next { right: 4px; }
.ub-carousel-counter {
    position: absolute; bottom: 5px; right: 7px;
    background: rgba(0,0,0,0.5); color: #fff;
    font-size: 0.72em; border-radius: 10px;
    padding: 1px 6px; z-index: 2;
}

/* Modal form */
.ub-form            { display: flex; flex-direction: column; gap: var(--sp-3); }
.ub-form-row        { display: flex; gap: var(--sp-3); }
.ub-form-col        { flex: 1; }
.ub-form-label      { display: block; font-size: 0.85em; font-weight: 600; margin-bottom: var(--sp-1); }
.ub-form-label-hint { font-weight: 400; color: var(--text-muted); }
.ub-form-input      {
    width: 100%; padding: var(--sp-2) var(--sp-3);
    border: 1px solid var(--border); border-radius: var(--radius);
    background: var(--bg-input); color: var(--text);
}
.ub-form-input--textarea { resize: vertical; }

/* Photo thumbs in modal */
.ub-photo-thumbs    { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-bottom: var(--sp-2); }
.ub-photo-thumb {
    position: relative; width: 80px; height: 60px;
    border-radius: var(--radius-sm); overflow: hidden; flex-shrink: 0;
}
.ub-photo-thumb__img { width: 100%; height: 100%; object-fit: cover; }
/* A photo whose file has gone from the volume (#511): a labelled tile, not a broken image */
.ub-photo-thumb--missing {
    background: var(--warning-soft); color: var(--warning);
    display: flex; align-items: center; justify-content: center;
    font-size: 0.72em; font-weight: 600; text-align: center;
}
.ub-photo-thumb__remove {
    position: absolute; top: 2px; right: 2px;
    background: rgba(0,0,0,0.6); color: #fff;
    border: none; border-radius: 50%;
    width: 18px; height: 18px; cursor: pointer;
    font-size: 10px; line-height: 1; padding: 0;
}
.ub-photo-file      { display: block; font-size: 0.85em; }
.ub-photo-previews  { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-2); }
/* Square tiles in one grid with a big Add photo square, as the old quick-add
   page had (bike-capture's .bc-photos). The two lists flow into the grid. */
.ub-photo-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(90px, 1fr)); gap: var(--sp-2); }
.ub-photo-grid .ub-photo-thumbs, .ub-photo-grid .ub-photo-previews { display: contents; }
.ub-photo-grid .ub-photo-thumb { width: auto; height: auto; aspect-ratio: 1; border-radius: var(--radius); }
.ub-photo-grid .ub-photo-thumb__remove { width: 26px; height: 26px; font-size: 13px; top: 4px; right: 4px; }
.ub-photo-add {
    aspect-ratio: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
    border: 2px dashed var(--border); border-radius: var(--radius); background: var(--bg-input, var(--surface));
    color: var(--text-muted); font-size: 0.8rem; cursor: pointer;
}
.ub-photo-add svg { width: 26px; height: 26px; }
.ub-photo-add[hidden] { display: none; }
.ub-photo-grid ~ .ub-photo-file { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.ub-photo-preview   { width: 80px; height: 60px; object-fit: cover; border-radius: var(--radius-sm); }
.ub-photo-count     { font-size: 0.78em; color: var(--text-muted); margin-top: var(--sp-1); }

/* Facebook / DoneDeal confirm banners */
.fb-confirm-banner, .dd-confirm-banner {
    background: var(--info-soft); border: 1px solid var(--info);
    border-radius: var(--radius);
    padding: var(--sp-2) var(--sp-3);
    margin: var(--sp-2) var(--sp-3);
    font-size: 0.82em;
    display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
}
.fb-confirm-banner__msg { flex: 1; }
.dd-confirm-banner__msg { flex: 1 1 100%; }
.dd-confirm-banner__url { flex: 1 1 14rem; min-width: 0; }

/* Parts Ordering: the sidebar names the page, so the heading's word takes no
   room (screen readers still read it); its "?" stays (3 Oct 2026). */
#page-ordering .page-header h1 { font-size: 0; display: flex; align-items: center; margin: 0; }
#page-ordering .page-header h1 .help-q { font-size: 0.9rem; margin-left: 0; }

/* Warranty: one bar at the top, search, the status dropdown and Export CSV,
   with the tiles under it (warranty.js _buildBar). The sidebar names the
   page, so the heading's word takes no room; its "?" stays (3 Oct 2026). */
/* One level row beside the sidebar on an upright iPad too (#2293): a row
   breaks on its items' flex-basis before anything shrinks, so the header and
   the bar do not wrap. Search and the dropdown shrink together, each down to
   a floor of its own (8.5rem and 5rem), so neither depends on how wide the
   font draws Export CSV. The header is its own container, since a
   screen-width rule cannot see the sidebar: where it is narrow the button
   gives up padding, which leaves the floors room beside it in a face a
   quarter wider than ours. */
#page-warranty .page-header { flex-wrap: nowrap; gap: var(--sp-3); container: warranty-header / inline-size; }
#page-warranty .page-header h1 { font-size: 0; display: flex; align-items: center; margin: 0; }
#page-warranty .page-header h1 .help-q { font-size: 0.9rem; margin-left: 0; }
#page-warranty .warranty-bar { flex: 1 1 0; min-width: 0; flex-wrap: nowrap !important; align-items: center; justify-content: flex-end; }
#page-warranty .warranty-bar #warranty-search { flex: 1 1 14rem; min-width: 8.5rem; max-width: none !important; }
#page-warranty .warranty-bar #warranty-status-filter { flex: 0 1 10rem; min-width: 5rem; width: auto; }
/* Every control in the bar is the one height (they were 37, 39 and 40). */
#page-warranty .warranty-bar > * { height: 40px; box-sizing: border-box; }
#page-warranty .warranty-bar .btn { flex: 0 0 auto; white-space: nowrap; }
@container warranty-header (max-width: 900px) {
    #page-warranty .warranty-bar .btn { padding-left: var(--sp-2); padding-right: var(--sp-2); }
}
/* + New Claim shrinks to its "+" where the header is narrow (#2693), so the
   bar keeps its one row beside the sidebar. */
@container warranty-header (max-width: 900px) {
    #page-warranty .warranty-bar .wn-label { display: none; }
    #page-warranty .warranty-bar .btn-primary { padding-left: 0; padding-right: 0; width: 36px; }
    #page-warranty .warranty-bar #warranty-search { min-width: 7rem; }
}
/* A phone has no room for the three abreast: search beside the "?", then
   the dropdown and Export CSV sharing the line under it. */
@media (max-width: 600px) {
    #page-warranty .page-header { align-items: flex-start; }
    #page-warranty .page-header h1 { min-height: 44px; }
    #page-warranty .warranty-bar { flex-wrap: wrap !important; }
    #page-warranty .warranty-bar #warranty-search { flex-basis: 100%; }
    #page-warranty .warranty-bar #warranty-status-filter { flex: 1 1 8rem; }
}
#page-warranty .warranty-bar .is-set { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
