/* ==========================================================================
   Mobile Heaven — design tokens
   --------------------------------------------------------------------------
   One token layer over Bootstrap 5.3, serving BOTH the public website and
   the staff application. There is no build step in this project (no Sass,
   no npm), so theming is done by overriding Bootstrap's own CSS custom
   properties — which is exactly what 5.3 is designed for.

   The two surfaces use these tokens at different intensities:

     website — accent everywhere; colour persuades.
     app     — brand colour in the chrome only; the content area stays
               neutral so STATUS colour can carry meaning. With 21 stock
               statuses, 11 repair, 11 lending and 11 lead statuses, an
               accent spent on decoration leaves nothing to say "overdue".
               Status colours are therefore independent of the public
               accent -- see --mh-review.

   Contrast note (BRD §43.6 "high contrast"): the accent is 5.26:1 on
   white and white on it is 5.26:1, so unlike the gold it replaces
   (2.46:1, surface-only) it CAN carry text -- links, button labels and
   small icons all work. On near-black it drops to 3.76:1, so dark
   sections use --mh-accent-on-dark (8.15:1) for anything textual.
   ========================================================================== */

:root {
    /* ---- brand ---- */
    /* Near-black, not brown. The positioning is "affordable, not cheap":
       the buyer wants the latest phone and cannot justify first-hand
       price, so the site has to read premium tech, not heritage. */
    --mh-graphite: #0A0A0B;
    --mh-graphite-hover: #1F1F23;
    --mh-graphite-deep: #000000;

    /* The accent CAN carry text, which the old gold could not: 5.26:1 on
       white against a 4.5:1 floor, where gold was 2.46:1 and had to stay
       a surface. White on it is also 5.26:1, so button labels work. */
    --mh-accent: #0B5CFF;
    --mh-accent-hover: #0847CC;
    --mh-accent-soft: #E3EBFF;

    /* On near-black the base accent is only 3.76:1 -- fine for a border,
       a focus ring or a filled button, below the floor for body text. Dark
       sections use this lighter tint of the same hue instead (8.15:1). */
    --mh-accent-on-dark: #7AA5FF;

    /* Staff status vocabulary, deliberately INDEPENDENT of the public
       accent. .status-review means "needs a human"; painting it the same
       blue as every link on the site would erase that distinction.
       #3F2D00 on #FDE68A is 10.63:1. */
    --mh-review: #FDE68A;
    --mh-review-ink: #3F2D00;

    /* ---- ground ---- */
    /* White is the page now, and generous. The old cream existed to soften
       deep chocolate; against near-black there is nothing to soften, and
       white is what makes product photography lead. Cards no longer lift
       off a tint -- a thin neutral border does that work. */
    --mh-page: #FFFFFF;
    --mh-white: #FFFFFF;
    --mh-border: #E4E4E7;

    /* Tinted surfaces: a product photo sits on `frame`, an icon tile on
       `icon`. Neutral grey now rather than warm, so a white PNG still
       reads as an object on a surface without reintroducing the brown. */
    --mh-surface-frame: #F4F4F5;
    --mh-surface-icon: #EFF4FF;

    /* ---- text ---- */
    --mh-ink: #0A0A0B;      /* 19.79:1 on white */
    --mh-muted: #52525B;    /* 7.73:1 on white */
    --mh-muted-on-dark: #A1A1AA; /* 7.72:1 on near-black */

    /* ---- rhythm ---- */
    /* --mh-radius/-lg feed --bs-border-radius app-wide and stay
       tight; the public site opts into the rounder scale below
       under .site-public, so staff tables keep their density. */
    --mh-radius: 0.25rem;
    --mh-radius-lg: 0.375rem;
    --mh-radius-sm: 0.5rem;
    --mh-radius-md: 0.75rem;
    --mh-radius-xl: 1rem;
    --mh-radius-pill: 999px;
    /* Was clamp(3.5rem, 6vw, 5.5rem) -- 76px at desktop, applied top AND
       bottom, so every boundary between two sections was 152px of
       nothing. On the homepage that added up to 1,368px, 19% of the
       page. One token because it is used everywhere; patching individual
       sections would drift. */
    --mh-section-y: clamp(2.25rem, 3.5vw, 3.5rem);

    /* ---- Bootstrap overrides ---- */
    --bs-primary: var(--mh-graphite);
    --bs-primary-rgb: 10, 10, 11;
    --bs-body-bg: var(--mh-page);
    --bs-body-color: var(--mh-ink);
    --bs-secondary-color: var(--mh-muted);
    --bs-border-color: var(--mh-border);
    --bs-link-color: var(--mh-accent);
    --bs-link-color-rgb: 11, 92, 255;
    --bs-link-hover-color: var(--mh-accent-hover);
    --bs-emphasis-color: var(--mh-ink);

    --bs-border-radius: var(--mh-radius);
    --bs-border-radius-lg: var(--mh-radius-lg);

    /* Georgia for display, system sans for everything else.
       A self-hosted variable serif would be more distinctive but costs
       30–60 KB, and performance IS design for customers on mobile data
       in Tripura. Georgia is universally available, warm, well-drawn and
       costs zero bytes. Revisit only if the wordmark needs more character. */
    --mh-font-display: Georgia, 'Times New Roman', serif;
    --mh-font-sans: 'Plus Jakarta Sans', system-ui, -apple-system,
        'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
    --bs-body-font-family: system-ui, -apple-system, 'Segoe UI', Roboto,
        'Helvetica Neue', Arial, sans-serif;
}

/* ==========================================================================
   Typography
   Hierarchy comes from size and weight, not from boxes and borders.
   ========================================================================== */

body {
    background-color: var(--mh-page);
    color: var(--mh-ink);
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3, .display-6 {
    font-family: var(--mh-font-display);
    color: var(--mh-graphite);
    letter-spacing: -0.01em;
}

h1, .display-6 { font-size: clamp(1.9rem, 4vw, 2.75rem); line-height: 1.15; }
h2 { font-size: clamp(1.5rem, 3vw, 2rem); line-height: 1.2; }
h3 { font-size: 1.5rem; }

.brand-mark {
    font-family: var(--mh-font-display);
    font-weight: 700;
    letter-spacing: 0.01em;
}

.text-muted { color: var(--mh-muted) !important; }

/* ==========================================================================
   Chrome — navbar and footer
   ========================================================================== */

.navbar.bg-primary {
    background-color: var(--mh-graphite) !important;
    /* The single thread of gold that ties the whole thing together. */
    border-bottom: 2px solid var(--mh-accent);
}

.navbar .nav-link.active {
    color: var(--mh-accent) !important;
}

/* ==========================================================================
   Buttons
   Restraint rule: ONE gold call-to-action per screen. Gold everywhere
   reads as a 1990s hotel.
   ========================================================================== */

.btn-primary {
    --bs-btn-bg: var(--mh-graphite);
    --bs-btn-border-color: var(--mh-graphite);
    --bs-btn-hover-bg: var(--mh-graphite-hover);
    --bs-btn-hover-border-color: var(--mh-graphite-hover);
    --bs-btn-active-bg: var(--mh-graphite-deep);
    --bs-btn-active-border-color: var(--mh-graphite-deep);
    --bs-btn-disabled-bg: var(--mh-graphite);
    --bs-btn-disabled-border-color: var(--mh-graphite);
}

.btn-outline-primary {
    --bs-btn-color: var(--mh-graphite);
    --bs-btn-border-color: var(--mh-graphite);
    --bs-btn-hover-bg: var(--mh-graphite);
    --bs-btn-hover-border-color: var(--mh-graphite);
    --bs-btn-active-bg: var(--mh-graphite-deep);
}

/* Gold as a SURFACE carrying chocolate text — roughly 8:1, which is why
   this is the one place gold is allowed near type. */
/* The old gold was a LIGHT surface and wanted dark text on it (~5.6:1).
   The accent is a DARK surface and wants white (5.26:1); keeping the dark
   label would have shipped 3.76:1, which the rendered audit caught. */
.btn-accent {
    --bs-btn-color: var(--mh-white);
    --bs-btn-bg: var(--mh-accent);
    --bs-btn-border-color: var(--mh-accent);
    --bs-btn-hover-color: var(--mh-white);
    --bs-btn-hover-bg: var(--mh-accent-hover);
    --bs-btn-hover-border-color: var(--mh-accent-hover);
    --bs-btn-active-color: var(--mh-white);
    --bs-btn-active-bg: var(--mh-accent-hover);
    --bs-btn-focus-shadow-rgb: 11, 92, 255;
    font-weight: 600;
}

/* BRD §43.6 "large touch targets". 44px is the smallest reliably tappable
   target on a phone; the shop's customers are overwhelmingly on phones. */
.btn-lg,
.btn-touch {
    min-height: 44px;
}

/* ==========================================================================
   Focus — visible, gold, never removed
   ========================================================================== */

:focus-visible {
    outline: 3px solid var(--mh-accent);
    outline-offset: 2px;
}

.btn:focus-visible,
.form-control:focus,
.form-select:focus {
    border-color: var(--mh-accent);
    box-shadow: 0 0 0 0.25rem rgba(201, 162, 39, 0.35);
}

/* ==========================================================================
   Surfaces
   ========================================================================== */

.card,
.card-block {
    background-color: var(--mh-white);
    border: 1px solid var(--mh-border);
    border-radius: var(--mh-radius);
    box-shadow: 0 1px 3px rgba(43, 29, 20, 0.05);
}

/* Alternating band, so a long marketing page has rhythm without rules
   everywhere. */
.section-cream { background-color: var(--mh-page); }
.section-white { background-color: var(--mh-white); }

.section-y { padding-block: var(--mh-section-y); }

/* A hairline of gold, used to separate — never a heavy divider. */
.rule-gold {
    border: 0;
    border-top: 2px solid var(--mh-accent);
    width: 3rem;
    opacity: 1;
    margin-block: 1.25rem;
}

/* ==========================================================================
   Editorial hero
   Photograph carries the emotional weight; the overlay exists only so the
   headline stays readable over an unpredictable image.
   ========================================================================== */

.hero {
    position: relative;
    /* A framed hero with a tall image can be taller than its min-height band;
       clipping keeps that overflow inside the hero instead of bleeding over
       the navbar (where it silently captured nav clicks). */
    overflow: hidden;
    background-color: var(--mh-graphite);
    background-size: cover;
    background-position: center;
    color: var(--mh-white);
}

/* The global hero overlay was removed: image heroes now carry their own
   OWNER-ADJUSTABLE overlay inline (see x-site.hero), and the animated
   homepage hero needs none. A fixed dark ::after on top of those doubled
   the darkening -- the deep overlay problem. */
.hero::after { content: none; }

.hero > * {
    position: relative;
    z-index: 1;
}

.hero h1,
.hero .display-6 {
    color: var(--mh-white);
}

/* ==========================================================================
   Application — data density
   The content area stays deliberately neutral. Staff read these tables all
   day; brand colour here would compete with status colour, which is the
   only colour in the app that means anything.
   ========================================================================== */

.data-table th {
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--mh-muted);
    font-weight: 600;
    border-bottom: 2px solid var(--mh-border);
}

.data-table td { vertical-align: middle; }

/* Digits that must not be misread — IMEI, invoice and serial numbers.
   Tabular figures line the columns up and make a transposed digit visible. */
.numeric,
.imei,
.reference {
    font-variant-numeric: tabular-nums;
    font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
    font-size: 0.9375em;
}

.amount {
    font-variant-numeric: tabular-nums;
    text-align: right;
    white-space: nowrap;
}

/* ==========================================================================
   Status vocabulary — application only, semantic never decorative
   ========================================================================== */

.status {
    display: inline-block;
    padding: 0.2rem 0.55rem;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    white-space: nowrap;
}

.status-good    { background: #E3F2E6; color: #1E5B2A; }  /* available, paid, verified */
.status-wait    { background: #FDF1DC; color: #7A5410; }  /* reserved, awaiting parts */
.status-bad     { background: #FBE4E4; color: #8C1D1D; }  /* overdue, lost, damaged */
.status-active  { background: #E1ECF7; color: #1B4A76; }  /* under repair, lent */
.status-done    { background: #ECE9E4; color: #57493E; }  /* terminal: sold, closed */
.status-review  { background: var(--mh-review); color: var(--mh-review-ink); } /* needs a human */

/* ==========================================================================
   Utilities
   ========================================================================== */

[x-cloak] { display: none !important; }

/* Images must never reflow the page as they load. */
img { max-width: 100%; height: auto; }

/* ==========================================================================
   Clickable cards
   A card wrapped in a link with no hover state does not read as clickable,
   so people do not click it. Bootstrap gives no affordance here because it
   does not know the card is inside an anchor.
   ========================================================================== */

a:hover > .card,
a:focus-visible > .card {
    border-color: var(--mh-accent);
    box-shadow: 0 2px 10px rgba(43, 29, 20, 0.10);
    transform: translateY(-1px);
}

a > .card {
    transition: border-color 120ms ease, box-shadow 120ms ease, transform 120ms ease;
}

/* Respect a stated preference for less motion -- the lift is decoration,
   the border change carries the same information. */
@media (prefers-reduced-motion: reduce) {
    a > .card { transition: none; }
    a:hover > .card, a:focus-visible > .card { transform: none; }
}

/* Card headings inside links must not lose their colour to the link
   reset applied by .text-decoration-none. */
a.text-decoration-none .card { color: var(--mh-ink); }

/* ==========================================================================
   Device photography
   The box holds its shape whether or not a photograph exists, so cards do
   not resize as images are added. object-fit keeps an odd aspect ratio
   from distorting the handset.
   ========================================================================== */

.device-photo {
    width: 100%;
    background: var(--mh-page);
    border-bottom: 1px solid var(--mh-border);
    overflow: hidden;
}

.device-photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* Reads as "photo to come", not as a broken image. A plain grey box looks
   like a fault; this looks deliberate. */
.device-photo__placeholder {
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    background:
        repeating-linear-gradient(
            135deg,
            rgba(201, 162, 39, 0.05) 0 10px,
            rgba(201, 162, 39, 0.00) 10px 20px
        ),
        var(--mh-page);
}

.device-photo__initial {
    font-family: var(--mh-font-display);
    font-size: 2.5rem;
    line-height: 1;
    color: var(--mh-graphite);
    opacity: 0.35;
}

.device-photo__caption {
    font-size: 0.75rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--mh-muted);
}

/* ==========================================================================
   PUBLIC SITE — editorial layer
   --------------------------------------------------------------------------
   Scoped to .site-public so none of it reaches the staff application,
   where density matters more than drama and where brand colour would
   compete with the status vocabulary.
   ========================================================================== */

/* --- Type ramp -----------------------------------------------------------
   The previous scale ran 2.75 / 2 / 1.5 / 1 -- everything inside one
   narrow band, so nothing led. Headlines climb, body drops slightly, and
   the CONTRAST between them is what reads as modern. Headings tighten
   their leading; body loosens it. */

.site-public h1,
.site-public .display-6 {
    font-size: clamp(2.25rem, 4.5vw, 3.25rem);
    line-height: 1.06;
    letter-spacing: -0.02em;
}

.site-public .hero h1,
.site-public .hero .display-6 {
    font-size: clamp(2.5rem, 6vw, 4.25rem);
    line-height: 1.02;
}

.site-public h2 {
    font-size: clamp(1.6rem, 3vw, 2.25rem);
    line-height: 1.1;
    letter-spacing: -0.015em;
}

.site-public h3 { font-size: 1.25rem; line-height: 1.25; }

.site-public {
    font-size: 0.95rem;
    line-height: 1.65;
}

.site-public .lead {
    font-size: clamp(1.05rem, 1.6vw, 1.25rem);
    line-height: 1.55;
}

.site-public small,
.site-public .small { font-size: 0.8125rem; }

/* --- Eyebrow -------------------------------------------------------------
   The uppercase micro-label was written inline on the hero. Promoted to a
   real class so every section can lead with one, consistently. */

/* The base colour is the DARK-ground case: every light section overrides
   it to muted just below, so the hero is the only place this lands. The
   base accent is 3.99:1 there; the on-dark tint is 8.15:1. */
.eyebrow {
    display: block;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--mh-accent-on-dark);
    margin-bottom: 0.75rem;
}

.section-cream .eyebrow,
.section-white .eyebrow { color: var(--mh-muted); }

/* --- Surfaces ------------------------------------------------------------
   A border AND a shadow AND a radius on every card is the combination
   that dates a layout. On the website, cream against white separates
   perfectly well on its own. The application keeps its borders, because
   tables genuinely need the structure. */

.site-public .card,
.site-public .card-block {
    border: 0;
    box-shadow: none;
}

.site-public .section-cream .card {
    background: var(--mh-white);
}

.site-public .section-white .card {
    background: var(--mh-page);
}

/* Clickable cards still need an affordance without a border to change. */
.site-public a:hover > .card,
.site-public a:focus-visible > .card {
    box-shadow: 0 6px 24px rgba(43, 29, 20, 0.10);
    transform: translateY(-2px);
}

/* --- Interior spacing ----------------------------------------------------
   Cards were roomier inside than the gaps between sections, which is the
   wrong way round. Pull the insides in; the section rhythm token above
   pushes the outsides out. */

.site-public .card-body { padding: 1.5rem; }

@media (min-width: 992px) {
    .site-public .card-body { padding: 1.75rem; }
}

/* --- Rule ----------------------------------------------------------------
   Slightly finer and wider now that headings are larger, so it reads as a
   mark rather than an underline. */

.site-public .rule-gold {
    width: 2.5rem;
    border-top-width: 2px;
    margin-block: 0 1.25rem;
}

/* Closing call-to-action ground. Used once per page at most, which is
   what keeps it emphatic. */
.section-dark { background: var(--mh-graphite); color: var(--mh-muted-on-dark); }
.section-dark h1,
.section-dark h2,
.section-dark h3 { color: #FFFFFF; }
/* Base accent is 3.76:1 on near-black -- below the body-text floor.
   The lighter tint is 8.15:1. */
.section-dark a:not(.btn) { color: var(--mh-accent-on-dark); }
.section-dark .eyebrow { color: var(--mh-accent-on-dark); }

/* ==========================================================================
   Product gallery — thumbnail rail beside a large stage
   The radios are the state. They are visually hidden rather than
   display:none, so they stay reachable by keyboard and screen reader.
   ========================================================================== */

.pdp-gallery {
    display: grid;
    grid-template-columns: 84px 1fr;
    gap: 0.75rem;
    align-items: start;
}

.pdp-input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

.pdp-rail {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.pdp-thumb {
    display: block;
    cursor: pointer;
    border: 2px solid var(--mh-border);
    border-radius: var(--mh-radius);
    overflow: hidden;
    background: var(--mh-white);
    opacity: 0.65;
    transition: opacity 120ms ease, border-color 120ms ease;
}

.pdp-thumb:hover { opacity: 1; }

.pdp-thumb img {
    display: block;
    width: 100%;
    aspect-ratio: 1 / 1;
    object-fit: cover;
}

/* The selected thumbnail is keyboard-focusable through its radio; mirror
   the focus ring onto the label so it is visible. */
.pdp-input:focus-visible ~ .pdp-rail .pdp-thumb { outline: 3px solid var(--mh-accent); outline-offset: 2px; }

.pdp-stage {
    background: var(--mh-white);
    border-radius: var(--mh-radius);
    overflow: hidden;
}

.pdp-shot {
    display: none;
    width: 100%;
    height: auto;
    aspect-ratio: 1 / 1;
    object-fit: contain;
    background: var(--mh-white);
}

/* Phones get the rail underneath: a vertical strip beside a small stage
   would leave the product itself postage-stamp sized. */
@media (max-width: 575.98px) {
    .pdp-gallery { grid-template-columns: 1fr; }

    .pdp-rail {
        flex-direction: row;
        overflow-x: auto;
        order: 2;
        padding-bottom: 0.25rem;
    }

    .pdp-thumb { flex: 0 0 68px; }
    .pdp-stage { order: 1; }
}

/* ==========================================================================
   Specification block
   Dense and factual on purpose. Rules between rows rather than boxes
   around them, so a long list stays scannable without becoming a grid of
   containers.
   ========================================================================== */

.spec-group {
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--mh-muted);
    margin: 1.75rem 0 0.5rem;
}

.spec-group:first-child { margin-top: 0; }

.spec-list { margin: 0; }

.spec-row {
    display: grid;
    grid-template-columns: 40% 1fr;
    gap: 1rem;
    padding: 0.55rem 0;
    border-bottom: 1px solid var(--mh-border);
}

.spec-row dt {
    font-weight: 400;
    color: var(--mh-muted);
    font-size: 0.875rem;
}

.spec-row dd {
    margin: 0;
    font-weight: 500;
    font-size: 0.875rem;
}

/* ==========================================================================
   Brand filter chips
   ========================================================================== */

.brand-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.45rem 0.9rem;
    border: 1px solid var(--mh-border);
    border-radius: 999px;
    background: var(--mh-white);
    color: var(--mh-ink);
    font-size: 0.875rem;
    text-decoration: none;
    transition: border-color 120ms ease, background 120ms ease;
}

.brand-chip:hover { border-color: var(--mh-accent); color: var(--mh-ink); }

.brand-chip .numeric { color: var(--mh-muted); font-size: 0.8125rem; }

.brand-chip--on {
    background: var(--mh-graphite);
    border-color: var(--mh-graphite);
    color: #fff;
}

.brand-chip--on .numeric { color: var(--mh-accent-soft); }

/* ==========================================================================
   Hero — slow gradient drift
   Costs nothing: no JavaScript, no images, no extra bytes. 24s is long
   enough that it reads as depth rather than as something moving.
   ========================================================================== */

.hero-animated {
    background: linear-gradient(
        130deg,
        #000000 0%,
        #0A0A0B 26%,
        #1F1F23 50%,
        #0A0A0B 74%,
        #050506 100%
    );
    background-size: 300% 300%;
    animation: heroDrift 24s ease-in-out infinite;
}

@keyframes heroDrift {
    0%   { background-position: 0% 50%; }
    50%  { background-position: 100% 50%; }
    100% { background-position: 0% 50%; }
}

/* A single gold sheen crossing the hero, slowly. Sits under the text via
   the overlay that is already there. */
.hero-animated::before {
    content: '';
    position: absolute;
    inset: 0;
    background: radial-gradient(
        ellipse at 20% 30%,
        rgba(201, 162, 39, 0.16) 0%,
        rgba(201, 162, 39, 0) 55%
    );
    animation: heroSheen 30s ease-in-out infinite alternate;
}

@keyframes heroSheen {
    from { transform: translate3d(-6%, -4%, 0); opacity: 0.7; }
    to   { transform: translate3d(8%, 5%, 0); opacity: 1; }
}

/* Someone who has asked their device to stop moving things gets a still
   hero. The gradient stays; only the motion goes. */
@media (prefers-reduced-motion: reduce) {
    .hero-animated,
    .hero-animated::before {
        animation: none;
    }
}


/* ==========================================================================
   Product card -- framed photo, badges, body
   Details sit BELOW the photo, never on top of it. The previous version
   slid a dark gradient panel over the lower half of every picture, which
   is what made the shelf look muddy.
   ========================================================================== */

.pd-card {
    position: relative;
    overflow: hidden;
    transition: transform 180ms ease, box-shadow 180ms ease;
}

.pd-card:hover,
.pd-card:focus-within {
    transform: translateY(-2px);
    box-shadow: 0 10px 28px rgba(42, 33, 30, 0.10);
}

/* A tinted square so photos of any shape sit centred on one consistent
   surface instead of each dictating its own card height. */
.pd-card__frame {
    position: relative;
    background: var(--mh-surface-frame);
    border-radius: var(--mh-radius-md);
    overflow: hidden;
    margin: 0.5rem 0.5rem 0;
}

.pd-card__frame .device-photo {
    background: transparent;
    border-bottom: 0;
}

/* contain, not cover: a handset is never cropped to fill the box. The
   tinted frame fills whatever letterbox gap that leaves. */
.pd-card__frame .device-photo img {
    object-fit: contain;
}

.pd-card__badges {
    position: absolute;
    top: 0.5rem;
    left: 0.5rem;
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem;
    z-index: 2;
}

.pd-badge {
    font-size: 0.6875rem;
    font-weight: 700;
    line-height: 1;
    padding: 0.32rem 0.5rem;
    border-radius: var(--mh-radius-pill);
    white-space: nowrap;
}

/* Gold as a SURFACE carrying chocolate text (~8:1). Gold TEXT on this
   light frame would be ~2.5:1 and fail contrast -- see the file header. */
.pd-badge--grade {
    background: var(--mh-accent);
    color: var(--mh-white);
}

.pd-badge--battery {
    background: rgba(10, 10, 11, 0.82);
    color: #FFFFFF;
}

.pd-card__title {
    font-size: 0.9375rem;
    font-weight: 700;
    line-height: 1.3;
    margin-bottom: 0.15rem;
    color: var(--mh-ink);
}

.pd-card__meta {
    font-size: 0.8125rem;
    color: var(--mh-muted);
    margin-bottom: 0.75rem;
}

.pd-card__more {
    font-weight: 600;
    font-size: 0.8125rem;
    color: var(--mh-graphite);
}

.pd-card:hover .pd-card__more,
.pd-card:focus-within .pd-card__more {
    color: var(--mh-graphite-hover);
}

@media (prefers-reduced-motion: reduce) {
    .pd-card { transition: none; }
    .pd-card:hover,
    .pd-card:focus-within { transform: none; }
}

/* Hero video sits behind the overlay and text; the poster shows first. */
.hero-video {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    z-index: 0;
}
@media (prefers-reduced-motion: reduce) {
    /* Do not autoplay motion for someone who asked their device not to.
       The poster (CSS background) remains. */
    .hero-video { display: none; }
}

/* ==========================================================================
   Dashboard alignment
   The three dashboards (admin / manager / employee) hand-rolled their stat
   tiles with slightly different markup and sizes. These rules give every
   tile the same shape, typography and gold accent so the three read as one
   system, whether they use the <x-stat> component or the original
   .card-block.text-center markup.
   ========================================================================== */

/* The page heading, consistent across all three. */
main > .container > h1.h3,
main > .container > h1.h3:first-child {
    margin-bottom: 1.25rem;
}

/* Stat tiles — both the component and the legacy inline markup. */
.stat-tile,
.card-block.text-center {
    position: relative;
    border-top: 3px solid var(--mh-accent);
    min-height: 116px;
    transition: box-shadow 120ms ease, transform 120ms ease;
}

.stat-tile:hover,
.card-block.text-center:hover {
    box-shadow: 0 4px 16px rgba(43, 29, 20, 0.08);
    transform: translateY(-1px);
}

/* Label — small, muted, uppercase-ish. Targets the component and the
   legacy `.text-muted.small` first child inside a centred tile. */
.stat-tile__label,
.card-block.text-center .text-muted.small:first-child {
    font-size: 0.75rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--mh-muted);
    margin-bottom: 0.35rem;
}

/* Value — large, tabular, chocolate. Covers the component and the legacy
   .h4 / .display-6 the dashboards used. */
.stat-tile__value,
.card-block.text-center .h4,
.card-block.text-center .display-6 {
    font-family: var(--mh-font-display);
    font-size: 1.9rem;
    line-height: 1.1;
    color: var(--mh-graphite);
    font-variant-numeric: tabular-nums;
    margin-bottom: 0.15rem;
}

.stat-tile__sub {
    font-size: 0.8125rem;
    color: var(--mh-muted);
}

/* Panels (non-tile dashboard cards) get a consistent header rhythm. */
.card-block h2,
.card-block h5 {
    font-size: 1.05rem;
    margin-bottom: 0.75rem;
}

/* Social icon chips (footer & contact). */
.social-chip {
    width: 38px; height: 38px;
    border-radius: 50%;
    background: rgba(255,255,255,0.10);
    color: #F4F4F5;
    transition: background 120ms ease, color 120ms ease;
}
.social-chip:hover { background: var(--mh-accent); color: var(--mh-white); }
/* On light backgrounds (contact page) invert. */
.site-public section.section-white .social-chip,
.site-public .card .social-chip {
    background: var(--mh-page); color: var(--mh-graphite);
}
.site-public section.section-white .social-chip:hover,
.site-public .card .social-chip:hover { background: var(--mh-accent); }

/* Horizontal-overflow guard: the page body must never scroll sideways.
   overflow-x guard clips any stray wide element without creating a
   scroll container (so position:sticky still works). */
/* `clip` is Safari 16+ and misses older in-app WebViews entirely, where
   the declaration is dropped and any overflow then widens the document --
   which is what makes a phone lay the page out wide and scale it down to a
   narrow strip. `hidden` first is the floor every engine honours; `clip`
   wins where supported because it does not create a scroll container. */
html { overflow-x: hidden; overflow-x: clip; }
body.site-public { overflow-x: hidden; overflow-x: clip; max-width: 100%; }


/* Framed hero image — a bounded div that shows the WHOLE image (contain),
   so a tall/portrait upload is displayed fully instead of being cropped to
   a sliver by a full-width cover. The cream fills any letterbox gap. */
.hero-frame {
    max-width: 460px;
    margin-inline: auto;
    aspect-ratio: 4 / 5;
    max-height: 62vh;
    border-radius: var(--mh-radius-lg);
    overflow: hidden;
    background: var(--mh-page);
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.30);
}

.hero-frame img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    display: block;
}


/* ==========================================================================
   The public header must always sit above hero content. .hero > * gets
   z-index:1, and a tall framed hero can overflow its band; without this the
   invisible overflow captured every nav-link click. 1030 = the app overlay
   layer (matches the WhatsApp FAB), so the header always wins hit-testing.
   ========================================================================== */
.site-public .navbar {
    position: sticky;
    top: 0;
    z-index: 1030;
}

/* Accessory-category icon picker: a radio-per-icon grid where the
   checked state is shown with CSS only (adjacent-sibling selector),
   consistent with this app's no-unnecessary-JS approach. */
.icon-pick__input:checked + .icon-pick__box {
    border-color: var(--mh-accent) !important;
    border-width: 2px !important;
    background: var(--mh-accent-soft);
}

/* Inspection checklist rows (replaces toggle switches -- see
   inspections/inspection-form.blade.php). The whole row is the tap
   target; a failed item gets a visible red tint + border so it reads at
   a glance down a long list, not just from a small checkbox state. */
.inspection-item {
    cursor: pointer;
    border: 1px solid transparent;
    transition: background-color 0.15s ease, border-color 0.15s ease;
}

.inspection-item:hover {
    background: var(--mh-page);
}

.inspection-item--failed {
    background: #FDEDEC;
    border-color: #F1B6B0;
}

.inspection-item__check {
    width: 1.35em;
    height: 1.35em;
    margin-top: 0.15em;
}


/* ==========================================================================
   Plus Jakarta Sans -- self-hosted, single variable file
   Google serves ONE variable woff2 spanning the whole 200-800 weight axis;
   requesting 400 and 700 returns byte-identical files (verified by md5),
   so shipping one file and declaring the range costs 27KB, not 54KB.
   Only the `latin` subset is shipped -- latin-ext/vietnamese/cyrillic are
   unused here. font-display:swap paints text immediately in the fallback
   and never blocks on the font arriving, which matters on mobile data.
   ========================================================================== */
@font-face {
    font-family: 'Plus Jakarta Sans';
    src: url('../fonts/plus-jakarta-sans-variable.woff2') format('woff2');
    font-weight: 200 800;
    font-style: normal;
    font-display: swap;
}

/* ==========================================================================
   Public site typography + surface scale
   Scoped to .site-public: the staff application keeps system-ui and the
   tight 4px radius, because its dense tables are built around them. Only
   the public marketing site takes the editorial treatment.
   ========================================================================== */
body.site-public {
    font-family: var(--mh-font-sans);
    --bs-body-font-family: var(--mh-font-sans);

    --bs-border-radius: var(--mh-radius-md);
    --bs-border-radius-sm: var(--mh-radius-sm);
    --bs-border-radius-lg: var(--mh-radius-xl);
    --bs-border-radius-xl: var(--mh-radius-xl);
}

/* Headings drop Georgia for the sans stack. Weight and negative tracking
   carry the hierarchy now instead of a serif face. */
body.site-public h1,
body.site-public h2,
body.site-public h3,
body.site-public h4,
body.site-public h5,
body.site-public h6,
body.site-public .brand-mark,
body.site-public .display-6 {
    font-family: var(--mh-font-sans);
    font-weight: 700;
    letter-spacing: -0.02em;
    color: var(--mh-ink);
}

/* Hero and dark sections invert -- those headings sit on chocolate. */
body.site-public .hero h1,
body.site-public .hero h2,
body.site-public .hero .display-6,
body.site-public .section-dark h2,
body.site-public .section-dark h3 {
    color: var(--mh-white);
}

body.site-public .lead {
    font-weight: 400;
    color: var(--mh-muted);
}

/* The heading rule above also matches .brand-mark, which lives INSIDE the
   dark navbar -- inheriting ink there put the ink colour on the brand
   surface (~1.2:1,
   effectively invisible). The brand always sits on chocolate, so it is
   pinned light regardless of the heading colour. */
body.site-public .navbar .brand-mark,
body.site-public .navbar .brand-mark span {
    color: var(--mh-white);
}

/* Gold is a SURFACE, never text on a light ground (~2.5:1 -- below even
   the 3:1 large-text floor). A gold chip with chocolate text is ~8:1 and
   is the approved way to make a numeral or badge read as the accent. */
.accent-chip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--mh-accent);
    color: var(--mh-white);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    border-radius: var(--mh-radius-sm);
}


/* ==========================================================================
   Public header
   Compact bar, gold underline marking the current page, and one gold-ringed
   call to action. The layout's own comment always intended a single CTA on
   the bar; until now there was none.
   ========================================================================== */

body.site-public .navbar { padding-block: 0.5rem; }

body.site-public .navbar .nav-link {
    position: relative;
    font-size: 0.9375rem;
    font-weight: 500;
    color: #F4F4F5;
    padding-inline: 0.75rem;
}

body.site-public .navbar .nav-link:hover { color: #FFFFFF; }

/* The base rule sets active to gold !important, which on this dark bar is
   fine for contrast but reads as a second accent competing with the CTA.
   White text + a gold rule underneath separates "where I am" from
   "what to click". */
body.site-public .navbar .nav-link.active { color: #FFFFFF !important; }

body.site-public .navbar .nav-link.active::after {
    content: "";
    position: absolute;
    left: 0.75rem;
    right: 0.75rem;
    bottom: 0.1rem;
    height: 2px;
    border-radius: 2px;
    background: var(--mh-accent);
}

/* Outline CTA on the near-black bar. The base accent is 3.76:1 there --
   fine for the border, below the floor for the label -- so the label uses
   the lighter tint (8.15:1) while the border keeps the saturated hue. */
.navbar .btn-nav-cta {
    border: 1px solid var(--mh-accent);
    color: var(--mh-accent-on-dark);
    font-weight: 600;
    font-size: 0.875rem;
    line-height: 1.2;
    border-radius: var(--mh-radius-pill);
    padding: 0.45rem 1.05rem;
    white-space: nowrap;
    transition: background-color 160ms ease, color 160ms ease;
}

.navbar .btn-nav-cta:hover,
.navbar .btn-nav-cta:focus-visible {
    background: var(--mh-accent);
    color: var(--mh-white);
}

@media (prefers-reduced-motion: reduce) {
    .navbar .btn-nav-cta { transition: none; }
}

/* ==========================================================================
   Homepage hero -- asymmetric two column
   Left: type and CTAs. Right: a frosted panel showing live stock.
   ========================================================================== */

.hero-pills {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-bottom: 1.75rem;
}

.hero-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.8125rem;
    font-weight: 600;
    color: #F4F4F5;
    background: rgba(255, 255, 255, 0.08);
    border: 1px solid rgba(197, 160, 89, 0.38);
    border-radius: var(--mh-radius-pill);
    padding: 0.4rem 0.85rem;
}

.hero-pill svg { color: var(--mh-accent); flex-shrink: 0; }

/* Frosted panel over the drifting gradient. backdrop-filter is applied
   progressively: with no support the translucent background alone still
   reads correctly, so nothing breaks. */
.hero-stock {
    background: rgba(255, 255, 255, 0.07);
    -webkit-backdrop-filter: blur(14px);
    backdrop-filter: blur(14px);
    border: 1px solid rgba(255, 255, 255, 0.16);
    border-radius: var(--mh-radius-xl);
    padding: 1.5rem;
    box-shadow: 0 18px 44px rgba(0, 0, 0, 0.24);
}

.hero-stock__label {
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    /* Hero only, so always on the dark ground. */
    color: var(--mh-accent-on-dark);
}

.hero-stock__count {
    font-size: clamp(2.5rem, 6vw, 3.5rem);
    font-weight: 700;
    line-height: 1;
    letter-spacing: -0.03em;
    color: #FFFFFF;
    font-variant-numeric: tabular-nums;
}

.hero-stock__sub { font-size: 0.875rem; color: var(--mh-muted-on-dark); }

.hero-stock__thumbs {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0.5rem;
}

.hero-stock__thumb {
    aspect-ratio: 1;
    border-radius: var(--mh-radius-sm);
    overflow: hidden;
    background: rgba(255, 255, 255, 0.10);
}

.hero-stock__thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}


/* ==========================================================================
   Top 10 by fans -- ranked grid
   The bar length is real: each entry is scaled against the top entry's
   enquiry count, from device_variant_metrics. The whole section is gated
   on hasMeaningfulSignal(), so it hides rather than dressing up noise.
   ========================================================================== */

.rank-row {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    padding: 0.8rem 0;
    border-bottom: 1px solid var(--mh-border);
}

.rank-row:last-child { border-bottom: 0; }

/* .accent-chip supplies white-on-accent (5.26:1). The accent AS TEXT on
   white is 5.26:1 too, so unlike the gold this replaces it would also be
   legible -- the chip is now a choice, not a workaround. */
.rank-num {
    flex-shrink: 0;
    width: 2.4rem;
    height: 2.4rem;
    font-size: 0.9375rem;
}

.rank-body { flex-grow: 1; min-width: 0; }

.rank-name {
    font-size: 0.9375rem;
    font-weight: 700;
    color: var(--mh-ink);
    line-height: 1.3;
}

.rank-meta { font-size: 0.8125rem; color: var(--mh-muted); }

.rank-bar {
    height: 5px;
    border-radius: var(--mh-radius-pill);
    background: var(--mh-border);
    overflow: hidden;
    margin-top: 0.45rem;
}

.rank-bar__fill {
    display: block;
    height: 100%;
    border-radius: var(--mh-radius-pill);
    background: var(--mh-accent);
}

/* ==========================================================================
   Value tiles -- "Why buy from us" / About
   Replaces em-dash bullets with an icon grid.
   ========================================================================== */

.value-icon {
    width: 46px;
    height: 46px;
    border-radius: var(--mh-radius-md);
    background: var(--mh-surface-icon);
    /* Espresso glyph, not gold: gold on this pale tile is ~2.2:1 and the
       icon would all but vanish. The brief allows either; espresso is the
       one that can actually be seen. */
    color: var(--mh-graphite);
    display: grid;
    place-items: center;
    margin-bottom: 0.85rem;
}

.value-tile__text {
    font-size: 0.9375rem;
    line-height: 1.5;
    color: var(--mh-ink);
}

/* ==========================================================================
   Framed photography -- About and marketing pages
   ========================================================================== */

.site-figure {
    border-radius: var(--mh-radius-xl) !important;
    border: 1px solid var(--mh-border);
    box-shadow: 0 1px 3px rgba(42, 33, 30, 0.06);
}


/* ==========================================================================
   Micro-interactions
   Everything here is decorative and sits behind a reduced-motion guard.
   ========================================================================== */

/* Gold focus ring. Bootstrap's default is a blue glow that has nothing to
   do with this palette. Focus stays clearly visible -- this replaces the
   ring's colour, never its presence. */
body.site-public .form-control:focus,
body.site-public .form-select:focus,
body.site-public .form-check-input:focus,
body.site-public .btn:focus-visible {
    border-color: var(--mh-accent);
    box-shadow: 0 0 0 0.2rem rgba(197, 160, 89, 0.30);
}

body.site-public .form-check-input:checked {
    background-color: var(--mh-graphite);
    border-color: var(--mh-graphite);
}

/* WhatsApp floating button -- a slow ring that breathes outward, so the
   button reads as live without ever moving from under the thumb. The ring
   is a ::before so it cannot intercept the tap. */
.wa-fab { position: fixed; }

.wa-fab::before {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: 50%;
    border: 2px solid #25D366;
    animation: wa-ring 2.8s ease-out infinite;
    pointer-events: none;
}

@keyframes wa-ring {
    0%   { transform: scale(1);   opacity: 0.55; }
    70%  { transform: scale(1.5); opacity: 0; }
    100% { transform: scale(1.5); opacity: 0; }
}

/* Cards that are whole links lift slightly on hover. */
.card-lift {
    transition: transform 180ms ease, box-shadow 180ms ease;
}

.card-lift:hover,
.card-lift:focus-within {
    transform: translateY(-2px);
    box-shadow: 0 10px 28px rgba(42, 33, 30, 0.10);
}

@media (prefers-reduced-motion: reduce) {
    .wa-fab::before { animation: none; opacity: 0; }
    .card-lift { transition: none; }
    .card-lift:hover,
    .card-lift:focus-within { transform: none; }
}


/* ==========================================================================
   STAFF APP -- mobile chrome
   Brand colour lives in the chrome (top bar, bottom bar, FAB); the content
   area stays neutral so STATUS colour keeps its meaning. That rule is the
   one this file's header already states for the app surface.

   All of this is scoped to body.site-app and shown below lg only: a thumb
   bar pinned to the bottom of a 27-inch monitor is a worse tool, not a
   better one, so desktop keeps the dropdown navbar.
   ========================================================================== */

:root {
    --mh-top-h: 56px;
    --mh-bottom-h: 64px;
}

/* Touch target floor. BRD §43.6 asked for 44px; this app is used one-handed
   at a counter, so 48px. .btn-touch existed already but was applied almost
   nowhere -- below it is applied to real controls. */
.btn-lg,
.btn-touch { min-height: 48px; }

@media (max-width: 991.98px) {
    body.site-app {
        padding-top: var(--mh-top-h);
        /* Bottom bar + the iPhone home indicator. */
        padding-bottom: calc(var(--mh-bottom-h) + env(safe-area-inset-bottom, 0px));
    }

    /* Controls are thumb-sized on mobile whether or not a view remembered
       to add .btn-touch. */
    body.site-app .btn,
    body.site-app .form-control,
    body.site-app .form-select {
        min-height: 48px;
    }

    body.site-app .form-select {
        background-size: 18px 14px;
    }

    body.site-app main.container {
        padding-top: 1rem !important;
        padding-bottom: 1rem !important;
    }
}

.mchrome-top {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: var(--mh-top-h);
    z-index: 1035;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0 0.85rem;
    background: var(--mh-graphite);
    color: #FFFFFF;
    border-bottom: 2px solid var(--mh-accent);
}

.mchrome-top__brand {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-width: 0;
    color: #FFFFFF;
    text-decoration: none;
    font-weight: 700;
    font-size: 0.9375rem;
    letter-spacing: -0.01em;
}

.mchrome-top__brand img { border-radius: 50%; display: block; flex-shrink: 0; }

.mchrome-top__brand span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mchrome-status {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.6875rem;
    font-weight: 600;
    color: var(--mh-muted-on-dark);
    white-space: nowrap;
}

.mchrome-status__dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #3FB56B;
    flex-shrink: 0;
}

.mchrome-status.is-offline .mchrome-status__dot { background: #D9534F; }
.mchrome-status.is-offline { color: #F3C9C7; }

/* The role badge is the first thing to go when the brand name is long. */
@media (max-width: 400px) {
    .mchrome-role { display: none; }
    .mchrome-status__text { display: none; }
}

.mchrome-bottom {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1035;
    display: flex;
    align-items: stretch;
    height: calc(var(--mh-bottom-h) + env(safe-area-inset-bottom, 0px));
    padding-bottom: env(safe-area-inset-bottom, 0px);
    background: var(--mh-graphite);
    border-top: 1px solid rgba(255, 255, 255, 0.12);
}

.mchrome-tab {
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.15rem;
    padding: 0.35rem 0.25rem;
    background: none;
    border: 0;
    color: #C9BCB1;
    text-decoration: none;
    font-size: 0.6875rem;
    font-weight: 600;
    line-height: 1.1;
    min-width: 0;
    transition: color 120ms ease, transform 120ms ease;
}

.mchrome-tab svg { width: 22px; height: 22px; }

.mchrome-tab.is-active { color: var(--mh-accent); }

/* Pressed state -- the brief asked for a clear active/pressed cue. */
.mchrome-tab:active { transform: scale(0.94); }

.mchrome-fab {
    position: fixed;
    right: 1rem;
    bottom: calc(var(--mh-bottom-h) + env(safe-area-inset-bottom, 0px) + 0.85rem);
    z-index: 1036;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.5rem;
}

.mchrome-fab__button {
    width: 56px;
    height: 56px;
    border-radius: 50%;
    border: 0;
    background: var(--mh-accent);
    color: var(--mh-white);
    display: grid;
    place-items: center;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.28);
    transition: transform 140ms ease;
}

.mchrome-fab__button svg { width: 26px; height: 26px; transition: transform 160ms ease; }
.mchrome-fab__button:active { transform: scale(0.94); }

/* The dial. Items are positioned from the button's own corner and fan
   out along a shallow arc: --index drives both how far up (linear) and
   how far left (quadratic, which is what makes it read as a curve).

   The arc stays shallow on purpose. Fanning across a true quarter turn
   puts items at similar heights and their labels then collide; keeping
   the vertical rhythm means the lean reads as a curve while every label
   stays legible. Three actions in a shop need words -- staff should not
   have to tap an icon to discover what it does. */
.mchrome-fab__menu {
    position: absolute;
    right: 4px;
    bottom: 4px;
}

.mchrome-fab__item {
    position: absolute;
    right: 0;
    bottom: 0;
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    background: var(--mh-white);
    color: var(--mh-ink);
    border: 1px solid var(--mh-border);
    border-radius: var(--mh-radius-pill);
    padding: 0.6rem 1rem;
    font-size: 0.875rem;
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.16);

    /* closed: tucked under the trigger, and out of the tab order */
    visibility: hidden;
    opacity: 0;
    transform: translate(0, 0) scale(0.4);
    transition:
        transform 320ms cubic-bezier(0.34, 1.56, 0.64, 1),
        opacity 160ms ease,
        visibility 0s linear 320ms;
}

.mchrome-fab__item svg { width: 18px; height: 18px; flex: none; }

.mchrome-fab.is-open .mchrome-fab__item {
    visibility: visible;
    opacity: 1;
    transform:
        translate(
            calc(var(--index) * var(--index) * -5px),
            calc(var(--index) * -52px - 16px)
        )
        scale(1);
    /* later items leave slightly after earlier ones, so the group
       unfolds rather than appearing all at once */
    transition-delay: calc(var(--index) * 45ms), calc(var(--index) * 45ms), 0s;
}

.mchrome-fab__item:hover,
.mchrome-fab__item:focus-visible {
    border-color: var(--mh-accent);
    color: var(--mh-ink);
}

.mchrome-fab__item:active { filter: brightness(0.97); }

/* The trigger shrinks as the menu opens -- reference 2's tell that the
   button has handed its job over to the items. */
.mchrome-fab.is-open .mchrome-fab__button {
    transform: scale(0.85);
}

.mchrome-fab.is-open .mchrome-fab__button svg {
    transform: rotate(45deg);
}

[x-cloak] { display: none !important; }

.mchrome-more__group { padding-block: 0.6rem; border-bottom: 1px solid var(--mh-border); }
.mchrome-more__group:last-of-type { border-bottom: 0; }

.mchrome-more__heading {
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--mh-muted);
    margin-bottom: 0.35rem;
}

.mchrome-more__link {
    display: block;
    padding: 0.7rem 0.25rem;
    min-height: 48px;
    color: var(--mh-ink);
    text-decoration: none;
    font-weight: 500;
    border-radius: var(--mh-radius);
}

.mchrome-more__link.is-active { color: var(--mh-graphite); font-weight: 700; }
.mchrome-more__link:active { background: var(--mh-page); }

@media (prefers-reduced-motion: reduce) {
    .mchrome-tab,
    .mchrome-fab__button,
    .mchrome-fab__button svg { transition: none; }

    /* No fan, no overshoot, no stagger -- items simply appear where
       they belong. Position is layout, not animation, so it stays. */
    .mchrome-fab__item {
        transition: none;
        transform: translate(
            calc(var(--index) * var(--index) * -5px),
            calc(var(--index) * -52px - 16px)
        ) scale(1);
    }

    .mchrome-fab.is-open .mchrome-fab__item { transition-delay: 0s; }
    .mchrome-fab.is-open .mchrome-fab__button { transform: none; }
    .mchrome-tab:active,
    .mchrome-fab__button:active,
    .mchrome-fab__item:active { transform: none; }
}


/* ==========================================================================
   STAFF APP -- record cards + sticky search
   Replaces the wide tables. A row of six columns forces a horizontal
   scroll on a phone, which is the one gesture that loses your place in a
   list; a card puts the same fields in reading order instead.
   ========================================================================== */

.rec-search {
    position: sticky;
    top: 0;
    /* Below Bootstrap's .dropdown-menu (1000). At 1020 this bar drew OVER
       the header menus and clipped them. It only needs to sit above list
       content -- never above navigation. */
    z-index: 990;
    background: var(--bs-body-bg);
    padding-block: 0.6rem;
    margin-bottom: 0.75rem;
}

@media (max-width: 991.98px) {
    /* Clear the fixed 56px top bar. */
    .rec-search { top: var(--mh-top-h); }
}

.rec-list { display: flex; flex-direction: column; gap: 0.6rem; }

.rec-card {
    display: block;
    position: relative;
    background: var(--mh-white);
    border: 1px solid var(--mh-border);
    border-radius: var(--mh-radius-md);
    padding: 0.85rem 0.95rem;
    text-decoration: none;
    color: inherit;
    transition: border-color 140ms ease, box-shadow 140ms ease, transform 140ms ease;
}

.rec-card:hover,
.rec-card:focus-visible {
    border-color: var(--mh-graphite);
    box-shadow: 0 4px 14px rgba(42, 33, 30, 0.08);
}

.rec-card:active { transform: scale(0.99); }

.rec-card__top {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.75rem;
}

.rec-card__name {
    font-weight: 700;
    font-size: 0.9375rem;
    color: var(--mh-ink);
    line-height: 1.3;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.rec-card__amount {
    font-weight: 700;
    font-size: 0.9375rem;
    color: var(--mh-ink);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    flex-shrink: 0;
}

.rec-card__mid {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem 0.5rem;
    margin-top: 0.2rem;
    font-size: 0.8125rem;
    color: var(--mh-muted);
}

.rec-card__ref { font-variant-numeric: tabular-nums; }

.rec-card__bottom {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin-top: 0.7rem;
}

.rec-card__more {
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--mh-graphite);
    white-space: nowrap;
}

.rec-empty {
    text-align: center;
    padding: 2.5rem 1rem;
    color: var(--mh-muted);
}

@media (prefers-reduced-motion: reduce) {
    .rec-card { transition: none; }
    .rec-card:active { transform: none; }
}


/* ==========================================================================
   STAFF APP -- POS sticky order summary
   Sits ABOVE the bottom nav rather than covering it: a form that hides
   the way out is a trap. Extra body clearance comes from .has-pos-footer.
   ========================================================================== */

.pos-footer {
    position: fixed;
    left: 0;
    right: 0;
    bottom: calc(var(--mh-bottom-h) + env(safe-area-inset-bottom, 0px));
    z-index: 1030;
    background: var(--mh-white);
    border-top: 1px solid var(--mh-border);
    box-shadow: 0 -6px 20px rgba(42, 33, 30, 0.10);
    padding: 0.7rem 0.9rem 0.8rem;
}

.pos-footer__lines {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    margin-bottom: 0.6rem;
}

.pos-footer__line {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    font-size: 0.8125rem;
    color: var(--mh-muted);
}

.pos-footer__line--total {
    font-size: 1.0625rem;
    font-weight: 700;
    color: var(--mh-ink);
    padding-top: 0.3rem;
    margin-top: 0.15rem;
    border-top: 1px solid var(--mh-border);
}

.pos-footer__line--due { color: #8C1D1D; font-weight: 700; }

.pos-footer__actions { display: flex; gap: 0.5rem; }

.has-pos-footer { padding-bottom: 11rem; }

/* On desktop the bottom nav is hidden, so the bar sits on the floor and
   the summary can be a single row. */
@media (min-width: 992px) {
    .pos-footer {
        bottom: 0;
        display: flex;
        align-items: center;
        justify-content: flex-end;
        gap: 1.5rem;
        padding-inline: 2rem;
    }
    .pos-footer__lines {
        flex-direction: row;
        align-items: baseline;
        gap: 1.5rem;
        margin-bottom: 0;
    }
    .pos-footer__line { gap: 0.5rem; }
    .pos-footer__line--total { border-top: 0; padding-top: 0; margin-top: 0; }
    .pos-footer__actions { flex: 0 0 auto; }
    .has-pos-footer { padding-bottom: 7rem; }
}


/* ==========================================================================
   IMEI camera scan
   ========================================================================== */

.imei-scan__btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 48px;
    flex-shrink: 0;
}

.imei-scan__stage {
    position: relative;
    width: 100%;
    aspect-ratio: 4 / 3;
    background: #000;
    border-radius: var(--mh-radius-md);
    overflow: hidden;
}

.imei-scan__stage video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* A visible target: without it people hold the phone too far back and
   assume the scanner is broken. */
.imei-scan__reticle {
    position: absolute;
    left: 8%;
    right: 8%;
    top: 38%;
    height: 24%;
    border: 2px solid var(--mh-accent);
    border-radius: var(--mh-radius-sm);
    box-shadow: 0 0 0 100vmax rgba(0, 0, 0, 0.35);
}


/* ==========================================================================
   STAFF APP -- dashboard
   Two columns of KPI chips on a phone, four on a laptop. The numbers are
   the screen; everything else is secondary.
   ========================================================================== */

.kpi-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 0.6rem;
}

@media (min-width: 992px) {
    .kpi-grid { grid-template-columns: repeat(4, 1fr); }
}

.kpi-chip {
    display: block;
    background: var(--mh-white);
    border: 1px solid var(--mh-border);
    border-radius: var(--mh-radius-md);
    padding: 0.8rem 0.85rem;
    text-decoration: none;
    color: inherit;
    min-height: 88px;
}

.kpi-chip__label {
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--mh-muted);
    line-height: 1.2;
}

.kpi-chip__value {
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1.15;
    letter-spacing: -0.02em;
    color: var(--mh-ink);
    font-variant-numeric: tabular-nums;
    margin-top: 0.2rem;
}

.kpi-chip__sub { font-size: 0.75rem; color: var(--mh-muted); }

/* Money owed to the shop is the one number that should never blend in. */
.kpi-chip--alert { border-color: #E7B4B1; background: #FDF6F5; }
.kpi-chip--alert .kpi-chip__value { color: #8C1D1D; }
.kpi-chip--alert .kpi-chip__label { color: #8C1D1D; }

/* Quick actions -- a single scrollable row rather than a wrapping block,
   so it never pushes the KPIs off the first screen. */
.qa-row {
    display: flex;
    gap: 0.5rem;
    overflow-x: auto;
    padding-block: 0.15rem;
    margin-block: 0.9rem;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
}

.qa-row::-webkit-scrollbar { display: none; }

.qa-pill {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    background: var(--mh-white);
    border: 1px solid var(--mh-border);
    border-radius: var(--mh-radius-pill);
    padding: 0.5rem 0.9rem;
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--mh-ink);
    text-decoration: none;
    white-space: nowrap;
    min-height: 40px;
}

.qa-pill__count {
    background: var(--mh-accent);
    color: var(--mh-white);
    border-radius: var(--mh-radius-pill);
    padding: 0.05rem 0.45rem;
    font-size: 0.75rem;
    font-variant-numeric: tabular-nums;
}

.qa-pill:active { transform: scale(0.97); }

/* Stock segments -- a bar each, proportional to the largest segment, so
   the shape of the shelf reads at a glance. */
.seg-row {
    display: grid;
    grid-template-columns: 5.5rem 1fr auto;
    align-items: center;
    gap: 0.6rem;
    padding-block: 0.4rem;
}

.seg-row__label { font-size: 0.8125rem; color: var(--mh-muted); }

.seg-row__track {
    height: 8px;
    background: var(--mh-page);
    border: 1px solid var(--mh-border);
    border-radius: var(--mh-radius-pill);
    overflow: hidden;
}

.seg-row__fill {
    display: block;
    height: 100%;
    background: var(--mh-graphite);
    border-radius: var(--mh-radius-pill);
}

.seg-row__count {
    font-weight: 700;
    font-size: 0.875rem;
    font-variant-numeric: tabular-nums;
    color: var(--mh-ink);
    min-width: 2.5rem;
    text-align: right;
}

.dash-list { list-style: none; margin: 0; padding: 0; }

.dash-list li {
    display: flex;
    justify-content: space-between;
    gap: 0.75rem;
    padding-block: 0.55rem;
    border-bottom: 1px solid var(--mh-border);
    font-size: 0.875rem;
}

.dash-list li:last-child { border-bottom: 0; }

.dash-time {
    font-variant-numeric: tabular-nums;
    color: var(--mh-muted);
    font-size: 0.8125rem;
    white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
    .qa-pill:active { transform: none; }
}


/* Bootstrap's .stretched-link::after covers the whole card at z-index 1,
   which swallowed taps on any control nested inside the card. These have
   to sit above that overlay or they are simply dead -- verified by
   hit-testing elementFromPoint at each control centre. */
.rec-card__actions {
    position: relative;
    z-index: 2;
    display: flex;
    gap: 0.5rem;
    align-items: center;
}


/* An expired reservation is the one row in these lists that needs to
   stand out before it is read. */
.rec-card--alert {
    border-color: #E7B4B1;
    background: #FDF6F5;
}


/* ==========================================================================
   STAFF APP -- invoice financial callout + action bar
   ========================================================================== */

.inv-callout { border-width: 2px; }

.inv-callout__row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
    padding-block: 0.4rem;
    font-size: 0.9375rem;
    color: var(--mh-muted);
}

.inv-callout__net {
    font-size: 1.25rem;
    font-weight: 700;
    color: var(--mh-ink);
    font-variant-numeric: tabular-nums;
}

.inv-callout__row--paid span:last-child {
    color: #1E5B2A;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.inv-callout__row--due {
    border-top: 1px solid var(--mh-border);
    margin-top: 0.3rem;
    padding-top: 0.6rem;
}

.inv-callout__row--due span:last-child {
    color: #8C1D1D;
    font-weight: 700;
    font-size: 1.25rem;
    font-variant-numeric: tabular-nums;
}

.inv-callout__row--settled span:last-child { color: #1E5B2A; font-weight: 600; }

/* Full-width stack on a phone, a row once there is space. */
.inv-actions {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin-top: 1rem;
}

.inv-actions .btn { width: 100%; }

@media (min-width: 768px) {
    .inv-actions { flex-direction: row; flex-wrap: wrap; }
    .inv-actions .btn { width: auto; flex: 1 1 auto; }
}


/* Demand: comparative metrics, so a proportional bar per model rather
   than a card each -- the question is which model is wanted most. Reuses
   .rank-bar from the public Top 10. */
.demand-row {
    padding-block: 0.7rem;
    border-bottom: 1px solid var(--mh-border);
}

.demand-row:last-child { border-bottom: 0; }

.demand-row__head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 0.75rem;
}

.demand-row__name {
    font-size: 0.9375rem;
    font-weight: 700;
    color: var(--mh-ink);
}

.demand-row__rate {
    font-weight: 700;
    font-size: 0.875rem;
    color: var(--mh-ink);
    white-space: nowrap;
}

.demand-row__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.35rem 0.5rem;
    margin-top: 0.35rem;
    font-size: 0.8125rem;
    color: var(--mh-muted);
}


/* ==========================================================================
   PUBLIC -- services page: trust pills, offering cards, repair grid
   ========================================================================== */

.trust-pills { display: flex; flex-wrap: wrap; gap: 0.5rem; }

.trust-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--mh-ink);
    background: var(--mh-surface-icon);
    border: 1px solid var(--mh-border);
    border-radius: var(--mh-radius-pill);
    padding: 0.45rem 0.9rem;
}

.trust-pill svg { color: var(--mh-graphite); flex-shrink: 0; }

.svc-card { transition: transform 180ms ease, box-shadow 180ms ease; }

.svc-card:hover,
.svc-card:focus-within {
    transform: translateY(-2px);
    box-shadow: 0 10px 28px rgba(42, 33, 30, 0.10);
}

.svc-card__num {
    display: block;
    font-weight: 700;
    font-size: 0.8125rem;
    color: var(--mh-accent);
    margin-bottom: 0.4rem;
}

.svc-card__cta {
    font-weight: 600;
    font-size: 0.875rem;
    color: var(--mh-graphite);
    text-decoration: none;
}

.svc-card__cta:hover { color: var(--mh-graphite-hover); text-decoration: underline; }

/* Risk reversal reads as reassurance, not as a warning -- gold on cream,
   never red. */
.risk-banner {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    background: var(--mh-surface-icon);
    border: 1px solid var(--mh-accent);
    border-radius: var(--mh-radius-md);
    padding: 0.85rem 1rem;
    font-size: 0.9375rem;
    color: var(--mh-ink);
}

.risk-banner svg { color: var(--mh-graphite); flex-shrink: 0; }

.proc-step {
    display: flex;
    gap: 1rem;
    padding-block: 0.9rem;
    border-bottom: 1px solid var(--mh-border);
}

.proc-step:last-child { border-bottom: 0; }

.proc-step__num {
    flex-shrink: 0;
    font-weight: 700;
    color: var(--mh-accent);
    min-width: 2rem;
}

.fix-card__icon {
    display: grid;
    place-items: center;
    width: 44px;
    height: 44px;
    border-radius: var(--mh-radius-md);
    background: var(--mh-surface-icon);
    color: var(--mh-graphite);
    margin-bottom: 0.7rem;
}

/* WhatsApp keeps its own brand green -- substituting the shop's gold here
   would make the one button people recognise instantly unrecognisable. */
.btn-whatsapp {
    background: #25D366;
    border-color: #25D366;
    color: #0B2E13;
    font-weight: 600;
}

.btn-whatsapp:hover,
.btn-whatsapp:focus {
    background: #1FBA59;
    border-color: #1FBA59;
    color: #0B2E13;
}

@media (prefers-reduced-motion: reduce) {
    .svc-card { transition: none; }
    .svc-card:hover,
    .svc-card:focus-within { transform: none; }
}


/* ==========================================================================
   PUBLIC -- About: inspection media card
   Sticky on large screens so the photograph stays alongside the seven
   stages rather than scrolling away after the second one.
   ========================================================================== */

.inspect-media {
    position: relative;
    aspect-ratio: 3 / 4;
    border-radius: var(--mh-radius-xl);
    overflow: hidden;
    border: 1px solid var(--mh-border);
    box-shadow: 0 8px 28px rgba(42, 33, 30, 0.10);
    background: var(--mh-surface-frame);
}

.inspect-media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.inspect-media__badge {
    position: absolute;
    left: 0.75rem;
    right: 0.75rem;
    bottom: 0.75rem;
    display: flex;
    align-items: center;
    gap: 0.45rem;
    background: rgba(62, 39, 35, 0.92);
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
    color: #FFFFFF;
    font-size: 0.8125rem;
    font-weight: 600;
    border-radius: var(--mh-radius-md);
    padding: 0.6rem 0.8rem;
}

.inspect-media__badge svg { color: var(--mh-accent); flex-shrink: 0; }

@media (min-width: 992px) {
    .inspect-media { position: sticky; top: 5.5rem; }
}


/* From lg up there is no bottom nav to clear, so the FAB drops to a plain
   margin. (The FAB sits clear of the bottom bar on mobile via the
   --mh-bottom-h offset in its base rule.) */
@media (min-width: 992px) {
    /* No bottom bar at this width, so nothing to clear. --mh-bottom-h is
       collapsed below for the same reason: every element offset by it was
       floating 64px above the window for a bar that is not rendered. */
    :root {
        --mh-bottom-h: 0px;
    }

    .mchrome-fab {
        right: 1.5rem;
        bottom: 1.5rem;
    }
}

/* A page with its own primary action bar does not get a floating button
   over the top of it. The FAB is "start something new"; halfway through
   a sale that is both in the way and the wrong offer.

   :has() rather than a body class because these bars are Alpine-driven --
   a browser too old for :has() cannot render the totals in them
   anyway. */
body:has(.pos-footer) .mchrome-fab,
body:has(.exch-settle) .mchrome-fab {
    display: none;
}


/* --------------------------------------------------------------------------
   Brand mark on a dark bar
   --------------------------------------------------------------------------
   The logo is a chocolate circle on a white JPEG square. Against the old
   chocolate navbar it read fine; against near-black it is ~1.9:1 and
   effectively disappears.

   Rather than recolour someone's brand mark, it sits on a white disc --
   which is what the artwork already assumes, since the JPEG's own ground
   is white. The padding keeps the mark off the edge so the disc reads as
   a deliberate badge rather than a rendering accident.
   -------------------------------------------------------------------------- */
.brand-logo {
    display: block;
    border-radius: 50%;
    background: var(--mh-white);
    padding: 2px;
    box-sizing: content-box;
}


/* ==========================================================================
   Offer band — public homepage, directly below the hero
   --------------------------------------------------------------------------
   Measured pairings (WCAG, computed not eyeballed):

     ink   #0A0A0B on accent-soft #E3EBFF   16.58:1  body text
     muted #52525B on accent-soft           6.48:1   supporting text
     white #FFFFFF on accent   #0B5CFF      5.26:1   the flag chip

   The solid accent is NOT used as a text ground here: ink on #0B5CFF is
   3.76:1, below the floor. Accent-coloured text on accent-soft is 4.41:1
   and is likewise avoided.

   The band renders only when an offer is live (see the component), so
   these rules are inert on a homepage with nothing running.
   ========================================================================== */
.offer-band {
    background: var(--mh-accent-soft);
    border-block: 1px solid rgba(11, 92, 255, 0.18);
    padding-block: clamp(1.1rem, 2.5vw, 1.6rem);
}

.offer-band__single {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.5rem 0.9rem;
}

/* Small caps on a saturated chip: the one place the solid accent is a
   ground, and it carries white. */
.offer-band__flag {
    display: inline-block;
    flex-shrink: 0;
    background: var(--mh-accent);
    color: var(--mh-white);
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    padding: 0.2rem 0.55rem;
    border-radius: var(--mh-radius-pill);
}

.offer-band__title {
    color: var(--mh-ink);
    font-weight: 650;
    font-size: clamp(1rem, 2vw, 1.15rem);
    line-height: 1.35;
}

.offer-band__body,
.offer-card__body {
    color: var(--mh-muted);
    font-size: 0.9rem;
    line-height: 1.45;
}

/* Not a countdown. A quiet date, so an offer that is ending reads as
   information rather than pressure. */
.offer-band__until {
    color: var(--mh-muted);
    font-size: 0.8rem;
    white-space: nowrap;
}

.offer-card {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    align-items: flex-start;
    background: var(--mh-white);
    border: 1px solid rgba(11, 92, 255, 0.18);
    border-radius: var(--mh-radius-md);
    padding: 1rem 1.1rem;
}

.offer-card__title {
    color: var(--mh-ink);
    font-weight: 650;
    line-height: 1.35;
}


/* ==========================================================================
   Trust band — risk reversal, stated as promises
   --------------------------------------------------------------------------
   Measured: ink #0A0A0B on surface-frame #F4F4F5 is 18.6:1; muted
   #52525B on the same is 7.3:1. The tick is the accent used as a MARK,
   not as text, so its 5.26:1 on white is comfortably clear of the 3:1
   floor for graphical objects.
   ========================================================================== */
.trust-band {
    padding-block: clamp(1.5rem, 3.5vw, 2.25rem);
}

.trust-band--light { background: var(--mh-surface-frame); }
.trust-band--white { background: var(--mh-white); border-block: 1px solid var(--mh-border); }

.trust-band__item {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    height: 100%;
}

.trust-band__tick {
    color: var(--mh-accent);
    flex-shrink: 0;
}

.trust-band__title {
    color: var(--mh-ink);
    font-weight: 650;
    font-size: 0.95rem;
    line-height: 1.3;
}

.trust-band__text {
    color: var(--mh-muted);
    font-size: 0.82rem;
    line-height: 1.4;
}

/* ==========================================================================
   Printing
   --------------------------------------------------------------------------
   Two different jobs, and conflating them was a bug.

   EVERY page with a print button needs the app chrome gone: the invoice,
   the sale, the purchase documents and the customer's own receipt all
   printed the navigation and every button before this existed.

   ONLY the sales counter, while a completed sale is on screen, wants
   80mm thermal paper. That is keyed off body.thermal-print, which the
   thermal partial sets. Applying it globally squeezed A4 documents into
   80mm on five other pages.

   Browsers cannot send raw ESC/POS bytes, so the thermal slip is
   produced the way a browser can: a print stylesheet through whatever
   driver the printer already has. Nothing to install.
   ========================================================================== */
.printable-receipt { display: none; }

@media print {
    /* ---- every printed page ---------------------------------------- */

    .navbar,
    .app-nav,
    .app-breadcrumb,
    .contact-fab,
    .mchrome-top,
    .mchrome-bottom,
    .mchrome-fab,
    .rec-search,
    .modal,
    .modal-backdrop,
    .offcanvas,
    .offcanvas-backdrop,
    .inv-actions,
    footer,
    /* Screen-only notices. "Recorded, but NOT sent: no SMTP provider is
       configured yet" is a message to the shop, not to the customer, and
       it was printing on their invoice. Flash messages, validation
       summaries and setup warnings are all screen furniture. */
    .alert,
    .no-print,
    .d-print-none,
    button,
    .btn {
        display: none !important;
    }

    html,
    body {
        background: #fff !important;
        color: #000 !important;
    }

    /* Cards are a screen device; on paper they are just boxes and rules
       that waste toner. */
    .card,
    .card-block {
        border: 0 !important;
        box-shadow: none !important;
        background: transparent !important;
    }

    /* A table split across pages loses its meaning. */
    table, tr, td, th {
        page-break-inside: avoid;
        break-inside: avoid;
    }

    /* The URL after every link is noise; where a URL matters it is
       already printed on its own line. */
    a[href]::after { content: none !important; }

    /* ---- the sales counter, mid-handover --------------------------- */

    @page { margin: 10mm; }

    body.thermal-print {
        width: 74mm;
        margin: 0;
        padding: 0;
        font-family: 'Courier New', Courier, monospace;
        font-size: 12px;
        line-height: 1.35;
    }

    /* Only when a thermal slip is on the page does the paper change. */
    body.thermal-print main,
    body.thermal-print .container,
    body.thermal-print .container-fluid,
    body.thermal-print .card,
    body.thermal-print .card-body,
    body.thermal-print .app-shell {
        max-width: none !important;
        width: auto !important;
        margin: 0 !important;
        padding: 0 !important;
        border: 0 !important;
        box-shadow: none !important;
        background: transparent !important;
    }

    /* Everything on the counter except the slip itself. */
    body.thermal-print .app-main > *:not(.printable-receipt),
    body.thermal-print form,
    body.thermal-print h1 {
        display: none !important;
    }

    body.thermal-print .printable-receipt {
        display: block !important;
        width: 74mm;
        color: #000;
    }

    .printable-receipt,
    .printable-receipt table,
    .printable-receipt tr,
    .printable-receipt td,
    .pr-item {
        page-break-inside: avoid;
        break-inside: avoid;
    }

    .pr-center { text-align: center; }
    .pr-bold { font-weight: 700; }
    .pr-small { font-size: 11px; }

    /* A long URL must wrap, not run off the edge of the paper. */
    .pr-wrap {
        word-break: break-all;
        overflow-wrap: anywhere;
    }

    .pr-rule {
        border-top: 1px dashed #000;
        margin: 4px 0;
    }

    .pr-line {
        display: flex;
        justify-content: space-between;
        gap: 6px;
    }

    .pr-item { margin-bottom: 2px; }
    .pr-item__name { font-weight: 600; }
}

/* ==========================================================================
   Public receipt page — the customer's own copy at /r/{uuid}
   ========================================================================== */
.receipt-doc {
    background: var(--mh-white);
    border: 1px solid var(--mh-border);
    border-radius: var(--mh-radius-md);
    padding: clamp(1.25rem, 4vw, 2rem);
}

.receipt-doc__head {
    text-align: center;
    padding-bottom: 0.9rem;
    border-bottom: 1px solid var(--mh-border);
}

.receipt-doc__shop {
    font-weight: 700;
    font-size: 1.15rem;
    color: var(--mh-ink);
}

.receipt-doc__meta {
    color: var(--mh-muted);
    font-size: 0.82rem;
}

.receipt-doc__kv {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 0.25rem 1rem;
    margin: 1rem 0;
    font-size: 0.9rem;
}

.receipt-doc__kv dt { color: var(--mh-muted); font-weight: 500; }
.receipt-doc__kv dd { margin: 0; color: var(--mh-ink); text-align: right; }

.receipt-doc__items {
    width: 100%;
    border-collapse: collapse;
    margin-bottom: 1rem;
}

.receipt-doc__items th {
    text-align: left;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--mh-muted);
    border-bottom: 1px solid var(--mh-border);
    padding-bottom: 0.4rem;
}

.receipt-doc__items td {
    padding: 0.55rem 0;
    border-bottom: 1px solid var(--mh-border);
    vertical-align: top;
    font-size: 0.92rem;
}

.receipt-doc__items .num { text-align: right; white-space: nowrap; }
.receipt-doc__detail { color: var(--mh-muted); font-size: 0.8rem; }

.receipt-doc__totals {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 0.3rem 1rem;
    font-size: 0.92rem;
}

.receipt-doc__totals dt { color: var(--mh-muted); }
.receipt-doc__totals dd { margin: 0; text-align: right; color: var(--mh-ink); }

.receipt-doc__totals .is-total {
    font-weight: 700;
    font-size: 1.05rem;
    color: var(--mh-ink);
    padding-top: 0.35rem;
    border-top: 1px solid var(--mh-border);
}

.receipt-doc__warranty {
    margin-top: 1.1rem;
    padding: 0.55rem 0.8rem;
    background: var(--mh-surface-frame);
    border-radius: var(--mh-radius-sm);
    font-size: 0.85rem;
    color: var(--mh-ink);
}

.receipt-doc__thanks {
    margin-top: 1.1rem;
    text-align: center;
    color: var(--mh-muted);
    font-size: 0.85rem;
}


/* ==========================================================================
   Exchange settlement bar
   --------------------------------------------------------------------------
   The one number the customer asks about, kept in view while the fields
   that feed it are edited. Sticky rather than fixed so it sits inside the
   form and cannot cover the mobile action bar or the bottom nav.

   Measured: ink #0A0A0B on surface-frame #F4F4F5 is 18.6:1, muted
   #52525B on it 7.3:1. The result figure is ink at full weight rather
   than the accent -- accent on this surface is 4.6:1, which passes, but a
   money total should be the highest-contrast thing on the bar.
   ========================================================================== */
.exch-settle {
    position: sticky;
    bottom: 0;
    z-index: 5;
    margin-top: 1.5rem;
    padding: 0.9rem 1rem;
    background: var(--mh-surface-frame);
    border: 1px solid var(--mh-border);
    border-radius: var(--mh-radius-md);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem 1.5rem;
}

.exch-settle__figures {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.5rem 1.5rem;
}

.exch-settle__cell {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
}

.exch-settle__label {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--mh-muted);
}

.exch-settle__value {
    font-size: 1rem;
    font-weight: 600;
    color: var(--mh-ink);
}

.exch-settle__cell--result { padding-left: 1rem; border-left: 2px solid var(--mh-border); }

.exch-settle__value--total {
    font-size: 1.4rem;
    font-weight: 700;
    line-height: 1.15;
}

.exch-settle__actions {
    display: flex;
    gap: 0.5rem;
    margin-left: auto;
}

@media (max-width: 575.98px) {
    .exch-settle { flex-direction: column; align-items: stretch; }
    .exch-settle__cell--result { padding-left: 0; border-left: 0; }
    .exch-settle__actions { margin-left: 0; }
    .exch-settle__actions .btn { flex: 1 1 0; }
}


/* ==========================================================================
   Settings index
   --------------------------------------------------------------------------
   Fourteen identical cards in alphabetical order, each showing a raw group
   name and a count, is what "too much" looked like. Sections carry the
   weight now, so the cards themselves are deliberately quiet.

   Measured: ink #0A0A0B on white 19.79:1, muted #52525B on white 7.73:1.
   ========================================================================== */
.set-section { margin-bottom: 2rem; }

.set-section__title {
    margin-bottom: 0.15rem;
    color: var(--mh-ink);
    font-weight: 650;
    letter-spacing: 0.01em;
}

.set-section__blurb {
    margin-bottom: 0.85rem;
    color: var(--mh-muted);
    font-size: 0.85rem;
}

.set-card {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    height: 100%;
    padding: 0.9rem 1rem;
    background: var(--mh-white);
    border: 1px solid var(--mh-border);
    border-radius: var(--mh-radius-md);
    text-decoration: none;
    transition: border-color 140ms ease, transform 140ms ease;
}

.set-card:hover,
.set-card:focus-visible {
    border-color: var(--mh-accent);
    transform: translateY(-1px);
}

.set-card__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}

.set-card__label {
    color: var(--mh-ink);
    font-weight: 600;
    line-height: 1.3;
}

/* A count is orientation, not information — it should not compete with
   the label for attention. */
.set-card__count {
    flex-shrink: 0;
    color: var(--mh-muted);
    font-size: 0.8rem;
}

.set-card__desc {
    color: var(--mh-muted);
    font-size: 0.82rem;
    line-height: 1.45;
}

@media (prefers-reduced-motion: reduce) {
    .set-card { transition: none; }
    .set-card:hover,
    .set-card:focus-visible { transform: none; }
}


/* ==========================================================================
   Contact button — one control, draggable
   --------------------------------------------------------------------------
   There used to be a floating WhatsApp circle AND a full-width bottom
   bar, in two different greens, with the bar covering both the circle and
   the footer. This is the one that remains.

   WhatsApp green #25D366 is 2.15:1 on white and could never carry a
   label; it carries only the mark here, which is a graphical object and
   clears the 3:1 floor comfortably. The Call mini-button uses the
   accent, whose white sits at 5.26:1.

   left/top are set by the drag script; the defaults below are the
   resting corner before anyone moves it.
   ========================================================================== */
.contact-fab {
    position: fixed;
    right: 1rem;
    bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
    /* Above content, deliberately BELOW Bootstrap's dialogs at 1055 and
       clear of the navbar at 1030. A widget that floats over your own
       modals is not "on top", it is in the way. */
    z-index: 1035;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.75rem;
}


.contact-fab__main,
.contact-fab__mini {
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    text-decoration: none;
    box-shadow: 0 6px 18px rgba(10, 10, 11, 0.22);
    /* The image inside must not be draggable itself, or the browser
       starts a native drag and the gesture is lost. */
    -webkit-user-select: none;
    user-select: none;
}

.contact-fab__main {
    width: 58px;
    height: 58px;
    background: #25D366;
    position: relative;
}

.contact-fab__mini {
    /* 48px, not 42. BRD SS43.6 sets 44px as the floor and this file already
       states the app uses 48; a secondary control is still a control, and
       42 was below the line I had written down elsewhere. */
    width: 48px;
    height: 48px;
    background: var(--mh-accent);
    color: var(--mh-white);
}

/* A slow ring, so the button reads as live without moving under the
   thumb. ::before cannot intercept the tap. */
.contact-fab__main::before {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: 50%;
    border: 2px solid #25D366;
    animation: wa-ring 2.8s ease-out infinite;
    pointer-events: none;
}

/* Drag removed: the widget is fixed bottom-right. The desktop offset,
   the hover lift and the tooltips all live in the contact-widget block
   further down and were already correct. */

.contact-fab__main:focus-visible,
.contact-fab__mini:focus-visible {
    outline: 3px solid var(--mh-ink);
    outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {
    .contact-fab__main::before { animation: none; opacity: 0; }

    .contact-fab__main,
    .contact-fab__mini { transition: none; }

    .contact-fab__main:hover,
    .contact-fab__mini:hover { transform: none; }
}


/* The breadcrumb's one position, directly under the hero. */
.crumb-bar {
    padding-block: 0.85rem 0.25rem;
}


/* Offer banner pictures. The strip has a fixed height so a tall upload
   cannot push the band down the page; object-fit crops rather than
   distorts, which matters because the owner uploads whatever they have. */
.offer-band__single--media {
    display: grid;
    grid-template-columns: minmax(0, 200px) 1fr;
    align-items: center;
    gap: 1rem 1.25rem;
}

.offer-band__media {
    grid-row: span 4;
    width: 100%;
    height: 96px;
    object-fit: cover;
    border-radius: var(--mh-radius-sm);
}

.offer-card__media {
    width: 100%;
    height: 110px;
    object-fit: cover;
    border-radius: var(--mh-radius-sm);
    margin-bottom: 0.35rem;
}

@media (max-width: 575.98px) {
    .offer-band__single--media { grid-template-columns: 1fr; }
    .offer-band__media { grid-row: auto; height: 140px; }
}


/* ==========================================================================
   Hero customer collage
   --------------------------------------------------------------------------
   Three real customers, overlapped and slightly rotated so the group reads
   as photographs rather than as a product grid.

   The rotations are small on purpose. .hero carries overflow:hidden -- it
   was added to stop hero content spilling over the navbar and swallowing
   nav clicks -- so a card rotated hard near the edge would be clipped by
   it. The container also keeps inset padding for the same reason.

   Measured: white on the badge's dark glass is 15.9:1 at the fallback
   colour, which is what a browser without backdrop-filter renders.
   ========================================================================== */
.hero-collage {
    position: relative;
    width: 100%;
    /* Squarish, matching the cropped photos (800x~755). */
    aspect-ratio: 1 / 1;
    /* Room for the rotated corners; without it .hero's overflow:hidden
       shaves them. */
    padding: 1.5rem 1.25rem 3rem;
}

.hero-collage__card {
    position: absolute;
    margin: 0;
    overflow: hidden;
    border-radius: var(--mh-radius-md);
    border: 3px solid rgba(255, 255, 255, 0.92);
    box-shadow: 0 18px 40px rgba(0, 0, 0, 0.45);
    background: var(--mh-graphite);
}

.hero-collage__card img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Back to front: the two supporting photos sit behind and to the left,
   the main one overlaps them on the right. */
.hero-collage__card--back {
    width: 46%;
    top: 4%;
    left: 2%;
    z-index: 1;
    transform: rotate(-5deg);
    aspect-ratio: 4 / 5;
}

.hero-collage__card--mid {
    width: 42%;
    bottom: 12%;
    left: 6%;
    z-index: 2;
    transform: rotate(3deg);
    aspect-ratio: 4 / 5;
}

.hero-collage__card--main {
    width: 62%;
    top: 12%;
    right: 2%;
    z-index: 3;
    transform: rotate(2deg);
    aspect-ratio: 4 / 5;
}

/* Glass panel. background is a real colour, not only a blur, so a browser
   without backdrop-filter still renders readable white text rather than
   white on a photograph. */
.hero-collage__badge {
    position: absolute;
    left: 50%;
    bottom: 0;
    transform: translateX(-50%);
    z-index: 4;
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.55rem 1rem;
    border-radius: var(--mh-radius-pill);
    background: rgba(10, 10, 11, 0.82);
    border: 1px solid rgba(255, 255, 255, 0.18);
    box-shadow: 0 10px 26px rgba(0, 0, 0, 0.35);
    white-space: nowrap;
}

@supports (backdrop-filter: blur(10px)) {
    .hero-collage__badge {
        background: rgba(10, 10, 11, 0.55);
        backdrop-filter: blur(10px);
    }
}

.hero-collage__icon {
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    flex-shrink: 0;
    border-radius: 50%;
    background: var(--mh-accent);
    color: var(--mh-white);
}

.hero-collage__badge-num {
    display: block;
    color: var(--mh-white);
    font-weight: 700;
    font-size: 0.95rem;
    line-height: 1.1;
}

.hero-collage__badge-sub {
    display: block;
    color: rgba(255, 255, 255, 0.72);
    font-size: 0.72rem;
    line-height: 1.2;
}

/* Below lg the hero stacks, so the collage gets its own capped band
   rather than a square that would push the CTAs off the screen. */
@media (max-width: 991.98px) {
    .hero-collage {
        aspect-ratio: auto;
        height: 300px;
        max-width: 30rem;
        margin-inline: auto;
        padding: 1rem 1rem 2.75rem;
    }

    .hero-collage__card--back { width: 40%; top: 2%; }
    .hero-collage__card--mid { width: 36%; bottom: 16%; }
    .hero-collage__card--main { width: 54%; top: 8%; }
}

@media (prefers-reduced-motion: reduce) {
    .hero-collage__card { transition: none; }
}


/* ==========================================================================
   Quick-contact widget: hover polish and tooltips
   --------------------------------------------------------------------------
   Tooltips are an enhancement, never the label -- they cannot appear on
   touch, so aria-label carries the meaning and this only helps a mouse.
   Gated on (hover: hover) so a tap does not leave one stuck open.

   Measured: white on graphite #0A0A0B is 19.79:1.
   ========================================================================== */
@media (min-width: 640px) {
    .contact-fab {
        right: 1.5rem;
        bottom: calc(1.5rem + env(safe-area-inset-bottom, 0px));
    }
}

.contact-fab__main,
.contact-fab__mini {
    transition: transform 0.2s ease, box-shadow 0.2s ease;
}

@media (hover: hover) and (pointer: fine) {
    .contact-fab__main:hover,
    .contact-fab__mini:hover {
        transform: scale(1.05);
        box-shadow: 0 10px 24px rgba(10, 10, 11, 0.32);
    }

    /* The label. position:absolute against the button, which is the only
       positioned ancestor that moves with it. */
    .contact-fab__main::after,
    .contact-fab__mini::after {
        content: attr(data-tip);
        position: absolute;
        right: calc(100% + 0.6rem);
        top: 50%;
        transform: translateY(-50%);
        padding: 0.3rem 0.6rem;
        border-radius: var(--mh-radius-sm);
        background: var(--mh-graphite);
        color: var(--mh-white);
        font-size: 0.78rem;
        font-weight: 600;
        line-height: 1;
        white-space: nowrap;
        opacity: 0;
        pointer-events: none;
        transition: opacity 0.15s ease;
    }

    .contact-fab__main:hover::after,
    .contact-fab__mini:hover::after {
        opacity: 1;
    }

    /* Dragged into the left half: the label would run off screen, so it
       swaps sides -- no longer needed: the widget is fixed. */
}

/* The mini needs a positioning context for its own tooltip. */
.contact-fab__mini { position: relative; }

@media (prefers-reduced-motion: reduce) {
    .contact-fab__main,
    .contact-fab__mini { transition: none; }

    .contact-fab__main:hover,
    .contact-fab__mini:hover { transform: none; }
}


/* --------------------------------------------------------------------------
   NEXT STEPS
   The one action bar used by every detail screen. Horizontal and wrapping
   rather than a dropdown: the whole point is that the available actions
   are visible without being hunted for.
   -------------------------------------------------------------------------- */
.next-steps {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-bottom: 1rem;
}

.next-step {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.55rem 0.95rem;
    border-radius: var(--mh-radius-pill);
    border: 1px solid var(--mh-border);
    background: var(--mh-white);
    color: var(--mh-ink);
    font-size: 0.9rem;
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
    transition: background 140ms ease, border-color 140ms ease;
}

.next-step svg { width: 18px; height: 18px; flex: none; }

.next-step:hover,
.next-step:focus-visible {
    background: var(--mh-surface-2, #f6f4f1);
    border-color: var(--mh-accent);
    color: var(--mh-ink);
}

.next-step--primary {
    background: var(--mh-accent);
    border-color: var(--mh-accent);
    color: var(--mh-white);
}

.next-step--primary:hover,
.next-step--primary:focus-visible {
    background: var(--mh-accent-hover, var(--mh-accent));
    border-color: var(--mh-accent-hover, var(--mh-accent));
    color: var(--mh-white);
}

@media (prefers-reduced-motion: reduce) {
    .next-step { transition: none; }
}


/* One line under the hero collage, keeping the shelf a click away. */
.hero-collage__shelf {
    margin: 0.85rem 0 0;
    text-align: center;
    font-size: 0.9rem;
    color: rgba(255, 255, 255, 0.78);
}

.hero-collage__shelf a {
    color: var(--mh-white);
    font-weight: 600;
    text-decoration: underline;
    text-underline-offset: 3px;
}

.hero-collage__shelf a:hover { color: var(--mh-gold, #E7B75F); }


/* --------------------------------------------------------------------------
   MORE PHONES LIKE THIS
   A detail page used to end in white space. These cards are the exit.
   -------------------------------------------------------------------------- */
.catalogue-similar__card {
    display: flex;
    flex-direction: column;
    height: 100%;
    text-decoration: none;
    color: inherit;
    background: var(--mh-white);
    border: 1px solid var(--mh-border);
    border-radius: var(--mh-radius-md);
    overflow: hidden;
    transition: border-color 160ms ease, box-shadow 160ms ease, transform 160ms ease;
}

.catalogue-similar__media { background: var(--mh-surface-2, #f6f4f1); }

.catalogue-similar__body {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.35rem;
    padding: 0.85rem 0.9rem 1rem;
}

.catalogue-similar__name { font-weight: 700; line-height: 1.25; }

.catalogue-similar__meta {
    font-size: 0.82rem;
    color: var(--mh-muted, #6b6b70);
}

@media (hover: hover) and (pointer: fine) {
    .catalogue-similar__card:hover {
        border-color: var(--mh-accent);
        box-shadow: 0 10px 26px rgba(10, 10, 11, 0.10);
        transform: translateY(-2px);
    }
}

.catalogue-similar__card:focus-visible {
    outline: 3px solid var(--mh-accent);
    outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {
    .catalogue-similar__card { transition: none; }
    .catalogue-similar__card:hover { transform: none; }
}


/* --------------------------------------------------------------------------
   ENQUIRY SENT
   An envelope that opens itself once a message has been accepted.
   Flattened from a nested source, and namespaced: the original's .body,
   .shadow and .letter would have styled half the site.
   -------------------------------------------------------------------------- */
.mh-envelope-wrap {
    text-align: center;
    /* Room for the mail's 50px drop and the shadow beneath it, so the
       animation is not clipped by the card it sits in. */
    padding: 0.5rem 0 1rem;
}

.mh-envelope {
    position: relative;
    width: 200px;
    height: 260px;
    margin: 0 auto;
}

.mh-envelope__mail {
    position: absolute;
    left: 0;
    top: 0;
    height: 150px;
    width: 200px;
    transition: transform 0.4s;
}

.mh-envelope__body {
    position: absolute;
    bottom: 0;
    width: 0;
    height: 0;
    border-style: solid;
    border-width: 0 0 100px 200px;
    border-color: transparent transparent #e95f55 transparent;
    z-index: 2;
}

.mh-envelope__top-fold {
    position: absolute;
    top: 50px;
    width: 0;
    height: 0;
    border-style: solid;
    border-width: 50px 100px 0 100px;
    border-color: #cf4a43 transparent transparent transparent;
    transform-origin: 50% 0%;
    transition: transform 0.4s 0.4s, z-index 0.2s 0.4s;
    z-index: 2;
}

.mh-envelope__back-fold {
    position: absolute;
    bottom: 0;
    width: 200px;
    height: 100px;
    background: #cf4a43;
    z-index: 0;
}

.mh-envelope__left-fold {
    position: absolute;
    bottom: 0;
    width: 0;
    height: 0;
    border-style: solid;
    border-width: 50px 0 50px 100px;
    border-color: transparent transparent transparent #e15349;
    z-index: 2;
}

.mh-envelope__letter {
    position: absolute;
    left: 20px;
    bottom: 0;
    width: 160px;
    height: 60px;
    background: #fff;
    z-index: 1;
    overflow: hidden;
    transition: height 0.4s 0.2s;
}

.mh-envelope__border {
    height: 10px;
    width: 100%;
    background: repeating-linear-gradient(-45deg, #cb5a5e, #cb5a5e 8px, transparent 8px, transparent 18px);
}

.mh-envelope__title {
    margin: 10px 0 0 5px;
    height: 10px;
    width: 40%;
    background: #cb5a5e;
}

.mh-envelope__context {
    margin: 10px 0 0 5px;
    height: 10px;
    width: 20%;
    background: #cb5a5e;
}

.mh-envelope__stamp {
    margin: 30px 0 0 120px;
    border-radius: 100%;
    height: 30px;
    width: 30px;
    background: #cb5a5e;
    opacity: 0.3;
}

.mh-envelope__shadow {
    position: absolute;
    top: 200px;
    left: 50%;
    width: 400px;
    height: 30px;
    transform: translateX(-50%);
    transition: width 0.4s;
    border-radius: 100%;
    background: radial-gradient(rgba(0, 0, 0, 0.28), rgba(0, 0, 0, 0), rgba(0, 0, 0, 0));
}

/* Open. .is-open is added on appearance so the envelope opens by itself
   -- the reference opened only on :hover, which never fires on a phone,
   and here the opening IS the confirmation. Hover replays it. */
.mh-envelope.is-open .mh-envelope__mail,
.mh-envelope:hover .mh-envelope__mail {
    transform: translateY(50px);
}

.mh-envelope.is-open .mh-envelope__top-fold,
.mh-envelope:hover .mh-envelope__top-fold {
    transition: transform 0.4s, z-index 0.2s;
    transform: rotateX(180deg);
    z-index: 0;
}

.mh-envelope.is-open .mh-envelope__letter,
.mh-envelope:hover .mh-envelope__letter {
    height: 180px;
}

.mh-envelope.is-open .mh-envelope__shadow,
.mh-envelope:hover .mh-envelope__shadow {
    width: 250px;
}

.mh-envelope__message {
    margin: 0.25rem 0 0;
    font-weight: 600;
}

/* The confirmation must not depend on movement. Reduced motion shows the
   envelope already open, with no transition at all. */
@media (prefers-reduced-motion: reduce) {
    .mh-envelope__mail,
    .mh-envelope__top-fold,
    .mh-envelope__letter,
    .mh-envelope__shadow {
        transition: none;
    }

    .mh-envelope__mail { transform: translateY(50px); }
    .mh-envelope__top-fold { transform: rotateX(180deg); z-index: 0; }
    .mh-envelope__letter { height: 180px; }
    .mh-envelope__shadow { width: 250px; }
}


/* --------------------------------------------------------------------------
   AT THE COUNTER
   Four real customers on the contact page. Two up on a phone, four across
   from md, so no photograph is ever reduced to a thumbnail.
   -------------------------------------------------------------------------- */
.contact-faces {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 0.75rem;
    margin-top: 1.5rem;
}

@media (min-width: 768px) {
    .contact-faces {
        grid-template-columns: repeat(4, 1fr);
        gap: 1rem;
    }
}

.contact-faces__item {
    margin: 0;
    border-radius: var(--mh-radius-md);
    overflow: hidden;
    background: var(--mh-graphite);
    box-shadow: 0 8px 22px rgba(10, 10, 11, 0.12);
}

.contact-faces__item img {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 1 / 1;
    object-fit: cover;
}

.contact-faces__note {
    margin: 1.25rem 0 0;
    font-size: 0.92rem;
    color: var(--mh-muted, #6b6b70);
}

/* ==========================================================================
   App-wide sidebar shell + dashboard visual redesign (Aug 2026).
   Additive only — existing shared classes (.kpi-chip, .card-block, .navbar,
   .dash-list, etc.) are NOT redefined here, so every page that already uses
   them keeps working exactly as before. New rules are namespaced mh-*.
   ========================================================================== */

/* Scoped to lg+ only: below that, mobile-chrome's own top/bottom bars
   remain the untouched, already-working layout — nothing here applies. */
@media (min-width: 992px) {
    body.site-app {
        display: flex;
        min-height: 100vh;
    }

    body.site-app > .mh-sidebar {
        position: sticky;
        top: 0;
        height: 100vh;
    }

    body.site-app > .mh-app-body {
        flex: 1;
        min-width: 0;
        display: flex;
        flex-direction: column;
    }
}

.mh-sidebar {
    width: 232px;
    flex: 0 0 232px;
    background: #fff;
    border-right: 1px solid var(--mh-border);
    padding: 14px 10px;
    overflow-y: auto;
}

.mh-side-brand {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px 16px;
    font-weight: 700;
    color: var(--mh-graphite);
    text-decoration: none;
}

.mh-side-brand:hover {
    color: var(--mh-graphite);
}

.mh-side-scroll {
    display: flex;
    flex-direction: column;
}

.mh-side-link {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 10px;
    border-radius: var(--mh-radius-sm);
    color: var(--mh-graphite);
    font-size: .87rem;
    font-weight: 500;
    margin-bottom: 2px;
    width: 100%;
    border: none;
    background: transparent;
    text-align: left;
}

.mh-side-link:hover {
    background: #F3F5F9;
    text-decoration: none;
    color: var(--mh-graphite);
}

/* Bold solid-fill active state (SalesHive-style), not just a soft tint. */
.mh-side-link.active {
    background: var(--mh-accent);
    color: #fff;
    font-weight: 700;
}

.mh-side-link.active svg {
    color: #fff;
}

.mh-side-link svg {
    width: 18px;
    height: 18px;
    flex: 0 0 18px;
    color: var(--mh-muted);
}

.mh-side-toggle .mh-side-chevron {
    width: 14px;
    height: 14px;
    flex: 0 0 14px;
    margin-left: auto;
    color: var(--mh-muted);
    transition: transform .15s ease;
}

.mh-side-toggle.active .mh-side-chevron {
    color: #fff;
}

.mh-side-submenu {
    display: flex;
    flex-direction: column;
    padding-left: 30px;
    margin-bottom: 4px;
}

.mh-side-sublink {
    padding: 7px 10px;
    border-radius: var(--mh-radius-sm);
    color: var(--mh-muted);
    font-size: .83rem;
    font-weight: 500;
}

.mh-side-sublink:hover {
    background: #F3F5F9;
    text-decoration: none;
}

.mh-side-sublink.active {
    color: var(--mh-accent);
    font-weight: 700;
}

.mh-side-divider {
    height: 1px;
    background: var(--mh-border);
    margin: 10px 4px;
}

.mh-side-footer {
    margin-top: 10px;
    padding: 10px;
    border-radius: var(--mh-radius-sm);
    background: var(--mh-page, #F7F9FC);
    border: 1px solid var(--mh-border);
    display: flex;
    align-items: center;
    gap: 10px;
}

.mh-side-footer-meta {
    min-width: 0;
    overflow: hidden;
}

.mh-user-avatar {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--mh-accent);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: .75rem;
    font-weight: 700;
    flex: 0 0 32px;
}

.mh-fname {
    font-size: .82rem;
    font-weight: 700;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.mh-frole {
    font-size: .7rem;
    color: var(--mh-muted);
}

.mh-side-status {
    margin-left: auto;
    flex: 0 0 auto;
}

.mh-side-status .mchrome-status__dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #10B981;
    display: block;
}

.mh-side-status.is-offline .mchrome-status__dot {
    background: #EF4444;
}

/* Simplified top bar: module dropdowns are gone (the sidebar owns that job
   now), so what remains is just search + status icons + user menu. */
.mh-topbar-simple {
    background: #fff !important;
    border-bottom: 1px solid var(--mh-border);
}

.mh-topbar-simple .navbar-brand {
    display: none;
}

.mh-top-search {
    background: var(--mh-page, #F7F9FC);
    border: 1px solid var(--mh-border);
    border-radius: var(--mh-radius-pill);
    padding: 6px 14px;
    font-size: .85rem;
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 260px;
    color: var(--mh-muted);
}

.mh-top-search input {
    background: transparent;
    border: none;
    outline: none;
    font-size: .85rem;
    width: 100%;
}

.mh-top-icon-btn {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    border: none;
    background: var(--mh-page, #F7F9FC);
    color: var(--mh-graphite);
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative;
}

.mh-top-icon-btn:hover {
    background: #EEF1F6;
}

.mh-top-icon-btn svg {
    width: 18px;
    height: 18px;
}

.mh-top-badge-dot {
    position: absolute;
    top: -2px;
    right: -2px;
    background: var(--mh-danger, #EF4444);
    color: #fff;
    font-size: .6rem;
    font-weight: 700;
    border-radius: 999px;
    min-width: 15px;
    height: 15px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 2px solid #fff;
}

/* ---------- Dashboard card visual redesign ---------- */

.mh-metric-icon {
    width: 38px;
    height: 38px;
    border-radius: 11px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.mh-metric-icon svg {
    width: 19px;
    height: 19px;
}

.mh-metric-icon.blue { background: var(--mh-accent-soft); color: var(--mh-accent); }
.mh-metric-icon.green { background: #E6F7EF; color: #10B981; }
.mh-metric-icon.red { background: #FDECEC; color: #EF4444; }
.mh-metric-icon.purple { background: #F1EBFE; color: #8B5CF6; }

.mh-metric-delta {
    font-size: .76rem;
    font-weight: 600;
    display: inline-flex;
    align-items: center;
    gap: 3px;
}

.mh-metric-delta.up { color: #10B981; }
.mh-metric-delta.down { color: #EF4444; }

.mh-sparkline {
    height: 30px;
}

.mh-seg-icon {
    width: 24px;
    height: 24px;
    border-radius: 7px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 24px;
}

.mh-seg-icon svg { width: 13px; height: 13px; }

.mh-avatar-stack {
    display: flex;
}

.mh-avatar-stack .mh-avatar-sm {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    background: var(--mh-accent-soft);
    color: var(--mh-accent);
    border: 2px solid #fff;
    margin-left: -8px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: .68rem;
    font-weight: 700;
}

.mh-avatar-stack .mh-avatar-sm:first-child {
    margin-left: 0;
}

.mh-price-delta.up { color: #10B981; font-weight: 700; }
.mh-price-delta.down { color: #EF4444; font-weight: 700; }

.mh-badge-soft {
    display: inline-flex;
    align-items: center;
    font-size: .7rem;
    font-weight: 700;
    padding: 3px 9px;
    border-radius: 999px;
}

.mh-badge-soft.warn { background: #FEF3E2; color: #B45309; }
.mh-badge-soft.info { background: var(--mh-accent-soft); color: var(--mh-accent); }

/* ==========================================================================
   Flat sidebar + light top bar + donut chart (Aug 2026, round 3).
   Additive only, same rule as prior rounds: nothing shared/global is
   redefined, so no other page is affected by this block.
   ========================================================================== */

.mh-sidebar {
    transition: width .15s ease;
}

.mh-sidebar.is-collapsed {
    width: 72px;
    flex: 0 0 72px;
    padding-left: 6px;
    padding-right: 6px;
}

.mh-sidebar.is-collapsed .mh-side-link,
.mh-sidebar.is-collapsed .mh-side-brand {
    justify-content: center;
}

.mh-side-subswitch {
    display: flex;
    flex-direction: column;
    padding: 2px 10px 10px 40px;
    gap: 2px;
}

.mh-side-subswitch a {
    font-size: .78rem;
    color: var(--mh-muted);
    padding: 4px 0;
}

.mh-side-subswitch a.active {
    color: var(--mh-accent);
    font-weight: 700;
}

.mh-side-collapse-btn {
    display: flex;
    align-items: center;
    gap: 8px;
    border: none;
    background: transparent;
    color: var(--mh-muted);
    font-size: .8rem;
    padding: 8px 10px;
    margin-top: 6px;
}

.mh-side-collapse-btn:hover {
    background: #F3F5F9;
    border-radius: var(--mh-radius-sm);
}

.mh-side-collapse-btn svg {
    width: 15px;
    height: 15px;
    flex: 0 0 15px;
}

/* ---------- Light top bar, wide search ---------- */

.mh-topbar-simple .mh-top-search {
    min-width: 380px;
}

.mh-topbar-simple .mh-top-search kbd {
    background: #fff;
    border: 1px solid var(--mh-border);
    border-radius: 6px;
    padding: 2px 7px;
    font-size: .72rem;
    color: var(--mh-muted);
    margin-left: auto;
}

/* ---------- Donut chart (Stock by Segment) ---------- */

.mh-donut-wrap {
    position: relative;
    width: 140px;
    height: 140px;
    flex: 0 0 140px;
}

.mh-donut-center {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}

.mh-donut-center .val {
    font-size: 1.5rem;
    font-weight: 800;
}

.mh-donut-center .lbl {
    font-size: .72rem;
    color: var(--mh-muted);
}

.mh-legend-dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    display: inline-block;
    flex: 0 0 9px;
}

.mh-legend-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 7px 0;
    font-size: .85rem;
}

.mh-legend-row .lbl {
    flex: 1;
}

.mh-legend-row .count {
    width: 30px;
    text-align: right;
    font-weight: 700;
}

.mh-legend-row .pct {
    width: 44px;
    text-align: right;
    color: var(--mh-muted);
}

/* ---------- Metric card icon-header pattern for other cards ---------- */

.mh-card-icon-header {
    display: flex;
    align-items: center;
    gap: 10px;
}

.mh-card-icon-header .mh-metric-icon {
    width: 30px;
    height: 30px;
    border-radius: 8px;
}

.mh-card-icon-header .mh-metric-icon svg {
    width: 15px;
    height: 15px;
}

.mh-qa-icon {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--mh-accent-soft);
    color: var(--mh-accent);
    flex: 0 0 22px;
}

.mh-qa-icon svg {
    width: 12px;
    height: 12px;
}

/* ==========================================================================
   Sales module UI (Aug 2026). Additive only: nothing existing is
   redefined, so Invoices/Dues/Repairs and every other .rec-card page is
   untouched. New rules are mh-* namespaced, or scoped by .mh-rec-card so
   they apply only where that opt-in class is present.
   ========================================================================== */

/* .mh-metric-icon.orange was missing — the base block only shipped
   blue/green/red/purple. Tokens match the warning tone used elsewhere. */
.mh-metric-icon.orange { background: #FEF3E2; color: #F59E0B; }

/* A GROUP whose child is the current page. Deliberately NOT .active:
   that paints a solid accent fill and means "this is the page you are
   on". A parent only contains the current page, so it gets accent text
   and a tinted ground while the child sublink keeps the strong mark. */
.mh-side-link.is-branch-active {
    color: var(--mh-accent);
    background: var(--mh-accent-soft);
    font-weight: 700;
}

.mh-side-link.is-branch-active svg {
    color: var(--mh-accent);
}

/* .rec-card is display:block by default, so an avatar sibling would stack
   above the text. This opt-in class turns that one card into a flex row
   without touching the shared .rec-card rule. */
.mh-rec-card {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
}

.mh-rec-card__body {
    flex: 1;
    min-width: 0;
}

.mh-rec-card__avatar {
    flex: 0 0 38px;
    width: 38px;
    height: 38px;
    margin-left: 0;
    font-size: 0.78rem;
}

.mh-filter-panel {
    background: var(--mh-white);
    border: 1px solid var(--mh-border);
    border-radius: var(--mh-radius-md);
    padding: 0.85rem 0.95rem;
}

/* The filter panel lives inside .rec-search, which is sticky. Keep it
   readable when open rather than letting list rows show through. */
.rec-search .mh-filter-panel {
    box-shadow: 0 4px 10px rgba(16, 24, 40, 0.06);
}

/* ---------- Sectioned form cards (New Sale) ---------- */

.mh-form-section {
    border-top: 1px solid var(--mh-border);
    margin-top: 1.35rem;
    padding-top: 1.15rem;
}

.mh-form-section:first-of-type {
    border-top: 0;
    margin-top: 0;
    padding-top: 0;
}

.mh-form-section__head {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin-bottom: 0.85rem;
}

.mh-form-section__head .mh-metric-icon {
    width: 30px;
    height: 30px;
    border-radius: 8px;
    flex: 0 0 30px;
}

.mh-form-section__head .mh-metric-icon svg {
    width: 15px;
    height: 15px;
}

.mh-form-section__title {
    font-size: 0.95rem;
    font-weight: 700;
    margin: 0;
}

/* Accessory rows read as one unit rather than a loose grid of inputs. */
.mh-accessory-row {
    background: var(--mh-page, #F7F9FC);
    border: 1px solid var(--mh-border);
    border-radius: var(--mh-radius-md);
    padding: 0.75rem;
    margin-bottom: 0.6rem;
}

/* ---------- Quick-customer modal ---------- */

.mh-modal-head {
    display: flex;
    align-items: flex-start;
    gap: 0.85rem;
}

.mh-modal-head .mh-metric-icon {
    width: 42px;
    height: 42px;
    border-radius: 12px;
    flex: 0 0 42px;
}

.mh-modal-head .mh-metric-icon svg {
    width: 21px;
    height: 21px;
}

.mh-modal-sub {
    font-size: 0.82rem;
    color: var(--mh-muted);
    margin: 0.15rem 0 0;
}

/* Trailing field icon, per the reference. Purely decorative — the input
   keeps its own full width and padding so nothing overlaps the caret. */
.mh-field-icon {
    position: relative;
}

.mh-field-icon > svg {
    position: absolute;
    right: 0.75rem;
    top: 50%;
    transform: translateY(-50%);
    width: 17px;
    height: 17px;
    color: var(--mh-muted);
    pointer-events: none;
}

.mh-field-icon > .form-control {
    padding-right: 2.4rem;
}

/* ===========================================================================
   MOBILE HEAVEN — PRODUCT SURFACE (added 2026-08-12)
   ===========================================================================
   Shared components for the customer journeys, starting with valuation.
   Everything here is built on the EXISTING --mh-* tokens; only the four
   groups below are new, because the original system genuinely lacked them:
   a page tint, elevation, positive/success semantics, and a hero gradient.

   These are deliberately generic (.mh-stepper, .mh-chip, .mh-pill) rather
   than valuation-specific, because the rest of the application facelift
   reuses them. Nothing in here is scoped to one page.
   =========================================================================== */

:root {
    /* Page tint — cards sit ON something, rather than white on white. */
    --mh-page-tint: #F6F8FC;

    /* Elevation. The system previously defined no shadow tokens at all,
       so every card that wanted depth invented its own. */
    --mh-shadow-xs: 0 1px 2px rgba(10, 10, 11, .04);
    --mh-shadow-sm: 0 1px 3px rgba(10, 10, 11, .06), 0 1px 2px rgba(10, 10, 11, .04);
    --mh-shadow-md: 0 4px 12px rgba(10, 10, 11, .07), 0 1px 3px rgba(10, 10, 11, .05);
    --mh-shadow-lg: 0 12px 32px rgba(10, 10, 11, .10), 0 2px 8px rgba(10, 10, 11, .05);

    /* Positive semantics. --mh-review already covers "needs attention";
       there was no token for "this went well". Ink is 7.4:1 on the soft
       fill, so success text is readable rather than decorative. */
    --mh-positive: #12805C;
    --mh-positive-soft: #E7F6EF;
    --mh-positive-ink: #0A5C42;

    /* Hero surface for a result screen. */
    --mh-hero-from: #EEF3FF;
    --mh-hero-to: #F7FAFF;
}

/* --- Section heading with icon tile ------------------------------------- */
.mh-section-head { display: flex; align-items: center; gap: .625rem; margin-bottom: .875rem; }
.mh-icon-tile {
    display: inline-grid; place-items: center;
    width: 2rem; height: 2rem; flex: 0 0 auto;
    background: var(--mh-surface-icon);
    color: var(--mh-accent);
    border-radius: var(--mh-radius-sm);
    font-size: .95rem; line-height: 1;
}
.mh-section-head h2, .mh-section-head h3 {
    font-size: 1rem; font-weight: 600; margin: 0; color: var(--mh-ink);
}

/* --- Card --------------------------------------------------------------- */
.mh-card {
    background: var(--mh-white);
    border: 1px solid var(--mh-border);
    border-radius: var(--mh-radius-md);
    box-shadow: var(--mh-shadow-sm);
    padding: 1.125rem;
}
.mh-card + .mh-card { margin-top: 1rem; }

/* --- Stepper ------------------------------------------------------------
   Numbered dots joined by a rule. The connector is drawn behind the dots
   with a pseudo-element so the markup stays a plain ordered list, which is
   what a screen reader should hear.                                        */
.mh-stepper { display: flex; align-items: center; list-style: none; padding: 0; margin: 0 0 1.25rem; }
.mh-stepper li { display: flex; align-items: center; flex: 1 1 0; }
.mh-stepper li:last-child { flex: 0 0 auto; }
.mh-step-dot {
    display: grid; place-items: center;
    width: 1.75rem; height: 1.75rem; flex: 0 0 auto;
    border-radius: 999px;
    font-size: .8125rem; font-weight: 600;
    background: var(--mh-surface-frame);
    color: var(--mh-muted);
    border: 1px solid var(--mh-border);
    transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}
.mh-step-line { flex: 1 1 auto; height: 2px; background: var(--mh-border); margin: 0 .5rem; border-radius: 2px; }
.mh-stepper li[data-state="done"] .mh-step-dot,
.mh-stepper li[data-state="current"] .mh-step-dot {
    background: var(--mh-accent); color: var(--mh-white); border-color: var(--mh-accent);
}
.mh-stepper li[data-state="done"] + li .mh-step-line,
.mh-stepper li[data-state="done"] .mh-step-line { background: var(--mh-accent); }
.mh-step-caption { font-size: .8125rem; color: var(--mh-muted); }

/* --- Chip group (segmented condition selector) -------------------------
   Real radio inputs, visually hidden. Keyboard, screen readers and form
   reset all keep working; the chip is only a label.                        */
.mh-chip-group { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .5rem; }
@media (min-width: 576px) { .mh-chip-group { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.mh-chip-group input[type="radio"] { position: absolute; opacity: 0; pointer-events: none; }
.mh-chip {
    display: block; cursor: pointer;
    padding: .5rem .625rem;
    border: 1px solid var(--mh-border);
    border-radius: var(--mh-radius-sm);
    background: var(--mh-white);
    text-align: left;
    transition: border-color .15s ease, background-color .15s ease, box-shadow .15s ease;
}
.mh-chip strong { display: block; font-size: .8125rem; font-weight: 600; color: var(--mh-ink); line-height: 1.25; }
.mh-chip span   { display: block; font-size: .6875rem; color: var(--mh-muted); margin-top: .125rem; line-height: 1.3; }
.mh-chip:hover { border-color: var(--mh-accent); }
input[type="radio"]:checked + .mh-chip {
    border-color: var(--mh-accent);
    background: var(--mh-accent-soft);
    box-shadow: inset 0 0 0 1px var(--mh-accent);
}
input[type="radio"]:focus-visible + .mh-chip { outline: 2px solid var(--mh-accent); outline-offset: 2px; }

/* --- Yes / No pill pair ------------------------------------------------- */
.mh-pill-row { display: flex; align-items: center; justify-content: space-between; gap: .75rem; padding: .5rem 0; }
.mh-pill-row + .mh-pill-row { border-top: 1px solid var(--mh-border); }
.mh-pill-label { font-size: .875rem; color: var(--mh-ink); }
.mh-pill-group { display: inline-flex; gap: .25rem; flex: 0 0 auto; }
.mh-pill-group input[type="radio"] { position: absolute; opacity: 0; pointer-events: none; }
.mh-pill {
    display: inline-block; cursor: pointer;
    min-width: 3.25rem; padding: .3125rem .75rem;
    border: 1px solid var(--mh-border);
    border-radius: var(--mh-radius-pill);
    background: var(--mh-white);
    font-size: .8125rem; font-weight: 600; text-align: center;
    color: var(--mh-muted);
    transition: border-color .15s ease, background-color .15s ease, color .15s ease;
}
input[type="radio"]:checked + .mh-pill.is-yes {
    background: var(--mh-positive-soft); border-color: var(--mh-positive); color: var(--mh-positive-ink);
}
input[type="radio"]:checked + .mh-pill.is-no {
    background: var(--mh-surface-frame); border-color: var(--mh-ink); color: var(--mh-ink);
}
input[type="radio"]:focus-visible + .mh-pill { outline: 2px solid var(--mh-accent); outline-offset: 2px; }

/* --- Result hero -------------------------------------------------------- */
.mh-hero {
    background: linear-gradient(160deg, var(--mh-hero-from), var(--mh-hero-to));
    border: 1px solid var(--mh-border);
    border-radius: var(--mh-radius-xl);
    box-shadow: var(--mh-shadow-md);
    padding: 1.75rem 1.25rem;
    text-align: center;
}
.mh-hero-eyebrow { font-size: .8125rem; color: var(--mh-muted); margin-bottom: .375rem; }
.mh-hero-price {
    font-size: clamp(1.75rem, 7vw, 2.5rem);
    font-weight: 700; letter-spacing: -.02em; color: var(--mh-ink); line-height: 1.1;
}
.mh-hero-note { font-size: .75rem; color: var(--mh-muted); margin-top: .625rem; }

/* --- Confidence badge --------------------------------------------------- */
.mh-confidence {
    display: inline-flex; align-items: center; gap: .375rem;
    padding: .25rem .625rem; border-radius: var(--mh-radius-pill);
    font-size: .75rem; font-weight: 600;
}
.mh-confidence.status-good   { background: var(--mh-positive-soft); color: var(--mh-positive-ink); }
.mh-confidence.status-review { background: var(--mh-review); color: var(--mh-review-ink); }
.mh-confidence.status-bad    { background: #FDE7E7; color: #7A1C1C; }

/* --- Price breakdown ---------------------------------------------------- */
.mh-breakdown { list-style: none; padding: 0; margin: 0; }
.mh-breakdown li { display: flex; justify-content: space-between; gap: 1rem; padding: .5rem 0; font-size: .875rem; }
.mh-breakdown li + li { border-top: 1px solid var(--mh-border); }
.mh-breakdown .mh-amt { font-variant-numeric: tabular-nums; white-space: nowrap; font-weight: 600; }
.mh-breakdown .mh-amt-down { color: #9A2626; }
.mh-breakdown .mh-amt-up { color: var(--mh-positive-ink); }
.mh-breakdown-total {
    display: flex; justify-content: space-between; gap: 1rem;
    margin-top: .5rem; padding-top: .75rem; border-top: 2px solid var(--mh-ink);
    font-weight: 700; font-size: .9375rem;
}

/* --- Reassurance list --------------------------------------------------- */
.mh-reasons { list-style: none; padding: 0; margin: 0; }
.mh-reasons li { display: flex; gap: .5rem; padding: .25rem 0; font-size: .8125rem; color: var(--mh-ink); }
.mh-reasons li::before { content: "\2713"; color: var(--mh-positive); font-weight: 700; flex: 0 0 auto; }

.mh-callout {
    border-radius: var(--mh-radius-sm); padding: .75rem .875rem; font-size: .8125rem;
    border: 1px solid transparent;
}
.mh-callout-positive { background: var(--mh-positive-soft); border-color: #BFE5D5; color: var(--mh-positive-ink); }
.mh-callout-note { background: var(--mh-surface-frame); border-color: var(--mh-border); color: var(--mh-muted); }

/* --- Sticky action bar (mobile) ----------------------------------------- */
.mh-sticky-cta {
    position: sticky; bottom: 0; z-index: 5;
    background: linear-gradient(to top, var(--mh-white) 72%, rgba(255, 255, 255, 0));
    padding: .875rem 0 1rem;
    margin-top: 1.25rem;
}

/* --- Reduced motion ----------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
    .mh-chip, .mh-pill, .mh-step-dot { transition: none; }
}
/* ===========================================================================
   PRODUCT CARD SPECS + DEMAND ROWS (added 2026-08-19)
   Grade and battery were rendering as one grey sentence. They are the two
   facts a second-hand buyer decides on, so they get their own treatment:
   the grade in the shop's own colour vocabulary, the battery as a meter
   because a percentage reads better against a bar than alone.
   =========================================================================== */
:root{
    --mh-negative-soft:#FBEAE7;
    --mh-negative-ink:#8E2C1F;
}

.mh-spec{display:flex;align-items:center;gap:.55rem;flex-wrap:wrap;margin-bottom:.4rem}
.mh-grade{display:inline-block;font-size:.72rem;font-weight:800;padding:.16rem .48rem;
    border-radius:.35rem;white-space:nowrap;line-height:1.35}
.mh-grade--a{background:var(--mh-positive-soft);color:var(--mh-positive-ink)}
.mh-grade--b{background:var(--mh-accent-soft);color:var(--mh-accent-hover)}
.mh-grade--c{background:var(--mh-review);color:var(--mh-review-ink)}
.mh-grade--d{background:var(--mh-negative-soft);color:var(--mh-negative-ink)}
.mh-grade--x{background:var(--mh-surface-frame);color:var(--mh-muted)}

.mh-batt{display:inline-flex;align-items:center;gap:.4rem;font-size:.72rem;
    color:var(--mh-muted);font-weight:600}
.mh-batt__meter{display:inline-block;width:44px;height:5px;border-radius:99px;
    background:var(--mh-border);overflow:hidden}
.mh-batt__fill{display:block;height:100%;border-radius:99px;background:var(--mh-positive)}
/* Below 80% a replacement is usually due. Colour says so; the number still
   carries the fact, so this never relies on colour alone. */
.mh-batt__fill.is-low{background:#C0563F}

/* Demand rows are now the route into the valuation, so they must look
   pressable and respond to hover and keyboard focus alike. */
.rank-row--link{display:flex;text-decoration:none;color:inherit;
    transition:transform .18s ease}
.rank-row--link:hover{transform:translateX(3px)}
.rank-row--link:hover .rank-name{color:var(--mh-accent)}
.rank-row--link:focus-visible{outline:2px solid var(--mh-accent);outline-offset:3px;border-radius:.5rem}

/* Elevation pass — product cards previously had no depth at all. */
.pd-card{box-shadow:var(--mh-shadow-sm);
    transition:transform .22s ease, box-shadow .22s ease}
.pd-card:hover{transform:translateY(-4px);box-shadow:var(--mh-shadow-md)}

@media (prefers-reduced-motion:reduce){
    .rank-row--link,.pd-card{transition:none}
    .rank-row--link:hover,.pd-card:hover{transform:none}
}
/* ---------------------------------------------------------------------------
   Product-card elevation — a deliberate exception, 2026-08-19.

   `.site-public .card` sets box-shadow:none on purpose: the public site's
   card language is flat, lifting only on hover. That is a considered choice
   and the rest of it stands.

   Product cards are the exception because they are the one card on the page
   a visitor is meant to reach for. Matching the 0,2,0 specificity of the flat
   rule rather than escalating with !important, so the intent stays readable
   to whoever edits this next.
   --------------------------------------------------------------------------- */
.site-public .pd-card{box-shadow:var(--mh-shadow-sm)}
.site-public .pd-card:hover,
.site-public .pd-card:focus-within{box-shadow:var(--mh-shadow-md)}
/* ===========================================================================
   HERO STAGE (added 2026-08-19)
   The first screen of the public site. Depth carries information here: the
   shop's own facts sit in front of a real customer photograph, rather than
   ornament sitting in front of nothing.

   Grid + flex with gap throughout. Nothing is absolutely positioned over
   text, so the two columns cannot overlap at any viewport — the floating
   cards are anchored inside the photograph's own fixed-ratio box.
   =========================================================================== */
.mh-stage{position:relative;overflow:hidden;isolation:isolate;
    background:linear-gradient(165deg,#05070B 0%,#0B1018 55%,#070A10 100%)}
.mh-stage::before{content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
    background:
        radial-gradient(42% 40% at 20% 16%, rgba(11,92,255,.34), transparent 68%),
        radial-gradient(36% 38% at 84% 26%, rgba(14,122,87,.20), transparent 70%),
        radial-gradient(64% 44% at 50% 112%, rgba(255,255,255,.07), transparent 72%)}
.mh-stage__in{position:relative;z-index:1;display:grid;gap:2.5rem;align-items:center;
    padding-top:3.25rem;padding-bottom:3.5rem}
@media(min-width:992px){.mh-stage__in{grid-template-columns:1.03fr .97fr;gap:3rem;
    padding-top:4.5rem;padding-bottom:4.75rem}}

.mh-stage__copy{display:flex;flex-direction:column;gap:1.1rem;min-width:0}
.mh-stage__loc{font-size:.7rem;letter-spacing:.16em;text-transform:uppercase;
    color:var(--mh-muted-on-dark)}
.mh-stage__h1{color:#F5F7FA;font-size:clamp(2rem,4.6vw,3.4rem);line-height:1.05;
    letter-spacing:-.035em;margin:0;text-wrap:balance}
.mh-stage__lead{color:var(--mh-muted-on-dark);font-size:clamp(.96rem,1.4vw,1.09rem);
    max-width:46ch;margin:0}
.mh-stage__chips{display:flex;flex-wrap:wrap;gap:.5rem}
.mh-chip-fact{display:inline-flex;align-items:center;gap:.3rem;font-size:.76rem;font-weight:600;
    color:#EDF1F7;background:rgba(255,255,255,.09);border:1px solid rgba(255,255,255,.16);
    border-radius:999px;padding:.32rem .72rem;white-space:nowrap}
.mh-chip-fact b{color:var(--mh-accent-on-dark);font-weight:800}
.mh-stage__cta{display:flex;flex-wrap:wrap;gap:.7rem}
.mh-btn-glass{background:rgba(255,255,255,.11);color:#fff;border:1px solid rgba(255,255,255,.24);
    backdrop-filter:blur(10px)}
.mh-btn-glass:hover{background:rgba(255,255,255,.2);color:#fff}
.mh-stage__shelf{font-size:.83rem;color:var(--mh-muted-on-dark);margin:.15rem 0 0}
.mh-stage__shelf a{color:var(--mh-accent-on-dark);text-decoration:none;font-weight:600}
.mh-stage__shelf a:hover{text-decoration:underline}

/* --- the photograph, on a perspective stage --- */
.mh-compo{position:relative;perspective:1500px;min-width:0}
.mh-compo__inner{position:relative;transform-style:preserve-3d;
    transform:rotateY(-11deg) rotateX(5deg);
    transition:transform .55s cubic-bezier(.2,.7,.3,1)}
.mh-compo:hover .mh-compo__inner{transform:rotateY(-5deg) rotateX(2deg)}
.mh-compo__shot,.mh-compo__back{margin:0;border-radius:1.4rem;overflow:hidden;
    border:1px solid rgba(255,255,255,.14);background:#0B0F16}
.mh-compo__shot{box-shadow:0 44px 90px rgba(0,0,0,.6), 0 12px 28px rgba(0,0,0,.4);
    aspect-ratio:1/.94}
.mh-compo__shot img,.mh-compo__back img{width:100%;height:100%;object-fit:cover;display:block}
/* Second photo sits behind and to the side, giving the stack real depth
   without competing with the face in front. */
.mh-compo__back{position:absolute;inset:0;transform:translateZ(-70px) translateX(9%) rotate(4deg);
    filter:saturate(.85) brightness(.82);opacity:.9;aspect-ratio:1/.94}

.mh-float{position:absolute;background:rgba(255,255,255,.82);
    backdrop-filter:blur(18px) saturate(160%);border:1px solid rgba(255,255,255,.6);
    border-radius:1rem;box-shadow:0 20px 44px rgba(0,0,0,.34);padding:.7rem .9rem;color:#0B0F16}
.mh-float--grade{right:-.6rem;top:1.4rem;transform:translateZ(105px);text-align:center}
.mh-float__g{display:block;font-size:1.3rem;font-weight:800;color:var(--mh-accent);line-height:1}
.mh-float__t{display:block;font-size:.57rem;letter-spacing:.08em;text-transform:uppercase;
    color:var(--mh-muted);font-weight:700;margin-top:.15rem}
.mh-float--fact{left:-1rem;bottom:1.4rem;transform:translateZ(78px);min-width:10.5rem}
.mh-float__l{display:block;font-size:.62rem;letter-spacing:.08em;text-transform:uppercase;
    color:var(--mh-muted);font-weight:700}
.mh-float__v{display:block;font-size:1.15rem;font-weight:800;letter-spacing:-.02em;margin-top:.08rem}
.mh-float__s{display:block;font-size:.68rem;color:var(--mh-muted);margin-top:.1rem}

@media(max-width:575.98px){
    .mh-float--grade{right:.4rem;top:.6rem;padding:.5rem .65rem}
    .mh-float--fact{left:.4rem;bottom:.6rem;min-width:8.6rem;padding:.55rem .7rem}
    .mh-compo__inner{transform:rotateY(-7deg) rotateX(3deg)}
}
@media (prefers-reduced-motion:reduce){
    .mh-compo__inner{transform:none;transition:none}
    .mh-compo:hover .mh-compo__inner{transform:none}
}
/* ---------------------------------------------------------------------------
   Hero text colour — corrective, 2026-08-19.

   `.mh-stage__h1` (0,1,0) was losing to an existing `.site-public h1` rule
   (0,1,1), so the headline rendered in the light-theme ink colour on a dark
   ground and was effectively invisible. Same specificity trap as the flat-card
   rule. Scoping under `.mh-stage` raises these to 0,2,0 and 0,2,1 so they win
   without resorting to !important.

   The headline is white fading into the brand's on-dark blue. The solid colour
   is declared FIRST and only replaced inside @supports — without that, a
   browser lacking background-clip:text would paint transparent text on a dark
   background and show nothing at all.
   --------------------------------------------------------------------------- */
.mh-stage .mh-stage__h1{color:#FFFFFF}

@supports ((-webkit-background-clip:text) or (background-clip:text)){
    .mh-stage .mh-stage__h1{
        background-image:linear-gradient(104deg,#FFFFFF 0%,#FFFFFF 38%,#CFE0FF 62%,#7AA5FF 100%);
        -webkit-background-clip:text;
        background-clip:text;
        -webkit-text-fill-color:transparent;
        color:transparent;
    }
}

.mh-stage .mh-stage__lead{color:#C3CDDC}
.mh-stage .mh-stage__loc{color:#8FA0B6}
.mh-stage .mh-stage__shelf{color:#A9B6C7}
.mh-stage .mh-stage__shelf a{color:#7AA5FF}
.mh-stage .mh-chip-fact{color:#EDF1F7}
.mh-stage .mh-chip-fact b{color:#7AA5FF}
/* The floating cards sit on a light glass panel, so their text stays dark. */
.mh-stage .mh-float{color:#0B0F16}
.mh-stage .mh-float__g{color:#0B5CFF}
/* ===========================================================================
   QUICK VALUATION (added 2026-08-20)
   The visual customer journey: who you are → brand → model → variant → price.

   Built as its own `qv__` namespace rather than reusing the app's form styles,
   because the whole point of the rebuild is that this must NOT look like the
   rest of the admin-shaped UI. It is scoped to `.qv`, so nothing here can leak
   into the pages that share this stylesheet.

   The price is the only red on the page. Red means "the number" and nothing
   else, so it cannot be diluted.
   =========================================================================== */
.qv{
    --qv-ink:#0B0F16; --qv-muted:#64707F; --qv-line:#E4E9F0; --qv-line-2:#CFD8E3;
    --qv-page:#EEF2F8; --qv-card:#FFFFFF; --qv-soft:#F5F8FD;
    --qv-blue:#0B5CFF; --qv-blue-dark:#0740B8; --qv-blue-wash:#EAF0FF;
    --qv-red:#E01B33; --qv-red-wash:#FDEEF0;
    --qv-green:#0E7A57; --qv-green-wash:#E7F6EF;
    --qv-r:14px; --qv-r-lg:18px;
    --qv-sh:0 1px 2px rgba(11,15,22,.05);
    --qv-sh-2:0 6px 20px rgba(11,15,22,.08), 0 2px 6px rgba(11,15,22,.04);
    --qv-sh-3:0 18px 44px rgba(11,15,22,.14), 0 4px 12px rgba(11,15,22,.06);
    background:var(--qv-page); padding:1.25rem 1rem 3rem; min-height:70vh;
    font-family:"Public Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    color:var(--qv-ink);
}
/* Centred journey column.

   SUPERSEDED 2026-08-26 — the 560/620px caps below are overridden by the
   responsive block at the end of this file. Kept as the base declaration
   (mobile-first) rather than deleted, because the surface styling here is
   still in use; only the width is replaced.

   The original comment argued that nine brand tiles across 1600px "reads as
   a spreadsheet". Half right: the answer to content that does not fill a
   wide screen is a grid that reflows into it, not a container that refuses
   the width. As written it left ~1300px of dead page on a 1920px monitor and
   pushed 121 model cards into a 3-wide strip. See the responsive block. */
.qv__shell{max-width:560px;margin:0 auto;background:var(--qv-card);
    border:1px solid var(--qv-line);border-radius:var(--qv-r-lg);
    box-shadow:var(--qv-sh-3);overflow:hidden}
@media(min-width:992px){ .qv__shell{max-width:620px} }

.qv__bar{display:flex;align-items:center;justify-content:space-between;gap:1rem;
    padding:.85rem 1.1rem;border-bottom:1px solid var(--qv-line);background:var(--qv-card)}
.qv__brandmark{display:flex;align-items:center;gap:.55rem}
.qv__logo{display:grid;place-items:center;width:30px;height:30px;border-radius:9px;
    background:var(--qv-blue);color:#fff;font-weight:800;font-size:.72rem;letter-spacing:-.02em}
.qv__brandmark strong{display:block;font-size:.9rem;font-weight:700;letter-spacing:-.01em;line-height:1.15}
.qv__brandmark small{display:block;font-size:.66rem;color:var(--qv-muted)}
.qv__secure{display:inline-flex;align-items:center;gap:.35rem;font-size:.7rem;font-weight:600;
    color:var(--qv-muted);white-space:nowrap}

.qv__panel{padding:1.35rem 1.1rem 0}
.qv__head{display:flex;align-items:flex-start;gap:.7rem;margin-bottom:1.1rem}
.qv__num{display:grid;place-items:center;flex:0 0 auto;width:1.85rem;height:1.85rem;border-radius:999px;
    background:var(--qv-blue);color:#fff;font-weight:800;font-size:.85rem}
.qv__title{font-size:1.18rem;font-weight:800;letter-spacing:-.025em;margin:0;line-height:1.25}
.qv__sub{font-size:.83rem;color:var(--qv-muted);margin:.15rem 0 0}

/* --- step 0 form --- */
.qv__form{display:block;margin-bottom:1.25rem}
.qv__label{display:block;font-size:.78rem;font-weight:600;margin:.9rem 0 .35rem}
.qv__input{width:100%;border:1px solid var(--qv-line-2);border-radius:10px;padding:.7rem .85rem;
    font-size:.95rem;color:var(--qv-ink);background:var(--qv-card);transition:border-color .15s ease, box-shadow .15s ease}
.qv__input:focus{outline:none;border-color:var(--qv-blue);box-shadow:0 0 0 3px var(--qv-blue-wash)}
.qv__input.is-bad{border-color:var(--qv-red);box-shadow:0 0 0 3px var(--qv-red-wash)}
.qv__prefix{display:flex;align-items:stretch;gap:.5rem}
.qv__prefix > span{display:grid;place-items:center;padding:0 .8rem;border:1px solid var(--qv-line-2);
    border-radius:10px;background:var(--qv-soft);font-weight:700;font-size:.9rem;color:var(--qv-muted)}
.qv__prefix .qv__input{flex:1}
.qv__err{color:var(--qv-red);font-size:.76rem;font-weight:600;margin:.35rem 0 0}
.qv__hint{font-size:.74rem;color:var(--qv-muted);margin:.5rem 0 0}

.qv__trust{display:grid;grid-template-columns:repeat(3,1fr);gap:.5rem;margin-bottom:1.1rem}
.qv__trustitem,.qv__assure > div{display:flex;align-items:center;gap:.45rem;padding:.6rem .5rem;
    background:var(--qv-soft);border:1px solid var(--qv-line);border-radius:10px}
.qv__ti{display:grid;place-items:center;width:1.6rem;height:1.6rem;flex:0 0 auto;border-radius:8px;
    background:var(--qv-blue-wash);color:var(--qv-blue);font-size:.8rem}
.qv__trustitem strong,.qv__assure strong{display:block;font-size:.72rem;font-weight:700;line-height:1.2}
.qv__trustitem small,.qv__assure small{display:block;font-size:.65rem;color:var(--qv-muted)}

/* --- brand + model grid --- */
.qv__grid{display:grid;grid-template-columns:repeat(3,1fr);gap:.6rem}
@media(max-width:400px){ .qv__grid{grid-template-columns:repeat(2,1fr)} }
.qv__card{display:flex;flex-direction:column;align-items:center;gap:.5rem;
    padding:.95rem .5rem;background:var(--qv-card);border:1px solid var(--qv-line);
    border-radius:var(--qv-r);cursor:pointer;text-align:center;
    transition:transform .16s ease, box-shadow .16s ease, border-color .16s ease;
    box-shadow:var(--qv-sh)}
.qv__card:hover{transform:translateY(-2px);box-shadow:var(--qv-sh-2);border-color:var(--qv-line-2)}
.qv__card:focus-visible{outline:2px solid var(--qv-blue);outline-offset:2px}
.qv__card.is-on{border-color:var(--qv-blue);box-shadow:0 0 0 2px var(--qv-blue-wash), var(--qv-sh-2)}
.qv__cardimg{display:grid;place-items:center;height:2.4rem;width:100%}
.qv__cardimg img{max-height:2.2rem;max-width:80%;object-fit:contain}
.qv__mono{font-weight:800;font-size:1.05rem;letter-spacing:-.03em;color:var(--qv-ink)}
.qv__cardname{font-size:.76rem;font-weight:600;line-height:1.2}

.qv__grid--models .qv__card{padding:.7rem .45rem .8rem}
.qv__badgewrap{align-self:flex-end;min-height:1rem}
.qv__new{font-size:.55rem;font-weight:800;letter-spacing:.04em;padding:.1rem .3rem;border-radius:4px;
    background:var(--qv-green-wash);color:var(--qv-green)}
.qv__phone{display:grid;place-items:center;height:4.6rem;width:100%}
.qv__phone img{max-height:4.4rem;max-width:70%;object-fit:contain}
/* Drawn stand-in until the owner uploads a photo. Reads as a device rather
   than as a broken image. */
.qv__phoneshape{display:block;width:2.1rem;height:4.1rem;border-radius:7px;
    background:linear-gradient(150deg,#2A3342,#0C111A);
    box-shadow:inset 0 0 0 2px rgba(255,255,255,.09), var(--qv-sh)}
.qv__year{font-size:.66rem;color:var(--qv-muted)}

.qv__chips{display:flex;gap:.4rem;overflow-x:auto;padding-bottom:.6rem;margin-bottom:.7rem;
    scrollbar-width:none}
.qv__chips::-webkit-scrollbar{display:none}
.qv__chip{flex:0 0 auto;padding:.35rem .75rem;border-radius:999px;border:1px solid var(--qv-line-2);
    background:var(--qv-card);font-size:.74rem;font-weight:600;color:var(--qv-muted);cursor:pointer;
    white-space:nowrap;transition:background-color .15s ease,color .15s ease,border-color .15s ease}
.qv__chip.is-on{background:var(--qv-blue);border-color:var(--qv-blue);color:#fff}
.qv__chip:focus-visible{outline:2px solid var(--qv-blue);outline-offset:2px}

.qv__back{display:flex;align-items:center;gap:.6rem;margin-bottom:.9rem}
.qv__backbtn{width:2rem;height:2rem;border-radius:999px;border:1px solid var(--qv-line-2);
    background:var(--qv-card);cursor:pointer;font-size:1rem;line-height:1;color:var(--qv-ink)}
.qv__backbtn:hover{background:var(--qv-soft)}
.qv__crumb{font-weight:700;font-size:.9rem}

.qv__picked{display:flex;align-items:center;gap:.8rem;padding:.7rem .85rem;background:var(--qv-soft);
    border:1px solid var(--qv-line);border-radius:var(--qv-r);margin-bottom:1.1rem}
.qv__pickedimg{display:grid;place-items:center;width:3rem;height:3.4rem;flex:0 0 auto}
.qv__pickedimg img{max-height:3.3rem;max-width:100%;object-fit:contain}
.qv__picked strong{display:block;font-size:.95rem;font-weight:700;letter-spacing:-.02em}
.qv__picked small{display:block;font-size:.72rem;color:var(--qv-muted);margin-top:.1rem}

/* --- variants --- */
.qv__variants{display:grid;gap:.5rem;margin-bottom:1.1rem}
.qv__variant{display:flex;align-items:center;gap:.65rem;padding:.75rem .85rem;
    background:var(--qv-card);border:1px solid var(--qv-line);border-radius:12px;cursor:pointer;
    text-align:left;transition:border-color .15s ease, background-color .15s ease}
.qv__variant:hover{border-color:var(--qv-line-2)}
.qv__variant:focus-visible{outline:2px solid var(--qv-blue);outline-offset:2px}
.qv__variant.is-on{border-color:var(--qv-blue);background:var(--qv-blue-wash)}
.qv__radio{width:1.05rem;height:1.05rem;flex:0 0 auto;border-radius:999px;
    border:2px solid var(--qv-line-2);background:var(--qv-card);position:relative}
.qv__variant.is-on .qv__radio{border-color:var(--qv-blue)}
.qv__variant.is-on .qv__radio::after{content:"";position:absolute;inset:3px;border-radius:999px;background:var(--qv-blue)}
.qv__vlabel{font-size:.88rem;font-weight:600;flex:1}
.qv__pop{font-size:.58rem;font-weight:800;letter-spacing:.03em;padding:.12rem .38rem;border-radius:5px;
    background:var(--qv-blue);color:#fff;white-space:nowrap}
.qv__vdelta{font-size:.8rem;font-weight:700;color:var(--qv-muted);font-variant-numeric:tabular-nums;white-space:nowrap}

/* --- the price --- */
.qv__price{background:var(--qv-red-wash);border:1px solid #F6D3D8;border-radius:var(--qv-r);
    padding:1.3rem 1rem;text-align:center;margin-bottom:.9rem}
.qv__pricelabel{font-size:.86rem;font-weight:700;margin:0;color:var(--qv-ink)}
.qv__priceupto{font-size:.72rem;color:var(--qv-muted);margin:.1rem 0 .2rem;font-weight:600}
.qv__pricebig{font-size:clamp(2.1rem,9vw,2.9rem);font-weight:800;letter-spacing:-.035em;
    color:var(--qv-red);margin:0;line-height:1.05;font-variant-numeric:tabular-nums}
.qv__pricenote{display:inline-flex;align-items:center;gap:.35rem;font-size:.75rem;font-weight:600;
    color:var(--qv-green);margin:.55rem 0 0}
.qv__pricenote--wait{display:block;color:var(--qv-muted);font-weight:500;line-height:1.5;max-width:38ch;margin:.4rem auto 0}

.qv__assure{display:grid;grid-template-columns:repeat(3,1fr);gap:.5rem;margin-bottom:1rem}

/* --- actions --- */
.qv__cta{display:block;width:100%;padding:.9rem 1rem;border:none;border-radius:12px;
    background:var(--qv-blue);color:#fff;font-size:.98rem;font-weight:700;cursor:pointer;
    box-shadow:0 8px 20px rgba(11,92,255,.26);transition:transform .16s ease, background-color .16s ease}
.qv__cta:hover{background:var(--qv-blue-dark);transform:translateY(-1px)}
.qv__cta:focus-visible{outline:2px solid var(--qv-ink);outline-offset:2px}
.qv__cta--dark{background:#0B0F16;box-shadow:0 8px 20px rgba(11,15,22,.28)}
.qv__cta--dark:hover{background:#000}
.qv__missing{display:block;width:100%;margin-top:.9rem;padding:.7rem;border-radius:10px;
    border:1px dashed var(--qv-line-2);background:var(--qv-card);color:var(--qv-blue);
    font-size:.83rem;font-weight:700;cursor:pointer}
.qv__missing:hover{background:var(--qv-blue-wash)}

.qv__foot{display:flex;align-items:center;justify-content:center;gap:.35rem;font-size:.72rem;
    color:var(--qv-muted);margin:1.1rem 0 .9rem}
.qv__stepbar{margin:1.1rem -1.1rem 0;padding:.75rem;background:var(--qv-blue);color:#fff;
    text-align:center;font-size:.85rem;font-weight:700}

@media (prefers-reduced-motion:reduce){
    .qv__card,.qv__cta,.qv__chip,.qv__variant,.qv__input{transition:none}
    .qv__card:hover,.qv__cta:hover{transform:none}
}

/* ---------------------------------------------------------------------------
   Quick Valuation — device placeholder + logo rendering (2026-08-20)

   The first placeholder was a black slab, which read as a dead image rather
   than as a pending one. This is a light device OUTLINE carrying the brand
   mark: it is obviously a stand-in, it matches the surrounding card, and it
   never pretends to be a photograph of the handset.

   simple-icons marks are monochrome single-path SVGs. Rendering them in ink
   rather than brand colours keeps twenty different logos looking like one
   considered set, and sidesteps reproducing trademarked colourways.
   --------------------------------------------------------------------------- */
.qv .qv__ghost{
    display:grid; place-items:center;
    width:2.5rem; height:4.4rem;
    border-radius:9px;
    background:linear-gradient(160deg,#FFFFFF 0%, #F2F6FD 55%, #E8EEF8 100%);
    border:1.5px solid var(--qv-line-2);
    box-shadow:inset 0 1px 0 #fff, 0 1px 2px rgba(11,15,22,.06);
}
.qv .qv__ghost--sm{width:2rem;height:3.4rem;border-radius:7px}
.qv .qv__ghostlogo{width:1.15rem;height:1.15rem;object-fit:contain;opacity:.32}
.qv .qv__ghost--sm .qv__ghostlogo{width:.95rem;height:.95rem}
.qv .qv__ghostmono{font-size:.68rem;font-weight:800;color:var(--qv-line-2);letter-spacing:-.02em}

/* Brand tiles: contain the mark, keep it ink-coloured and evenly sized so a
   wide wordmark and a square glyph still look like siblings. */
.qv .qv__cardimg img{max-height:1.9rem;max-width:72%;object-fit:contain;
    filter:grayscale(1) contrast(1.15); opacity:.86}
.qv .qv__card.is-on .qv__cardimg img{filter:none;opacity:1}
.qv .qv__card:hover .qv__cardimg img{opacity:1}
/* ==========================================================================
   Valuation Management (/app/staff/valuations)
   --------------------------------------------------------------------------
   A modern administration console, built on the same tokens as everything
   else. Prefixed `vm-` throughout so none of it can reach another screen.

   ON COLOUR. Design.md's rule for the app is: brand colour in the chrome
   only, content area neutral so STATUS colour can carry meaning. With 21
   stock statuses and 11 each of repair/lending/lead, an accent spent on
   decoration leaves nothing to say "overdue".

   That rule is kept. Every tint below sits on an ICON TILE or a bar, never
   on text and never on a row background. Tile colour is a wayfinding cue for
   a group -- battery is the green one -- which is what makes a long settings
   page scannable. Status still owns status: pills use the positive/review/red
   families and nothing decorative is allowed near them.

   ON SPECIFICITY. Nothing here reuses .card, .stat-tile or any other existing
   class, so there is no specificity contest to lose. Both collisions this
   project hit (.site-public .card beating .pd-card, .site-public h1 beating
   .mh-stage__h1) came from decorating a shared class. New surfaces get new
   names instead.
   ========================================================================== */

.vm {
    --vm-radius: 0.875rem;
    --vm-radius-sm: 0.5rem;
    --vm-line: #E9E9EE;
    --vm-shadow: 0 1px 2px rgba(16, 24, 40, .04), 0 1px 3px rgba(16, 24, 40, .06);
    --vm-shadow-lift: 0 4px 12px rgba(16, 24, 40, .08);

    /* Soft tile tints, each with an ink that clears 4.5:1 on its own tint. */
    --vm-blue-bg: #EAF1FF;    --vm-blue-ink: #1B4FD8;
    --vm-emerald-bg: #E6F6EE; --vm-emerald-ink: #16714A;
    --vm-violet-bg: #F0EBFE;  --vm-violet-ink: #5B34C4;
    --vm-amber-bg: #FDF2DC;   --vm-amber-ink: #8A5A00;
    --vm-sky-bg: #E4F3FC;     --vm-sky-ink: #10627F;
    --vm-rose-bg: #FDEAF1;    --vm-rose-ink: #A32552;
    --vm-orange-bg: #FEEEE3;  --vm-orange-ink: #9A4A12;
    --vm-indigo-bg: #ECEDFD;  --vm-indigo-ink: #3B3FBF;
    --vm-red-bg: #FDEAEA;     --vm-red-ink: #A32020;
    --vm-slate-bg: #EEF0F4;   --vm-slate-ink: #47526B;
}

/* ---------- page header ---------- */

.vm-head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem 1.5rem;
    margin-bottom: 1.5rem;
}

.vm-head__title {
    font-size: clamp(1.5rem, 2.2vw, 1.875rem);
    font-weight: 700;
    letter-spacing: -0.02em;
    color: var(--mh-ink);
    margin: 0 0 .25rem;
}

.vm-head__sub {
    font-size: .875rem;
    color: var(--mh-muted);
    margin: 0;
    max-width: 62ch;
}

.vm-head__actions { display: flex; flex-wrap: wrap; gap: .5rem; }

/* ---------- KPI strip ---------- */

.vm-kpis {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: .875rem;
    margin-bottom: 1.5rem;
}

.vm-kpi {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: .75rem;
    padding: 1.125rem 1.25rem;
    background: var(--mh-white);
    border: 1px solid var(--vm-line);
    border-radius: var(--vm-radius);
    box-shadow: var(--vm-shadow);
    text-decoration: none;
    color: inherit;
    transition: box-shadow .15s ease, transform .15s ease, border-color .15s ease;
}

a.vm-kpi:hover,
a.vm-kpi:focus-visible {
    box-shadow: var(--vm-shadow-lift);
    border-color: #D7DBE3;
    transform: translateY(-1px);
    color: inherit;
}

.vm-kpi__label {
    font-size: .75rem;
    font-weight: 600;
    letter-spacing: .01em;
    color: var(--mh-muted);
    margin-bottom: .35rem;
}

.vm-kpi__value {
    font-size: 1.75rem;
    line-height: 1.1;
    font-weight: 700;
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
    color: var(--mh-ink);
}

.vm-kpi__sub { font-size: .75rem; margin-top: .35rem; color: var(--mh-muted); }

/* The one place a KPI sub-line may shout: a figure that needs acting on.
   Always paired with a word, never carried by colour alone. */
.vm-kpi__sub.is-alert { color: var(--vm-red-ink); font-weight: 600; }
.vm-kpi__sub.is-good  { color: var(--vm-emerald-ink); font-weight: 600; }

.vm-tile {
    flex: 0 0 auto;
    width: 2.75rem;
    height: 2.75rem;
    display: grid;
    place-items: center;
    border-radius: var(--vm-radius-sm);
    background: var(--vm-slate-bg);
    color: var(--vm-slate-ink);
}

.vm-tile svg { width: 1.25rem; height: 1.25rem; }
.vm-tile--sm { width: 2.25rem; height: 2.25rem; border-radius: .5rem; }
.vm-tile--sm svg { width: 1.05rem; height: 1.05rem; }

.vm-tile--blue    { background: var(--vm-blue-bg);    color: var(--vm-blue-ink); }
.vm-tile--emerald { background: var(--vm-emerald-bg); color: var(--vm-emerald-ink); }
.vm-tile--violet  { background: var(--vm-violet-bg);  color: var(--vm-violet-ink); }
.vm-tile--amber   { background: var(--vm-amber-bg);   color: var(--vm-amber-ink); }
.vm-tile--sky     { background: var(--vm-sky-bg);     color: var(--vm-sky-ink); }
.vm-tile--rose    { background: var(--vm-rose-bg);    color: var(--vm-rose-ink); }
.vm-tile--orange  { background: var(--vm-orange-bg);  color: var(--vm-orange-ink); }
.vm-tile--indigo  { background: var(--vm-indigo-bg);  color: var(--vm-indigo-ink); }
.vm-tile--red     { background: var(--vm-red-bg);     color: var(--vm-red-ink); }

/* ---------- tab strip ---------- */

.vm-tabs {
    display: flex;
    gap: .25rem;
    overflow-x: auto;
    scrollbar-width: thin;
    border-bottom: 1px solid var(--vm-line);
    margin-bottom: 1.5rem;
}

.vm-tab {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    padding: .75rem 1rem;
    font-size: .875rem;
    font-weight: 600;
    color: var(--mh-muted);
    text-decoration: none;
    white-space: nowrap;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    border-radius: .5rem .5rem 0 0;
    transition: color .15s ease, background-color .15s ease;
}

.vm-tab svg { width: 1.05rem; height: 1.05rem; opacity: .85; }
.vm-tab:hover { color: var(--mh-ink); background: var(--mh-surface-frame); }
.vm-tab.is-active { color: var(--mh-accent); border-bottom-color: var(--mh-accent); }
.vm-tab.is-active svg { opacity: 1; }

/* A count on the tab itself, so "18 pending" is visible without opening it. */
.vm-tab__count {
    font-size: .6875rem;
    font-weight: 700;
    padding: .1rem .4rem;
    border-radius: 999px;
    background: var(--vm-slate-bg);
    color: var(--vm-slate-ink);
    font-variant-numeric: tabular-nums;
}

.vm-tab.is-active .vm-tab__count { background: var(--vm-blue-bg); color: var(--vm-blue-ink); }
.vm-tab__count.is-alert { background: var(--vm-red-bg); color: var(--vm-red-ink); }

/* ---------- panels ---------- */

.vm-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr));
    gap: 1.25rem;
    align-items: start;
}

.vm-panel {
    background: var(--mh-white);
    border: 1px solid var(--vm-line);
    border-radius: var(--vm-radius);
    box-shadow: var(--vm-shadow);
    overflow: hidden;
}

.vm-panel + .vm-panel { margin-top: 1.25rem; }

.vm-panel__head {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: 1rem 1.25rem;
    border-bottom: 1px solid var(--vm-line);
}

.vm-panel__title {
    font-size: .9375rem;
    font-weight: 700;
    color: var(--mh-ink);
    margin: 0;
    letter-spacing: -0.01em;
}

.vm-panel__note { font-size: .75rem; color: var(--mh-muted); margin: .15rem 0 0; }
.vm-panel__action { margin-left: auto; font-size: .8125rem; font-weight: 600; }
.vm-panel__body { padding: 1.25rem; }
.vm-panel__body--flush { padding: 0; }

/* ---------- configuration row list ---------- */

.vm-rows { display: flex; flex-direction: column; }

.vm-row {
    display: flex;
    align-items: center;
    gap: .875rem;
    padding: .875rem 1.25rem;
    border-bottom: 1px solid var(--vm-line);
    text-decoration: none;
    color: inherit;
    transition: background-color .12s ease;
}

.vm-row:last-child { border-bottom: 0; }
.vm-row:hover { background: #FAFAFB; color: inherit; }
.vm-row__main { min-width: 0; flex: 1; }
.vm-row__title { font-size: .875rem; font-weight: 600; color: var(--mh-ink); margin: 0; }
.vm-row__sub { font-size: .75rem; color: var(--mh-muted); margin: .1rem 0 0; }
.vm-row__end { margin-left: auto; display: flex; align-items: center; gap: .75rem; }
.vm-row__chev { color: #A1A1AA; display: grid; place-items: center; }
.vm-row__chev svg { width: 1rem; height: 1rem; }

/* ---------- pills ---------- */

.vm-pill {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    font-size: .6875rem;
    font-weight: 700;
    letter-spacing: .01em;
    padding: .25rem .55rem;
    border-radius: 999px;
    background: var(--vm-slate-bg);
    color: var(--vm-slate-ink);
    white-space: nowrap;
}

.vm-pill svg { width: .8rem; height: .8rem; }
.vm-pill--ok     { background: var(--vm-emerald-bg); color: var(--vm-emerald-ink); }
.vm-pill--warn   { background: var(--vm-amber-bg);   color: var(--vm-amber-ink); }
.vm-pill--danger { background: var(--vm-red-bg);     color: var(--vm-red-ink); }
.vm-pill--info   { background: var(--vm-blue-bg);    color: var(--vm-blue-ink); }
.vm-pill--muted  { background: var(--vm-slate-bg);   color: var(--vm-slate-ink); }

/* ---------- brand share bars ---------- */

.vm-bar { display: flex; align-items: center; gap: .75rem; padding: .45rem 0; }
.vm-bar__logo { width: 1.5rem; height: 1.5rem; flex: 0 0 auto; object-fit: contain; }
.vm-bar__name { font-size: .8125rem; font-weight: 600; width: 5.5rem; flex: 0 0 auto; color: var(--mh-ink); }
.vm-bar__track { flex: 1; height: .5rem; border-radius: 999px; background: var(--mh-surface-frame); overflow: hidden; }
.vm-bar__fill { height: 100%; border-radius: 999px; background: var(--mh-accent); }
.vm-bar__count { font-size: .8125rem; font-weight: 700; font-variant-numeric: tabular-nums; width: 2.75rem; text-align: right; color: var(--mh-ink); }

/* ---------- tables ---------- */

.vm-table-wrap { overflow-x: auto; }
.vm-table { width: 100%; border-collapse: collapse; font-size: .8125rem; }

.vm-table th {
    text-align: left;
    font-size: .6875rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--mh-muted);
    padding: .75rem 1rem;
    border-bottom: 1px solid var(--vm-line);
    background: #FCFCFD;
    white-space: nowrap;
}

.vm-table td {
    padding: .75rem 1rem;
    border-bottom: 1px solid var(--vm-line);
    vertical-align: middle;
    color: var(--mh-ink);
}

.vm-table tbody tr:last-child td { border-bottom: 0; }
.vm-table tbody tr:hover { background: #FAFAFB; }
.vm-table .num { text-align: right; font-variant-numeric: tabular-nums; }
.vm-table .vm-up { color: var(--vm-emerald-ink); font-weight: 600; }
.vm-table .vm-down { color: var(--vm-red-ink); font-weight: 600; }

.vm-thumb {
    width: 2.25rem;
    height: 2.75rem;
    object-fit: contain;
    border-radius: .375rem;
    background: var(--mh-surface-frame);
    flex: 0 0 auto;
}

.vm-thumb--empty { display: grid; place-items: center; color: #A1A1AA; }
.vm-thumb--empty svg { width: 1rem; height: 1rem; }

.vm-cell { display: flex; align-items: center; gap: .625rem; min-width: 0; }
.vm-cell__name { font-weight: 600; color: var(--mh-ink); }
.vm-cell__meta { font-size: .75rem; color: var(--mh-muted); }
.vm-actions { display: flex; gap: .375rem; justify-content: flex-end; flex-wrap: wrap; }

/* ---------- filters ---------- */

.vm-filters {
    display: flex;
    flex-wrap: wrap;
    gap: .625rem;
    align-items: center;
    padding: 1rem 1.25rem;
    border-bottom: 1px solid var(--vm-line);
    background: #FCFCFD;
}

.vm-filters .form-control,
.vm-filters .form-select {
    font-size: .8125rem;
    border-radius: var(--vm-radius-sm);
    border-color: var(--vm-line);
    min-height: 2.25rem;
}

.vm-filters .form-control { max-width: 16rem; }
.vm-filters .form-select { max-width: 12rem; }

/* ---------- buttons ---------- */

.vm-btn {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    font-size: .8125rem;
    font-weight: 600;
    padding: .45rem .8rem;
    border-radius: var(--vm-radius-sm);
    border: 1px solid var(--vm-line);
    background: var(--mh-white);
    color: var(--mh-ink);
    cursor: pointer;
    text-decoration: none;
    white-space: nowrap;
    transition: background-color .12s ease, border-color .12s ease, box-shadow .12s ease;
}

.vm-btn svg { width: .95rem; height: .95rem; }
.vm-btn:hover { background: var(--mh-surface-frame); color: var(--mh-ink); }

.vm-btn--primary { background: var(--mh-accent); border-color: var(--mh-accent); color: var(--mh-white); }
.vm-btn--primary:hover { background: var(--mh-accent-hover); border-color: var(--mh-accent-hover); color: var(--mh-white); }
.vm-btn--soft { background: var(--vm-blue-bg); border-color: transparent; color: var(--vm-blue-ink); }
.vm-btn--soft:hover { background: #DCE7FF; color: var(--vm-blue-ink); }
.vm-btn--danger-soft { background: var(--vm-red-bg); border-color: transparent; color: var(--vm-red-ink); }
.vm-btn--danger-soft:hover { background: #FBDCDC; color: var(--vm-red-ink); }
.vm-btn--sm { font-size: .75rem; padding: .3rem .6rem; }

/* Focus has to be obvious on every interactive surface, including the ones
   that are links dressed as cards or table rows. */
.vm-btn:focus-visible,
.vm-tab:focus-visible,
.vm-row:focus-visible,
a.vm-kpi:focus-visible,
.vm-summary:focus-visible {
    outline: 2px solid var(--mh-accent);
    outline-offset: 2px;
    border-radius: var(--vm-radius-sm);
}

/* ---------- inline editors (details/summary, no JS dependency) ---------- */

.vm-editor { border-bottom: 1px solid var(--vm-line); }
.vm-editor:last-child { border-bottom: 0; }

.vm-summary {
    display: flex;
    align-items: center;
    gap: .875rem;
    padding: .875rem 1.25rem;
    cursor: pointer;
    list-style: none;
}

.vm-summary::-webkit-details-marker { display: none; }
.vm-summary:hover { background: #FAFAFB; }
.vm-editor[open] > .vm-summary { background: #F7F8FA; border-bottom: 1px solid var(--vm-line); }
.vm-summary__chev { margin-left: auto; color: #A1A1AA; transition: transform .15s ease; }
.vm-summary__chev svg { width: 1rem; height: 1rem; display: block; }
.vm-editor[open] > .vm-summary .vm-summary__chev { transform: rotate(90deg); }
.vm-editor__body { padding: 1.125rem 1.25rem 1.25rem; background: #FCFCFD; }

/* ---------- rule grid ---------- */

.vm-rules {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 290px), 1fr));
    gap: .5rem 1.5rem;
}

.vm-rule { display: flex; align-items: center; gap: .75rem; padding: .35rem 0; }
.vm-rule__label { font-size: .8125rem; color: var(--mh-ink); flex: 1; min-width: 0; }
.vm-rule__hint { display: block; font-size: .6875rem; color: var(--mh-muted); }
.vm-rule__input { width: 6rem; flex: 0 0 auto; display: flex; align-items: center; gap: .3rem; }

.vm-rule__input input {
    width: 100%;
    font-size: .8125rem;
    text-align: right;
    font-variant-numeric: tabular-nums;
    padding: .35rem .5rem;
    border: 1px solid var(--vm-line);
    border-radius: var(--vm-radius-sm);
    background: var(--mh-white);
    color: var(--mh-ink);
}

.vm-rule__input input:focus { outline: 2px solid var(--mh-accent); outline-offset: 0; border-color: var(--mh-accent); }
.vm-rule__unit { font-size: .75rem; color: var(--mh-muted); flex: 0 0 auto; }

.vm-editor__foot {
    display: flex;
    align-items: center;
    gap: .625rem;
    flex-wrap: wrap;
    margin-top: 1rem;
    padding-top: .875rem;
    border-top: 1px solid var(--vm-line);
}

.vm-editor__foot .vm-hint { font-size: .75rem; color: var(--mh-muted); margin-left: auto; }

/* ---------- notices ---------- */

.vm-notice {
    display: flex;
    gap: .875rem;
    align-items: flex-start;
    padding: 1rem 1.125rem;
    border-radius: var(--vm-radius);
    border: 1px solid;
    margin-bottom: 1.25rem;
    font-size: .875rem;
}

.vm-notice__body { flex: 1; min-width: 0; }
.vm-notice__title { font-weight: 700; margin: 0 0 .2rem; }
.vm-notice p { margin: 0; }
.vm-notice p + p { margin-top: .4rem; }
.vm-notice--warn   { background: #FFFBF0; border-color: #F5DFAF; color: #6B4A00; }
.vm-notice--danger { background: #FEF6F6; border-color: #F3C9C9; color: #7A1C1C; }
.vm-notice--info   { background: #F5F8FF; border-color: #CFDDFB; color: #1B3F8F; }
.vm-notice--ok     { background: #F1FBF6; border-color: #BEE6D2; color: #14603F; }
.vm-notice a { color: inherit; font-weight: 600; }

/* ---------- empty states ---------- */

.vm-empty { padding: 2.5rem 1.25rem; text-align: center; color: var(--mh-muted); }

.vm-empty__icon {
    width: 2.75rem;
    height: 2.75rem;
    margin: 0 auto .75rem;
    display: grid;
    place-items: center;
    border-radius: 999px;
    background: var(--vm-emerald-bg);
    color: var(--vm-emerald-ink);
}

.vm-empty__icon svg { width: 1.25rem; height: 1.25rem; }
.vm-empty__title { font-size: .9375rem; font-weight: 600; color: var(--mh-ink); margin: 0 0 .2rem; }
.vm-empty p { font-size: .8125rem; margin: 0; }

/* ---------- form fields inside editors ---------- */

.vm-field { display: block; margin-bottom: .75rem; }
.vm-field__label { display: block; font-size: .75rem; font-weight: 600; color: var(--mh-muted); margin-bottom: .3rem; }
/* The one-line explanation under a control (2026-09-26). */
.vm-field__hint { display: block; font-size: .72rem; line-height: 1.45; color: var(--mh-muted); margin-top: .3rem; }

.vm-field .form-control,
.vm-field .form-select {
    font-size: .8125rem;
    border-radius: var(--vm-radius-sm);
    border-color: var(--vm-line);
    min-height: 2.25rem;
}

.vm-fieldset { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 190px), 1fr)); gap: 0 1rem; }
.vm-check { display: inline-flex; align-items: center; gap: .45rem; font-size: .8125rem; color: var(--mh-ink); }

/* ---------- pagination footer ---------- */

.vm-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    padding: .875rem 1.25rem;
    border-top: 1px solid var(--vm-line);
    background: #FCFCFD;
    font-size: .8125rem;
    color: var(--mh-muted);
}

.vm-foot .pagination { margin: 0; }

/* ---------- responsive ---------- */

@media (max-width: 767.98px) {
    .vm-kpis { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
    .vm-kpi { padding: .875rem 1rem; }
    .vm-kpi__value { font-size: 1.375rem; }
    .vm-tile { width: 2.25rem; height: 2.25rem; }
    .vm-tile svg { width: 1.05rem; height: 1.05rem; }
    .vm-filters .form-control,
    .vm-filters .form-select { max-width: 100%; flex: 1 1 100%; }
    .vm-head { flex-direction: column; align-items: stretch; }
    .vm-bar__name { width: 4.5rem; }
}

@media (prefers-reduced-motion: reduce) {
    .vm-kpi, .vm-btn, .vm-tab, .vm-row, .vm-summary__chev { transition: none; }
    a.vm-kpi:hover { transform: none; }
}

/* ==========================================================================
   Quick valuation — corrections, 2026-08-25
   --------------------------------------------------------------------------
   Three fixes, all found by walking the live journey rather than reading the
   markup. Appended rather than edited in place so the original block stays
   readable and the override is obvious.
   ========================================================================== */

/* ---- 1. Progress indicator replaces the button-shaped step bar ----------

   `.qv__stepbar` was solid --qv-blue, full width, white, bold, centred —
   pixel-for-pixel the same treatment as `.qv__cta`, the button that had just
   advanced the customer. On the price step it rendered directly beneath the
   real "Get final quote" button, so the screen ended in two stacked
   full-width bars and the brighter, lower one was inert.

   Status must not look like an action. Quiet surface, muted label, and a
   track that shows position. */

.qv__stepbar { display: none; }          /* belt and braces if any remain */

.qv__progress {
    margin: 1.15rem -1.1rem 0;
    padding: .7rem 1.1rem .85rem;
    background: #F7F8FA;
    border-top: 1px solid var(--qv-line);
}

.qv__progress__row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: .75rem;
    margin-bottom: .4rem;
}

.qv__progress__label {
    font-size: .74rem;
    font-weight: 700;
    letter-spacing: .01em;
    color: var(--qv-muted);
}

.qv__progress__pct {
    font-size: .7rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--qv-blue);
}

.qv__progress__track {
    display: block;
    height: .3rem;
    border-radius: 999px;
    background: #E3E6EC;
    overflow: hidden;
}

.qv__progress__fill {
    display: block;
    height: 100%;
    border-radius: 999px;
    background: var(--qv-blue);
    transition: width .25s ease;
}

/* ---- 2. Price disclaimer -------------------------------------------------

   Sits immediately under the figure, inside the same tinted panel. A
   disclaimer placed further down the page is read after the expectation has
   already been set, which is the same as not having one. */

.qv__pricedisc {
    margin: .6rem auto 0;
    max-width: 34rem;
    font-size: .72rem;
    line-height: 1.45;
    color: var(--qv-muted);
}

/* ---- 3. Brand marks -----------------------------------------------------

   Two problems in one grid.

   (a) Wide WORDMARKS (Nokia, Oppo, Asus, Honor) sat in a box sized for
       square glyph marks, so `max-width:80%` shrank them until the strokes
       read as faint. Giving the box a little more height and the image
       nearly the full width evens the optical weight without distorting
       anything.

   (b) Brands with no logo fell back to two bare letters, which reads as
       unfinished beside real marks. A neutral tile reads as designed. */

.qv__cardimg { height: 2.6rem; }
.qv__cardimg img { max-height: 2.35rem; max-width: 94%; }

.qv__monotile {
    display: grid;
    place-items: center;
    width: 2.3rem;
    height: 2.3rem;
    border-radius: .6rem;
    background: #EEF0F4;
    color: #47526B;
    font-weight: 800;
    font-size: .82rem;
    letter-spacing: -.02em;
}

.qv__card.is-on .qv__monotile {
    background: var(--qv-blue-wash);
    color: var(--qv-blue);
}

@media (prefers-reduced-motion: reduce) {
    .qv__progress__fill { transition: none; }
}

/* Monogram tile sized for up to four characters — see quick.blade.php for why
   two was not enough (Realme and Redmi both reduce to "RE"). Auto width with a
   square minimum, so "IQOO" and "INF" both sit comfortably. */
.qv__monotile {
    width: auto;
    min-width: 2.3rem;
    padding: 0 .45rem;
    font-size: .75rem;
    letter-spacing: .01em;
}

/* ==========================================================================
   Quick valuation — brand & model discovery, 2026-08-25
   --------------------------------------------------------------------------
   Search is the primary way into a catalogue of 20 brands and 121 models.
   The cards stay for people who would rather browse, but nobody should have
   to scroll a grid hunting for a logo they may not recognise — seven brands
   render a monogram tile because no legitimate logo exists for them.
   ========================================================================== */

.qv__search {
    position: relative;
    display: flex;
    align-items: center;
    margin-bottom: .85rem;
}

.qv__search__icon {
    position: absolute;
    left: .85rem;
    color: var(--qv-muted);
    pointer-events: none;
}

.qv__search__input {
    width: 100%;
    font: inherit;
    font-size: .95rem;
    padding: .8rem 2.4rem .8rem 2.6rem;
    border: 1px solid var(--qv-line);
    border-radius: .8rem;
    background: var(--qv-card);
    color: var(--qv-ink);
    box-shadow: var(--qv-sh);
    -webkit-appearance: none;
    appearance: none;
}

.qv__search__input::placeholder { color: var(--qv-muted); }

.qv__search__input:focus {
    outline: none;
    border-color: var(--qv-blue);
    box-shadow: 0 0 0 3px var(--qv-blue-wash);
}

/* The browser's own search clear button is inconsistent across engines and
   invisible on iOS, so it is suppressed in favour of a real control. */
.qv__search__input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }

.qv__search__clear {
    position: absolute;
    right: .5rem;
    width: 1.75rem;
    height: 1.75rem;
    display: grid;
    place-items: center;
    border: 0;
    border-radius: 999px;
    background: transparent;
    color: var(--qv-muted);
    font-size: 1.2rem;
    line-height: 1;
    cursor: pointer;
}

.qv__search__clear:hover { background: #EEF0F4; color: var(--qv-ink); }
.qv__search__clear:focus-visible { outline: 2px solid var(--qv-blue); outline-offset: 1px; }

.qv__resultcount {
    font-size: .74rem;
    color: var(--qv-muted);
    margin: -.35rem 0 .7rem;
}

/* ---- empty state ---- */

.qv__none {
    padding: 1.4rem 1.1rem;
    text-align: center;
    background: #F7F8FA;
    border: 1px dashed var(--qv-line);
    border-radius: .8rem;
    margin-bottom: 1rem;
}

.qv__none__title { font-size: .95rem; font-weight: 800; margin: 0 0 .3rem; color: var(--qv-ink); }
.qv__none__body { font-size: .8rem; color: var(--qv-muted); margin: 0 auto 1rem; max-width: 34rem; line-height: 1.5; }
.qv__none__acts { display: flex; flex-wrap: wrap; gap: .5rem; justify-content: center; }

.qv__btn {
    font: inherit;
    font-size: .8rem;
    font-weight: 700;
    padding: .5rem .9rem;
    border-radius: .6rem;
    border: 1px solid var(--qv-line);
    background: var(--qv-card);
    color: var(--qv-ink);
    cursor: pointer;
}

.qv__btn:hover { background: #EEF0F4; }
.qv__btn--soft { background: var(--qv-blue-wash); border-color: transparent; color: var(--qv-blue); }
.qv__btn--soft:hover { background: #DCE7FF; }
.qv__btn:focus-visible { outline: 2px solid var(--qv-blue); outline-offset: 2px; }

/* ---- "optional" marker on a field label ---- */

.qv__opt {
    font-weight: 600;
    font-size: .68rem;
    color: var(--qv-muted);
    text-transform: uppercase;
    letter-spacing: .04em;
    margin-left: .3rem;
}

/* ---- model card placeholder ----------------------------------------------
   A model with no photograph shows a light device outline carrying the brand
   mark. It reads as "picture pending" rather than as a broken image, and —
   unlike borrowing another model's photo — it does not assert something
   false about the handset. */

.qv__ghost {
    display: grid;
    place-items: center;
    width: 2.6rem;
    height: 4.1rem;
    border-radius: 7px;
    background: #F1F3F7;
    border: 1px solid var(--qv-line);
}

.qv__ghostlogo { max-width: 1.5rem; max-height: 1.5rem; object-fit: contain; opacity: .55; }
.qv__ghostmono { font-size: .8rem; font-weight: 800; color: #9AA3B2; }

/* ---- CTA busy state ---- */

.qv__cta[disabled] { opacity: .65; cursor: progress; }

@media (max-width: 480px) {
    .qv__search__input { font-size: 1rem; }   /* 16px stops iOS zooming on focus */
}

/* ==========================================================================
   Detailed valuation — the questionnaire, 2026-08-25
   --------------------------------------------------------------------------
   Deliberately built on the quick journey's shell (.qv / .qv__shell /
   .qv__panel / .qv__cta) rather than a second visual language. The customer
   crosses from "UP TO ₹80,000" into these questions in one click; if the
   chrome changed underneath them it would read as a different site, and the
   most common thing to do at that moment is leave.

   `dv-` covers only what is genuinely new: the pinned device summary, the
   condition cards, the grouped checks and the review panel.
   ========================================================================== */

/* ---- pinned device summary ----------------------------------------------
   Present above every step. The customer is answering thirty questions about
   one specific handset; showing which one — with its picture and headline
   price — is what stops them wondering whether the answers are landing on the
   right phone. */

.dv__device {
    display: flex;
    align-items: center;
    gap: .8rem;
    padding: .8rem 1.1rem;
    background: #F7F9FC;
    border-bottom: 1px solid var(--qv-line);
}

.dv__device__img {
    width: 2.6rem;
    height: 3.2rem;
    object-fit: contain;
    flex: 0 0 auto;
    border-radius: .4rem;
    background: #FFF;
}

.dv__device__img--ghost {
    display: block;
    background: linear-gradient(150deg, #E7EBF2, #D7DDE8);
    border: 1px solid var(--qv-line);
}

.dv__device__main { min-width: 0; flex: 1; }
.dv__device__name { font-size: .92rem; font-weight: 800; letter-spacing: -.01em; margin: 0; color: var(--qv-ink); }
.dv__device__meta { font-size: .73rem; color: var(--qv-muted); margin: .1rem 0 0; }

.dv__device__price { text-align: right; flex: 0 0 auto; }
.dv__device__pricelabel { display: block; font-size: .62rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--qv-muted); }
.dv__device__priceval { display: block; font-size: .95rem; font-weight: 800; color: var(--qv-ink); font-variant-numeric: tabular-nums; }

.dv__device__change {
    flex: 0 0 auto;
    font-size: .72rem;
    font-weight: 700;
    color: var(--qv-blue);
    text-decoration: none;
    padding: .3rem .55rem;
    border-radius: .45rem;
    background: var(--qv-blue-wash);
}

.dv__device__change:hover { background: #DCE7FF; color: var(--qv-blue); }

/* ---- form scaffolding ---- */

.dv__form { padding-bottom: 0; }

.dv__group { border: 0; padding: 0; margin: 0 0 1.5rem; }
.dv__group__title { font-size: .92rem; font-weight: 800; letter-spacing: -.01em; color: var(--qv-ink); margin: 0 0 .3rem; padding: 0; float: none; width: auto; }
.dv__group__note { font-size: .76rem; color: var(--qv-muted); margin: 0 0 .8rem; line-height: 1.5; }
.dv__group--alert .dv__group__title { color: #A32020; }

.dv__row { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr)); gap: .75rem; }

.dv__field { display: block; margin-bottom: .8rem; }
.dv__field__label { display: block; font-size: .76rem; font-weight: 700; color: var(--qv-ink); margin-bottom: .3rem; }
.dv__field__hint { display: block; font-size: .68rem; color: var(--qv-muted); margin-top: .25rem; line-height: 1.4; }

.dv__input {
    width: 100%;
    font: inherit;
    font-size: .88rem;
    padding: .6rem .7rem;
    border: 1px solid var(--qv-line);
    border-radius: .55rem;
    background: var(--qv-card);
    color: var(--qv-ink);
}

.dv__input:focus { outline: none; border-color: var(--qv-blue); box-shadow: 0 0 0 3px var(--qv-blue-wash); }

.dv__suffix { display: flex; align-items: center; gap: .4rem; }
.dv__suffix span { font-size: .8rem; color: var(--qv-muted); }

.dv__exact { display: inline-flex; align-items: center; gap: .45rem; font-size: .78rem; color: var(--qv-muted); margin: .3rem 0 .6rem; cursor: pointer; }

/* ---- selection cards ----------------------------------------------------
   Condition is the most consequential thing a customer tells us and the
   easiest to get wrong. Cards with a plain-English hint under each label beat
   a select element, because "hairline crack in a corner" and "cracked with
   lines across it" are worth 8% and 24% and nobody picks correctly from a
   dropdown of ten near-identical phrases. */

.dv__cards { display: grid; gap: .5rem; margin-bottom: .5rem; }
.dv__cards--4 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 8rem), 1fr)); }
.dv__cards--cond { grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr)); }

.dv__card {
    font: inherit;
    text-align: left;
    padding: .7rem .8rem;
    border: 1px solid var(--qv-line);
    border-radius: .65rem;
    background: var(--qv-card);
    cursor: pointer;
    transition: border-color .14s ease, box-shadow .14s ease, background-color .14s ease;
}

.dv__card:hover { border-color: #C9D2E0; }
.dv__card:focus-visible { outline: 2px solid var(--qv-blue); outline-offset: 2px; }

.dv__card.is-on {
    border-color: var(--qv-blue);
    background: var(--qv-blue-wash);
    box-shadow: 0 0 0 1px var(--qv-blue);
}

.dv__card__label { display: block; font-size: .82rem; font-weight: 700; color: var(--qv-ink); }
.dv__card__sub { display: block; font-size: .7rem; color: var(--qv-muted); margin-top: .15rem; line-height: 1.35; }

/* Battery bands carry a quiet colour cue. Never colour alone — each card
   also states its band and a word ("Excellent", "Poor"). */
.dv__card--good.is-on { border-color: #16714A; background: #E6F6EE; box-shadow: 0 0 0 1px #16714A; }
.dv__card--ok.is-on   { border-color: #1B4FD8; background: #EAF1FF; box-shadow: 0 0 0 1px #1B4FD8; }
.dv__card--warn.is-on { border-color: #8A5A00; background: #FDF2DC; box-shadow: 0 0 0 1px #8A5A00; }
.dv__card--bad.is-on  { border-color: #A32020; background: #FDEAEA; box-shadow: 0 0 0 1px #A32020; }

/* ---- yes / no ---- */

.dv__yesno { display: inline-flex; gap: .4rem; }

.dv__toggle {
    font: inherit;
    font-size: .82rem;
    font-weight: 700;
    padding: .5rem 1.4rem;
    border: 1px solid var(--qv-line);
    border-radius: .55rem;
    background: var(--qv-card);
    color: var(--qv-ink);
    cursor: pointer;
}

.dv__toggle.is-yes { border-color: #16714A; background: #E6F6EE; color: #16714A; }
.dv__toggle.is-no  { border-color: var(--qv-line); background: #EEF0F4; color: #47526B; }
.dv__toggle:focus-visible { outline: 2px solid var(--qv-blue); outline-offset: 2px; }

/* ---- grouped checks ---- */

.dv__checks { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr)); gap: .45rem; }

.dv__check {
    display: flex;
    align-items: flex-start;
    gap: .6rem;
    padding: .6rem .7rem;
    border: 1px solid var(--qv-line);
    border-radius: .6rem;
    background: var(--qv-card);
    cursor: pointer;
}

.dv__check:hover { border-color: #C9D2E0; }
.dv__check input { position: absolute; opacity: 0; width: 1px; height: 1px; }

.dv__check__box {
    flex: 0 0 auto;
    width: 1.15rem;
    height: 1.15rem;
    margin-top: .1rem;
    border: 1.5px solid #C2CAD8;
    border-radius: .35rem;
    background: #FFF;
    position: relative;
}

.dv__check input:checked + .dv__check__box {
    background: var(--qv-blue);
    border-color: var(--qv-blue);
}

.dv__check input:checked + .dv__check__box::after {
    content: '';
    position: absolute;
    left: .34rem; top: .12rem;
    width: .3rem; height: .58rem;
    border: solid #FFF;
    border-width: 0 2px 2px 0;
    transform: rotate(45deg);
}

.dv__check input:focus-visible + .dv__check__box { outline: 2px solid var(--qv-blue); outline-offset: 2px; }
.dv__check:has(input:checked) { border-color: var(--qv-blue); background: var(--qv-blue-wash); }

.dv__check__text { min-width: 0; }
.dv__check__label { display: block; font-size: .8rem; font-weight: 600; color: var(--qv-ink); line-height: 1.25; }
.dv__check__sub { display: block; font-size: .68rem; color: var(--qv-muted); margin-top: .1rem; }

.dv__sub { grid-column: 1 / -1; padding: .1rem 0 .5rem .5rem; border-left: 2px solid var(--qv-blue-wash); margin-left: .6rem; }

/* ---- notes and errors ---- */

.dv__note {
    padding: .8rem 1rem;
    border-radius: .65rem;
    background: #F7F8FA;
    border: 1px solid var(--qv-line);
    font-size: .78rem;
    color: var(--qv-muted);
    line-height: 1.5;
    margin-bottom: 1.5rem;
}

.dv__note strong { color: var(--qv-ink); }

.dv__errors {
    padding: .9rem 1rem;
    border-radius: .65rem;
    background: #FEF6F6;
    border: 1px solid #F3C9C9;
    color: #7A1C1C;
    margin-bottom: 1.25rem;
}

.dv__errors:focus { outline: 2px solid #A32020; outline-offset: 2px; }
.dv__errors__title { font-size: .85rem; font-weight: 800; margin: 0 0 .35rem; }
.dv__errors ul { margin: 0; padding-left: 1.1rem; font-size: .78rem; line-height: 1.5; }

/* ---- review ---- */

.dv__summary {
    padding: .95rem 1.1rem;
    border-radius: .7rem;
    background: var(--qv-blue-wash);
    border: 1px solid #CFDDFB;
    margin-bottom: 1.4rem;
}

.dv__summary__head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; margin-bottom: .4rem; }
.dv__summary__title { font-size: .68rem; font-weight: 800; text-transform: uppercase; letter-spacing: .05em; color: #1B4FD8; }
.dv__summary__edit { font-size: .74rem; font-weight: 700; color: #1B4FD8; }
.dv__summary__name { font-size: .95rem; font-weight: 800; color: var(--qv-ink); margin: 0; }
.dv__summary__line { font-size: .8rem; color: #33415C; margin: .15rem 0 0; word-break: break-word; }
.dv__summary__dot { color: #8FA0B6; margin: 0 .2rem; }
.dv__summary__hint { font-size: .7rem; color: var(--qv-muted); margin: .3rem 0 0; }

.dv__next { margin: 0; padding-left: 1.1rem; font-size: .8rem; color: var(--qv-muted); line-height: 1.7; }

.dv__confirm {
    display: flex;
    align-items: flex-start;
    gap: .65rem;
    padding: .9rem 1rem;
    border: 1px solid var(--qv-line);
    border-radius: .65rem;
    background: #FCFCFD;
    font-size: .78rem;
    line-height: 1.5;
    color: var(--qv-muted);
    cursor: pointer;
}

.dv__confirm.is-bad { border-color: #E4A4A4; background: #FEF6F6; }
.dv__confirm strong { color: var(--qv-ink); }
.dv__confirm input { margin-top: .15rem; flex: 0 0 auto; width: 1.05rem; height: 1.05rem; accent-color: var(--qv-blue); }

/* ---- navigation ---- */

.dv__nav { display: flex; align-items: center; gap: .7rem; margin-top: 1.4rem; }

.dv__back {
    font: inherit;
    font-size: .82rem;
    font-weight: 700;
    padding: .7rem 1rem;
    border: 1px solid var(--qv-line);
    border-radius: .6rem;
    background: var(--qv-card);
    color: var(--qv-ink);
    text-decoration: none;
    cursor: pointer;
    flex: 0 0 auto;
}

.dv__back:hover { background: #EEF0F4; color: var(--qv-ink); }
.dv__back:focus-visible { outline: 2px solid var(--qv-blue); outline-offset: 2px; }
.dv__next__btn { flex: 1; margin: 0; }

@media (max-width: 480px) {
    .dv__device__meta { font-size: .68rem; }
    .dv__device__change { padding: .3rem .45rem; }
    .dv__input { font-size: 1rem; }         /* 16px stops iOS zooming on focus */
    .dv__cards--4 { grid-template-columns: repeat(2, 1fr); }
}

@media (prefers-reduced-motion: reduce) {
    .dv__card { transition: none; }
}

/* Battery bands are a fixed set of four, so the grid says four rather than
   auto-fitting — `minmax(8rem, 1fr)` wrapped them 3 + 1 at the shell's width,
   which reads as though the last option belongs to something else. */
.dv__cards--4 { grid-template-columns: repeat(4, 1fr); }

@media (max-width: 560px) {
    .dv__cards--4 { grid-template-columns: repeat(2, 1fr); }
}

/* ==========================================================================
   Valuation journey — responsive correction, 2026-08-26
   --------------------------------------------------------------------------
   THE REGRESSION, AND WHY IT HAPPENED.

   One rule caused all of it:

       .qv__shell { max-width: 560px }
       @media (min-width: 992px) { .qv__shell { max-width: 620px } }

   That was a deliberate choice when the journey was a phone-first funnel, and
   the comment beside it argued that nine brand tiles across 1600px "reads as a
   spreadsheet". The argument was half right and the remedy was wrong: the fix
   for content that does not fill a wide screen is a grid that reflows into it,
   not a container that refuses the width. A 620px column on a 1920px monitor
   leaves ~1300px of empty page and pushes 121 model cards into a 3-wide strip
   the customer has to scroll for a minute.

   It applied to every screen in both journeys because the detailed
   questionnaire deliberately reuses `.qv__shell` for visual continuity — so
   one rule narrowed ten screens, and one rule widens them.

   THE APPROACH. The shell becomes fluid with a per-breakpoint cap, and the
   grids inside it become `auto-fit`/`minmax` so they genuinely fill whatever
   width they are given. Content that must NOT stretch — a name field, a line
   of prose — is constrained where it lives, not by starving the whole page.
   ========================================================================== */

/* ---- 1. The container ---------------------------------------------------
   Fluid to the viewport, capped so text lines stay readable and cards stay a
   sensible size. Caps track Bootstrap 5.3's breakpoints, which the rest of
   the site already uses, rather than inventing a second scale. */

.qv {
    padding-inline: clamp(0.75rem, 3vw, 2.5rem);
}

.qv__shell {
    max-width: 100%;            /* mobile: use the width there is */
}

@media (min-width: 576px)  { .qv__shell { max-width: 540px; } }
@media (min-width: 768px)  { .qv__shell { max-width: 720px; } }
@media (min-width: 992px)  { .qv__shell { max-width: 960px; } }
@media (min-width: 1200px) { .qv__shell { max-width: 1140px; } }

/* Large monitors stop here. Past ~1320px the cards would grow without
   becoming more useful, and the eye has to travel further for no gain. */
@media (min-width: 1400px) { .qv__shell { max-width: 1320px; } }

/* Padding scales with the container so a wide shell does not put content
   hard against its own border. */
.qv__panel { padding: 1.35rem 1.1rem 0; }

@media (min-width: 768px)  { .qv__panel { padding: 1.6rem 1.5rem 0; } }
@media (min-width: 1200px) { .qv__panel { padding: 1.9rem 2rem 0; } }

@media (min-width: 768px) {
    .qv__bar { padding: 1rem 1.5rem; }
    .qv__progress { margin-inline: -1.5rem; padding-inline: 1.5rem; }
}
@media (min-width: 1200px) {
    .qv__bar { padding: 1.1rem 2rem; }
    .qv__progress { margin-inline: -2rem; padding-inline: 2rem; }
}

/* ---- 2. Type scales with the container --------------------------------- */

@media (min-width: 992px) {
    .qv__title { font-size: 1.5rem; }
    .qv__sub   { font-size: .9rem; }
    .qv__num   { width: 2.1rem; height: 2.1rem; font-size: .95rem; }
}

/* ---- 3. Brand grid ------------------------------------------------------
   Was a hard `repeat(3,1fr)`, so a 1320px shell would have shown three
   enormous tiles. auto-fit lets the row decide: 2 on a small phone, 3–4 on a
   tablet, 6–8 on a desktop — without a single extra breakpoint. */

.qv__grid {
    grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
}

@media (max-width: 400px) {
    .qv__grid { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 992px) {
    .qv__grid { gap: .75rem; }
}

/* ---- 4. Model grid ------------------------------------------------------
   The specific complaint. 121 models three-across is a long scroll; the same
   models six-across is a glance. The floor is 9.5rem so a card never gets so
   narrow that the handset image and the name stop being legible. */

.qv__grid--models {
    grid-template-columns: repeat(auto-fit, minmax(10.5rem, 1fr));
}

@media (max-width: 420px) {
    .qv__grid--models { grid-template-columns: repeat(2, 1fr); }
}

/* A wider card can afford a bigger picture — the image is what the customer
   actually scans for. */
@media (min-width: 992px) {
    .qv__phone { height: 5.4rem; }
    .qv__phone img { max-height: 5.2rem; }
    .qv .qv__ghost { width: 2.9rem; height: 4.6rem; }
    .qv__cardname { font-size: .82rem; }
}

/* ---- 5. Search ----------------------------------------------------------
   Full width of the content area at every size. On desktop it now spans a
   1140–1320px shell, which is what "prominent" means here — the alternative
   was a search box narrower than a single model card. */

@media (min-width: 992px) {
    .qv__search__input { font-size: 1rem; padding-block: .95rem; }
    .qv__search__icon { left: 1.05rem; }
    .qv__search__input { padding-left: 2.9rem; }
}

/* ---- 6. Step 1 (details) ------------------------------------------------
   A name field 1300px wide is worse than one 400px wide, so the form does not
   inherit the shell's full width. Instead the form and the reassurance tiles
   sit side by side from 992px, which uses the space for something rather than
   leaving it blank. */

@media (min-width: 992px) {
    .qv__intro {
        display: grid;
        grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr);
        gap: 2rem;
        align-items: start;
    }

    .qv__intro .qv__form { margin-bottom: 0; }

    /* Stacked in the narrow right-hand column, where a 3-across row of tiles
       would be unreadably tight. */
    .qv__intro .qv__trust {
        grid-template-columns: 1fr;
        margin-bottom: 0;
        position: sticky;
        top: 1rem;
    }

    .qv__intro .qv__trustitem { padding: .8rem .9rem; }
    .qv__intro .qv__trustitem strong { font-size: .82rem; }
    .qv__intro .qv__trustitem small { font-size: .72rem; }
}

/* The CTA follows the form's column rather than spanning the whole shell —
   a 1300px-wide button looks like a banner, not a button. */
@media (min-width: 992px) {
    .qv__panel--intro .qv__cta { max-width: 26rem; }
}

/* ---- 7. Variant + price -------------------------------------------------
   Two columns on desktop: the storage options a customer is choosing between
   on the left, the headline price and what happens next on the right. They
   are read together, so putting the price a scroll below the options was
   costing the moment the journey exists to create. */

@media (min-width: 992px) {
    .qv__pricecols {
        display: grid;
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
        gap: 1.75rem;
        align-items: start;
    }

    .qv__pricecols > * { min-width: 0; }
    .qv__variants { margin-bottom: 0; }

    .qv__priceside { position: sticky; top: 1rem; }
    .qv__price { margin-bottom: 1rem; }
    .qv__assure { grid-template-columns: 1fr; }
    .qv__assure > div { padding: .7rem .85rem; }
}

@media (min-width: 1200px) {
    .qv__pricebig { font-size: 3.2rem; }
    /* Three across again once the column itself is wide enough. */
    .qv__assure { grid-template-columns: repeat(3, 1fr); }
}

/* ---- 8. Selected-device header ----------------------------------------- */

@media (min-width: 992px) {
    .qv__picked { padding: 1rem 1.25rem; }
    .qv__pickedimg { width: 3.6rem; height: 4.4rem; }
}

/* ==========================================================================
   Detailed questionnaire
   --------------------------------------------------------------------------
   Same shell, so the same widening applies. What it needed on top was for the
   groups to sit in columns rather than one long strip — four named groups of
   three checks each is a wall on a wide screen for no reason.
   ========================================================================== */

/* Two-column composition for steps made of independent groups. `align-items:
   start` so a short group does not stretch to match a tall neighbour, and the
   grid is auto-fit so it collapses to one column by itself. */
@media (min-width: 992px) {
    .dv__cols {
        display: grid;
        /* Two, not auto-fit. The four functional groups auto-fitted into
           three columns at 1440px, leaving a 3 + 1 orphan row; two columns
           give an even 2 + 2, and step 4's pair sits side by side. Each
           column also stays wide enough for its checks to keep their labels
           on one line. */
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 0 2rem;
        align-items: start;
    }

    .dv__cols > .dv__group { break-inside: avoid; }
}

/* Form fields stop growing well before the container does — a date input the
   width of a monitor is not easier to use. */
@media (min-width: 992px) {
    .dv__field { max-width: 26rem; }
    .dv__row { max-width: 54rem; }
    .dv__row .dv__field { max-width: none; }
    .dv__group__note { max-width: 62ch; }
}

/* Condition cards: already auto-fit, so they simply gain columns with the
   shell. The floor rises on desktop so a card keeps room for its hint line. */
@media (min-width: 992px) {
    .dv__cards--cond { grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); }
    .dv__checks { grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); }
}

/* Battery bands: four across is right once there is room for it, two before. */
@media (max-width: 560px) { .dv__cards--4 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 561px) { .dv__cards--4 { grid-template-columns: repeat(4, 1fr); } }

/* Review step: summary and next-steps side by side, confirmation full width
   underneath so it is not something the eye can skip past. */
@media (min-width: 992px) {
    .dv__reviewcols {
        display: grid;
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
        gap: 1.75rem;
        align-items: start;
    }

    .dv__reviewcols .dv__summary { margin-bottom: 0; }
    .dv__reviewcols .dv__group { margin-bottom: 0; }
}

/* Navigation: the Continue button stops being a full-width bar on desktop. */
@media (min-width: 768px) {
    .dv__next__btn { flex: 0 1 18rem; margin-left: auto; }
    .dv__nav { gap: 1rem; }
}

/* Device summary header grows with the shell. */
@media (min-width: 992px) {
    .dv__device { padding: 1rem 1.5rem; }
    .dv__device__img { width: 3.2rem; height: 3.9rem; }
    .dv__device__name { font-size: 1.05rem; }
    .dv__device__priceval { font-size: 1.15rem; }
}
@media (min-width: 1200px) {
    .dv__device { padding: 1.05rem 2rem; }
}

/* ==========================================================================
   Floating contact buttons
   --------------------------------------------------------------------------
   They sit bottom-right over the page. On a 620px column they cleared the
   content by accident; over a 1320px shell they overlap the right-hand edge
   of the grid — including the price panel and the CTA in the two-column
   layouts above. The shell gets right-hand clearance at the sizes where the
   buttons are actually shown.
   ========================================================================== */

@media (min-width: 992px) {
    .qv__pricecols,
    .dv__reviewcols { padding-right: 4.5rem; }
}

@media (min-width: 1500px) {
    /* Once the viewport is wider than shell + buttons, the overlap cannot
       happen and the reserved gutter would just be a hole. */
    .qv__pricecols,
    .dv__reviewcols { padding-right: 0; }
}

/* ==========================================================================
   Mobile guards
   --------------------------------------------------------------------------
   Widening a desktop layout is the easy half. These stop it costing anything
   on a phone, which is where most of this traffic is.
   ========================================================================== */

@media (max-width: 575.98px) {
    .qv { padding-inline: .75rem; }
    .qv__shell { border-radius: 14px; }
    .qv__trust { grid-template-columns: 1fr; }
    .qv__assure { grid-template-columns: 1fr; }
    .qv__bar { padding: .8rem .9rem; }
    .qv__panel { padding: 1.15rem .9rem 0; }

    /* 44px minimum touch targets. */
    .qv__cta,
    .dv__back,
    .qv__btn { min-height: 2.75rem; }
    .qv__card { min-height: 5.5rem; }

    .dv__nav { flex-wrap: wrap; }
    .dv__next__btn { flex: 1 1 100%; order: -1; }
}

/* Nothing in this journey may cause sideways scroll at any width.

   This deliberately does NOT set max-width on .qv__shell. An earlier draft
   did, and being the last rule in the file it silently overrode every
   breakpoint cap above — the shell computed to max-width:100% at 1440px and
   the caps did nothing at all. Overflow containment and width capping are
   different jobs; only the first belongs in a catch-all guard. */
.qv,
.qv__panel { max-width: 100%; }

.qv,
.qv__shell,
.qv__panel { overflow-x: clip; }

.qv__chips { overflow-x: auto; scrollbar-width: thin; }

/* =====================================================================
   MH UI — recent screens (purchase, inventory, documents)
   Appended as one block so it is easy to find, review and revert.

   Mobile-first: the base rules describe the phone, and the @media
   (min-width: 768px) block adds the desktop table back. That order
   matters -- writing it the other way round means every phone parses
   and then overrides desktop rules it will never use.
   ===================================================================== */

/* --- Icon buttons ---------------------------------------------------
   44px is the smallest comfortable touch target; below that people miss.
   Icon-only buttons keep their accessible name from aria-label.        */
.mh-iconbtn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .4rem;
    min-width: 44px;
    min-height: 44px;
    padding: .45rem .7rem;
    border: 1px solid var(--mh-line, #dee2e6);
    border-radius: .5rem;
    background: #fff;
    color: var(--mh-ink, #212529);
    font-size: .875rem;
    line-height: 1;
    text-decoration: none;
    white-space: nowrap;
}
.mh-iconbtn:hover { background: var(--mh-page, #f6f8fb); color: inherit; }
.mh-iconbtn:focus-visible { outline: 2px solid #0B5CFF; outline-offset: 2px; }
.mh-iconbtn[disabled] { opacity: .55; pointer-events: none; }
.mh-iconbtn--primary { background: #0B5CFF; border-color: #0B5CFF; color: #fff; }
.mh-iconbtn--primary:hover { background: #0a52e6; color: #fff; }
.mh-iconbtn--success { background: #10893E; border-color: #10893E; color: #fff; }
.mh-iconbtn--success:hover { background: #0d7434; color: #fff; }

/* The label collapses on small screens; the icon and its aria-label
   remain, so nothing becomes unreachable -- only quieter. */
.mh-iconbtn__label { display: none; }
@media (min-width: 576px) {
    .mh-iconbtn__label { display: inline; }
}

.mh-actionbar { display: flex; flex-wrap: wrap; gap: .4rem; }

/* --- Section headings with an icon ---------------------------------- */
.mh-section-title {
    display: flex;
    align-items: center;
    gap: .5rem;
    font-weight: 600;
}
.mh-section-title svg { flex: 0 0 auto; opacity: .7; }

/* --- Record cards that become a table on desktop --------------------
   One markup, two presentations. The <table> keeps its semantics for
   screen readers and for desktop; below 768px each row is re-laid out
   as a card with its column name shown from data-label.               */
@media (max-width: 767.98px) {
    .mh-rowcards thead { display: none; }
    .mh-rowcards, .mh-rowcards tbody, .mh-rowcards tr, .mh-rowcards td { display: block; width: 100%; }
    .mh-rowcards tr {
        border: 1px solid var(--mh-line, #dee2e6);
        border-radius: .6rem;
        padding: .7rem .8rem;
        margin-bottom: .6rem;
        background: #fff;
    }
    .mh-rowcards td {
        border: 0 !important;
        padding: .15rem 0 !important;
        display: flex;
        justify-content: space-between;
        gap: .75rem;
        align-items: baseline;
    }
    .mh-rowcards td::before {
        content: attr(data-label);
        color: var(--mh-muted, #6c757d);
        font-size: .78rem;
        flex: 0 0 auto;
    }
    /* The primary cell reads as the card's heading, not a labelled row. */
    .mh-rowcards td.mh-cell-primary {
        display: block;
        font-size: 1rem;
        margin-bottom: .3rem;
    }
    .mh-rowcards td.mh-cell-primary::before { content: none; }
    .mh-rowcards td.mh-cell-actions { justify-content: flex-end; margin-top: .5rem; }
    .mh-rowcards td.mh-cell-actions::before { content: none; }
    .mh-rowcards td[data-label]:empty { display: none; }
}

/* --- Status chip: icon + text, never colour alone -------------------- */
.mh-chip {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    padding: .18rem .5rem;
    border-radius: 999px;
    font-size: .78rem;
    font-weight: 600;
    white-space: nowrap;
}
.mh-chip svg { flex: 0 0 auto; }
.mh-chip--ok { background: #e7f5ec; color: #10893E; }
.mh-chip--warn { background: #fdf3e3; color: #9a6300; }
.mh-chip--info { background: #e8f0ff; color: #0B5CFF; }
.mh-chip--muted { background: #eef1f5; color: #55606e; }
.mh-chip--danger { background: #fdeaea; color: #b42318; }

/* --- Document slots -------------------------------------------------- */
.mh-docslots { display: grid; grid-template-columns: 1fr; gap: .6rem; }
@media (min-width: 576px) { .mh-docslots { grid-template-columns: 1fr 1fr; } }

.mh-docslot {
    border: 1px solid var(--mh-line, #dee2e6);
    border-radius: .6rem;
    padding: .7rem;
    display: flex;
    flex-direction: column;
    gap: .5rem;
}
.mh-docslot__head { display: flex; align-items: center; gap: .45rem; font-weight: 600; font-size: .875rem; }
.mh-docslot__thumb {
    width: 100%;
    height: 108px;
    border-radius: .45rem;
    border: 1px solid var(--mh-line, #dee2e6);
    background: var(--mh-page, #f6f8fb);
    object-fit: cover;
    display: block;
}
.mh-docslot__empty {
    height: 108px;
    border: 1px dashed #c7cedb;
    border-radius: .45rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: .3rem;
    color: var(--mh-muted, #6c757d);
    font-size: .8rem;
    text-align: center;
}
.mh-docslot__actions { display: flex; gap: .35rem; flex-wrap: wrap; }

/* Any uploaded preview must stay inside its container on a phone. */
.mh-docslot img, .mh-doc-preview img { max-width: 100%; height: auto; }

/* --- Timeline -------------------------------------------------------- */
.mh-timeline__icon {
    width: 30px; height: 30px;
    border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    flex: 0 0 auto;
    color: #fff;
}

/* --- Sticky action bar on phones ------------------------------------
   Long forms bury their Save button under the fold. This pins it, and
   only on small screens -- a fixed bar on a desktop monitor is wasted
   furniture. Body padding stops it covering the last field.            */
@media (max-width: 767.98px) {
    .mh-sticky-actions {
        position: sticky;
        bottom: 0;
        z-index: 20;
        display: flex;
        gap: .5rem;
        padding: .6rem .75rem calc(.6rem + env(safe-area-inset-bottom, 0px));
        margin: 0 -.75rem;
        background: rgba(255, 255, 255, .96);
        border-top: 1px solid var(--mh-line, #dee2e6);
    }
    .mh-sticky-actions .btn, .mh-sticky-actions .mh-iconbtn { flex: 1 1 auto; }
}

/* --- Forms ----------------------------------------------------------- */
@media (max-width: 575.98px) {
    /* One column on a phone regardless of the desktop grid: two 6-col
       fields side by side on a 320px screen are two unusable fields. */
    .mh-form .row > [class*="col-"] { flex: 0 0 100%; max-width: 100%; }
    .mh-form .form-control, .mh-form .form-select { min-height: 44px; }
    .mh-form .btn { min-height: 44px; }
}

/* --- Combobox as a bottom sheet on phones ---------------------------- */
@media (max-width: 575.98px) {
    .mh-sheet {
        position: fixed;
        left: 0; right: 0; bottom: 0;
        z-index: 1060;
        border-radius: .9rem .9rem 0 0;
        box-shadow: 0 -8px 28px rgba(16, 24, 40, .18);
        max-height: 82vh;
        overflow-y: auto;
        padding-bottom: calc(.75rem + env(safe-area-inset-bottom, 0px));
    }
    .mh-sheet__backdrop {
        position: fixed;
        inset: 0;
        background: rgba(16, 24, 40, .35);
        z-index: 1055;
    }
}

/* --- Preview / print screens on a phone ------------------------------ */
@media (max-width: 820px) {
    .sheet { width: auto !important; margin: 10px !important; padding: 14px !important; min-height: 0 !important; }
    .toolbar { flex-wrap: wrap; }
    .toolbar .hint { order: 10; }
}

/* --- Small helpers --------------------------------------------------- */
.mh-truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mh-tap { min-height: 44px; display: inline-flex; align-items: center; }

/* --- Icon sizing -----------------------------------------------------
   vm-icon renders a viewBox-only <svg> with no width/height, so it takes
   whatever size its container implies: it fills a block parent, and
   collapses to nothing inside a flex row. Every icon this UI places gets
   an explicit box here so neither can happen.                          */
.mh-ico,
.mh-iconbtn > svg,
.mh-section-title > svg,
.mh-chip > svg,
.mh-docslot__head > svg,
.mh-docslot__empty > svg,
.mh-actionbar svg,
.mh-timeline__icon > svg,
.mh-form label > svg,
.mh-inline-ico > svg {
    width: 16px;
    height: 16px;
    flex: 0 0 16px;
    display: inline-block;
    vertical-align: -.15em;
}
.mh-docslot__empty > svg { width: 22px; height: 22px; flex: 0 0 22px; }
.mh-timeline__icon > svg { width: 15px; height: 15px; flex: 0 0 15px; }
.mh-section-title > svg { opacity: .65; }

/* Columns that are noise in a narrow desktop table but useful on a card.
   Bootstrap's .d-none is !important and cannot be undone by the card
   layout, so these opt out of the table instead of out of the card. */
@media (min-width: 768px) and (max-width: 1199.98px) {
    .mh-rowcards .mh-md-hide { display: none; }
}
@media (min-width: 768px) and (max-width: 991.98px) {
    .mh-rowcards .mh-sm-hide { display: none; }
}


/* Sales — picking one handset out of several of the same model. --------- */
.mh-unit-results { display: flex; flex-direction: column; gap: .5rem; max-height: 22rem; overflow-y: auto; }
.mh-unit-result {
    display: flex; align-items: flex-start; justify-content: space-between; gap: .75rem;
    width: 100%; text-align: left; padding: .75rem; min-height: 44px;
    background: #fff; border: 1px solid var(--bs-border-color, #dee2e6); border-radius: .5rem;

    /*
     * Do NOT let these shrink. The list is a column flex box with a
     * max-height, so the default flex-shrink:1 crushes every row to its
     * min-height and the device name spills out over the border. The
     * container scrolls; the rows keep their size.
     */
    flex: 0 0 auto;
}
.mh-unit-result:hover, .mh-unit-result:focus-visible { border-color: #0d6efd; background: #f8fbff; }
.mh-unit-result__cta { flex: none; font-size: .875rem; font-weight: 600; color: #0d6efd; }
.mh-chosen-unit { background: #f8fbff; border-color: #b6d4fe !important; }
@media (max-width: 575.98px) {
    .mh-unit-result { flex-direction: column; align-items: flex-start; gap: .25rem; }
    .mh-unit-result__cta { align-self: flex-end; }
}


/* ---------------------------------------------------------------------
   Sales form sections adopt the purchase invoice's card language.

   The purchase screens are .card > .card-header.bg-white.fw-semibold >
   .card-body. The sales form was built with .mh-form-section and a
   coloured icon medallion, so the two halves of the counter did not look
   like one application. These rules reproduce the card metrics exactly,
   without touching markup that works.

   Scoped to .mh-form (the sales form's own class) so no other screen
   using .mh-form-section is restyled underneath itself.
   --------------------------------------------------------------------- */
.mh-form .mh-form-section,
form.mh-sales-form .mh-form-section {
    background: #fff;
    border: 1px solid var(--bs-border-color, #dee2e6);
    border-radius: 0.5rem;
    box-shadow: none;
    margin-bottom: 1rem;
    /* No top padding: the header supplies its own and sits flush. */
    padding: 0 1rem 1rem;
}

.mh-form .mh-form-section:first-of-type,
form.mh-sales-form .mh-form-section:first-of-type { margin-top: 0; }

/* .card-header: flush to the section edges, its own padding, hairline under. */
.mh-form .mh-form-section__head,
form.mh-sales-form .mh-form-section__head {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0 -1rem 1rem;
    padding: 0.75rem 1rem;
    background: #fff;
    border-bottom: 1px solid var(--bs-border-color, #dee2e6);
    border-radius: 0.5rem 0.5rem 0 0;
}

/* The medallion becomes the small monochrome glyph the purchase headers use. */
.mh-form .mh-form-section__head .mh-metric-icon,
form.mh-sales-form .mh-form-section__head .mh-metric-icon {
    width: 1rem;
    height: 1rem;
    min-width: 1rem;
    padding: 0;
    border-radius: 0;
    background: transparent;
    color: var(--bs-body-color, #212529);
}
.mh-form .mh-form-section__head .mh-metric-icon svg,
form.mh-sales-form .mh-form-section__head .mh-metric-icon svg {
    width: 1rem;
    height: 1rem;
}

/* Section name: body-sized and semibold, not a heading. */
.mh-form .mh-form-section__title,
form.mh-sales-form .mh-form-section__title {
    font-size: 1rem;
    font-weight: 600;
    line-height: 1.5;
    margin: 0;
}

/* Labels at the purchase form's size (form-label small mb-1). */
.mh-form .mh-form-section .form-label,
form.mh-sales-form .mh-form-section .form-label {
    font-size: 0.875rem;
    margin-bottom: 0.25rem;
}

@media (max-width: 575.98px) {
    .mh-form .mh-form-section,
    form.mh-sales-form .mh-form-section { padding: 0 0.75rem 0.75rem; }
    .mh-form .mh-form-section__head,
    form.mh-sales-form .mh-form-section__head { margin: 0 -0.75rem 0.75rem; padding: 0.75rem; }
}


/* ---------------------------------------------------------------------
   Sales invoice workspace.
   --------------------------------------------------------------------- */

/* Sale type: two options, both visible, one tap to switch. */
.mh-segmented { display: inline-flex; border: 1px solid var(--bs-border-color, #dee2e6); border-radius: .5rem; overflow: hidden; }
.mh-segmented__option {
    display: inline-flex; align-items: center; gap: .5rem;
    padding: .5rem 1rem; min-height: 44px;
    background: #fff; border: 0; color: var(--bs-body-color, #212529); font-weight: 500;
}
.mh-segmented__option + .mh-segmented__option { border-left: 1px solid var(--bs-border-color, #dee2e6); }
.mh-segmented__option.is-active { background: #0d6efd; color: #fff; }

/* A line item. A row on a desktop, a card on a phone -- same markup. */
.mh-line {
    display: grid; align-items: end; gap: .75rem;
    grid-template-columns: 1fr 5.5rem 9rem 7rem 3rem;
    padding: .75rem; margin-bottom: .5rem;
    border: 1px solid var(--bs-border-color, #dee2e6); border-radius: .5rem; background: #fff;
}
.mh-line__specs { display: flex; flex-wrap: wrap; gap: .25rem .75rem; margin-top: .25rem; }
.mh-line__spec { font-size: .8125rem; }
.mh-line__total { text-align: right; }
.mh-line__remove { display: flex; justify-content: flex-end; }

@media (max-width: 767.98px) {
    /* Never a table that scrolls sideways: the price is the thing being
       edited on a phone, so it gets a full-width row of its own. */
    .mh-line { grid-template-columns: 1fr 1fr; }
    .mh-line__info { grid-column: 1 / -1; }
    .mh-line__total { text-align: left; }
    .mh-line__remove { grid-column: 2; justify-content: flex-end; }
}

.mh-summary dt, .mh-summary dd { padding: .125rem 0; }


/* ==========================================================================
   Staff application — visual refresh
   --------------------------------------------------------------------------
   Scoped to body.site-app throughout. The public website shares this
   stylesheet and its own accent is unchanged; nothing below leaks to it.

   The token block at the top of this file argues that the app should stay
   neutral so that status colour can carry meaning. That still holds: what
   changes here is the CHROME -- the primary action, the active nav item,
   the card surface -- and not the status vocabulary. .status-* keeps every
   colour it had, which is why "overdue" still reads as overdue against a
   violet button.
   ========================================================================== */

body.site-app {
    --mh-violet: #6D5DF6;
    --mh-violet-hover: #5B4BE0;
    --mh-violet-soft: #EFEDFE;
    --mh-violet-ink: #4B3FD1;

    /* The app's primary action becomes the accent. It was near-black,
       inherited from the website, which made every button on every screen
       look like the same weight of decision. */
    --bs-primary: var(--mh-violet);
    --bs-primary-rgb: 109, 93, 246;
    --bs-link-color: var(--mh-violet-ink);
    --bs-link-hover-color: var(--mh-violet-hover);

    /* A faint ground so white cards lift off it. On pure white the cards
       had to be drawn with borders alone. */
    --mh-app-ground: #F6F6FB;
    --mh-app-line: #ECECF3;
    --mh-app-line-soft: #F2F2F7;

    background-color: var(--mh-app-ground);
}

.site-app .mh-app-body { background-color: var(--mh-app-ground); }

/* ---- surfaces --------------------------------------------------------- */
.site-app .card,
.site-app .card-block {
    border: 1px solid var(--mh-app-line);
    border-radius: 16px;
    background: #fff;
    box-shadow: 0 1px 2px rgba(16, 24, 40, .04), 0 12px 28px -18px rgba(16, 24, 40, .16);
}

.site-app .card-header {
    background: #fff !important;
    border-bottom: 1px solid var(--mh-app-line-soft);
    padding: .9rem 1.15rem;
    font-weight: 600;
    border-radius: 16px 16px 0 0;
}

.site-app .card-body { padding: 1.15rem; }

/* Section glyph: a soft violet tile, so a heading reads at a glance. */
.site-app .card-header .mh-ico,
.site-app .mh-form-section__head .mh-ico {
    color: var(--mh-violet);
}

.site-app .mh-card-ico {
    display: inline-flex; align-items: center; justify-content: center;
    width: 2rem; height: 2rem; flex: none;
    border-radius: .6rem;
    background: var(--mh-violet-soft);
    color: var(--mh-violet);
}
.site-app .mh-card-ico svg { width: 1.05rem; height: 1.05rem; }

/* ---- controls --------------------------------------------------------- */
.site-app .form-control,
.site-app .form-select {
    border-radius: .65rem;
    border-color: #E6E6EF;
    background-color: #FCFCFE;
    padding-top: .5rem; padding-bottom: .5rem;
}
.site-app .form-control:focus,
.site-app .form-select:focus {
    border-color: var(--mh-violet);
    box-shadow: 0 0 0 .2rem rgba(109, 93, 246, .18);
    background-color: #fff;
}
.site-app .form-label { font-weight: 500; color: #5A5A6E; }

/* ---- buttons ---------------------------------------------------------- */
.site-app .btn { border-radius: .65rem; font-weight: 600; }

.site-app .btn-primary {
    --bs-btn-bg: var(--mh-violet);
    --bs-btn-border-color: var(--mh-violet);
    --bs-btn-hover-bg: var(--mh-violet-hover);
    --bs-btn-hover-border-color: var(--mh-violet-hover);
    --bs-btn-active-bg: var(--mh-violet-hover);
    --bs-btn-disabled-bg: #C7C1FA;
    --bs-btn-disabled-border-color: #C7C1FA;
    background-image: linear-gradient(135deg, #7C6BF7 0%, #6D5DF6 100%);
    border: 0;
    box-shadow: 0 8px 18px -8px rgba(109, 93, 246, .75);
}
.site-app .btn-primary:disabled { background-image: none; box-shadow: none; }

.site-app .btn-outline-secondary {
    --bs-btn-color: #4A4A5A;
    --bs-btn-border-color: #E1E1EA;
    --bs-btn-hover-bg: #F4F4F9;
    --bs-btn-hover-border-color: #D5D5E2;
    --bs-btn-hover-color: #2B2B38;
}

/* ---- sidebar ---------------------------------------------------------- */
.site-app .mh-sidebar { background: #fff; border-right: 1px solid var(--mh-app-line); }

.site-app .mh-side-link { border-radius: .7rem; font-weight: 500; }

.site-app .mh-side-link.active,
.site-app .mh-side-link.is-branch-active {
    background-image: linear-gradient(135deg, #7C6BF7 0%, #6D5DF6 100%);
    color: #fff;
    box-shadow: 0 8px 18px -10px rgba(109, 93, 246, .9);
}
.site-app .mh-side-link.active svg,
.site-app .mh-side-link.is-branch-active svg { color: #fff; }

.site-app .mh-side-sublink { border-radius: .5rem; }
.site-app .mh-side-sublink.active { color: var(--mh-violet-ink); font-weight: 600; }

.site-app .mh-side-footer { border-top: 1px solid var(--mh-app-line); }
.site-app .mh-user-avatar { background: var(--mh-violet-soft); color: var(--mh-violet-ink); font-weight: 700; }

/* ---- badges / chips --------------------------------------------------- */
.site-app .badge.text-bg-light {
    background: var(--mh-violet-soft) !important;
    color: var(--mh-violet-ink) !important;
    border-radius: 999px; font-weight: 600;
}

/* ==========================================================================
   Sales invoice workspace
   ========================================================================== */

.mh-page-head { display: flex; align-items: flex-start; gap: 1rem; flex-wrap: wrap; margin-bottom: 1.25rem; }
.mh-page-head__ico {
    display: inline-flex; align-items: center; justify-content: center;
    width: 3rem; height: 3rem; flex: none; border-radius: .9rem;
    background: var(--mh-violet-soft); color: var(--mh-violet);
}
.mh-page-head__ico svg { width: 1.4rem; height: 1.4rem; }
.mh-page-head__actions { margin-left: auto; display: flex; gap: .5rem; flex-wrap: wrap; }

/* Sale type: two equal cards, the chosen one outlined in the accent. */
.mh-saletype { display: grid; grid-template-columns: 1fr 1fr; gap: .75rem; }
.mh-saletype__option {
    display: flex; align-items: center; justify-content: center; gap: .5rem;
    padding: .85rem .75rem; min-height: 56px;
    border: 1.5px solid var(--mh-app-line); border-radius: .8rem;
    background: #fff; color: #4A4A5A; font-weight: 600;
}
.mh-saletype__option svg { width: 1.05rem; height: 1.05rem; }
.mh-saletype__option:hover { border-color: #CFC9FB; }
.mh-saletype__option.is-active {
    border-color: var(--mh-violet);
    background: var(--mh-violet-soft);
    color: var(--mh-violet-ink);
}

/* Add-item row: the plus is the affordance, the scan icon sits opposite. */
.mh-additem { display: flex; align-items: center; gap: .75rem; border: 1px solid var(--mh-app-line); border-radius: .8rem; padding: .4rem .6rem; background: #FCFCFE; }
.mh-additem__plus {
    display: inline-flex; align-items: center; justify-content: center;
    width: 2.1rem; height: 2.1rem; flex: none; border: 0; border-radius: 999px;
    background: var(--mh-violet-soft); color: var(--mh-violet);
}
.mh-additem input { border: 0 !important; background: transparent !important; box-shadow: none !important; flex: 1 1 auto; padding-left: 0; }
.mh-additem__scan { color: #9A9AAE; flex: none; }

/* ---- line items ------------------------------------------------------- */
.mh-line {
    display: grid; align-items: center; gap: .85rem;
    grid-template-columns: 3.5rem 1fr 8rem 5.5rem 7rem 3rem;
    padding: .9rem; border: 1px solid var(--mh-app-line-soft); border-radius: .9rem;
    background: #fff;
}
.mh-line + .mh-line { margin-top: .6rem; }

.mh-line__thumb {
    width: 3.5rem; height: 3.5rem; border-radius: .7rem; overflow: hidden;
    background: #F4F4F9; display: flex; align-items: center; justify-content: center;
    color: #A9A9BC; flex: none;
}
.mh-line__thumb img { width: 100%; height: 100%; object-fit: cover; }
.mh-line__thumb svg { width: 1.4rem; height: 1.4rem; }

.mh-line__title { font-weight: 600; }
.mh-line__specs { display: flex; flex-wrap: wrap; gap: .15rem .9rem; margin-top: .2rem; }
.mh-line__spec { font-size: .8125rem; color: #6B6B80; }
.mh-line__spec b { color: #2B2B38; font-weight: 600; }

.mh-line__total { text-align: right; font-weight: 700; }
.mh-line__remove { display: flex; justify-content: flex-end; }
.mh-line__remove button {
    display: inline-flex; align-items: center; justify-content: center;
    width: 2.4rem; height: 2.4rem; border-radius: .6rem;
    border: 1px solid #F6D9DC; background: #FEF4F5; color: #D3455B;
}
.mh-line__remove button:hover { background: #FCE7EA; }

@media (max-width: 991.98px) {
    /* Never a table that scrolls sideways. The price is what gets edited
       on a phone, so it keeps a row of its own. */
    .mh-line { grid-template-columns: 3.5rem 1fr auto; grid-auto-rows: min-content; }
    .mh-line__info { grid-column: 2 / -1; }
    .mh-line__field { grid-column: span 1; }
    .mh-line__thumb { grid-row: span 2; }
    .mh-line__total { grid-column: 2 / 3; text-align: left; }
    .mh-line__remove { grid-column: 3; }
}

/* ---- summary ---------------------------------------------------------- */
.mh-summary-row { display: flex; align-items: center; justify-content: space-between; padding: .4rem 0; }
.mh-summary-row + .mh-summary-row { border-top: 1px dashed var(--mh-app-line-soft); }
.mh-summary-total {
    display: flex; align-items: center; justify-content: space-between;
    margin-top: .6rem; padding-top: .85rem; border-top: 1px solid var(--mh-app-line);
}
.mh-summary-total__value { font-size: 1.6rem; font-weight: 700; color: var(--mh-violet-ink); }
.site-app .mh-summary-card { background: linear-gradient(180deg, #FBFAFF 0%, #FFFFFF 60%); }

/* ---- sticky footer ---------------------------------------------------- */
.site-app .pos-footer {
    border-top: 1px solid var(--mh-app-line);
    box-shadow: 0 -8px 24px -18px rgba(16, 24, 40, .5);
    background: #fff;
}
.mh-footer-trust { display: flex; align-items: center; gap: .6rem; color: #6B6B80; }
.mh-footer-trust svg { width: 1.4rem; height: 1.4rem; color: #22A06B; flex: none; }
.mh-footer-figs { display: flex; align-items: center; gap: 1.25rem; margin-left: auto; }
@media (max-width: 767.98px) { .mh-footer-trust { display: none; } }

/* The app's top bar. .navbar.bg-primary outranks .mh-topbar-simple, so the
   bar rendered in the brand colour even though the simple variant asks for
   white. The design wants light chrome throughout: the sidebar carries the
   accent, and the bar above the content stays out of the way. */
body.site-app .navbar.bg-primary,
body.site-app .navbar.mh-topbar-simple {
    background: #fff !important;
    border-bottom: 1px solid var(--mh-app-line);
    box-shadow: none;
}
body.site-app .mh-topbar-simple .nav-link,
body.site-app .mh-topbar-simple .btn,
body.site-app .mh-topbar-simple .mh-top-icon-btn,
body.site-app .mh-topbar-simple .dropdown-toggle { color: #4A4A5A; }
body.site-app .mh-topbar-simple .mh-top-icon-btn:hover { background: #F4F4F9; color: var(--mh-violet-ink); }
body.site-app .mh-topbar-simple .mh-top-search .form-control {
    background: #F5F5FA; border-color: transparent; border-radius: 999px;
}
body.site-app .mh-topbar-simple .mh-top-search .form-control:focus {
    background: #fff; border-color: var(--mh-violet);
}

/* The phone's own chrome. It was near-black from the previous scheme,
   which left the app light on a desktop and dark in the hand. Same
   surfaces, same accent, either way. */
body.site-app .mchrome-top,
body.site-app .mchrome-bottom {
    background: #fff;
    color: #2B2B38;
    border-color: var(--mh-app-line);
}
body.site-app .mchrome-top { border-bottom: 1px solid var(--mh-app-line); }
body.site-app .mchrome-bottom { border-top: 1px solid var(--mh-app-line); }
body.site-app .mchrome-top__brand,
body.site-app .mchrome-top__brand span { color: #1B1B25; }
body.site-app .mchrome-tab { color: #6B6B80; }
body.site-app .mchrome-tab.is-active { color: var(--mh-violet); }
body.site-app .mchrome-tab.is-active svg { color: var(--mh-violet); }
/* .mchrome-fab is the positioning wrapper, not the button -- painting it
   drew a violet square behind the round button. The button is the thing
   that is round, so the button is the thing that gets the gradient. */
body.site-app .mchrome-fab__button {
    background-image: linear-gradient(135deg, #7C6BF7 0%, #6D5DF6 100%);
    background-color: var(--mh-violet);
    border-color: transparent;
    box-shadow: 0 8px 24px -6px rgba(109, 93, 246, .45);
}


/* ==========================================================================
   Shared pieces, so Inventory and Purchase are built from the same parts
   the Sales Invoice is -- not restyled one screen at a time.
   ========================================================================== */

/* ---- stat tile -------------------------------------------------------- */
.mh-stat {
    display: flex; align-items: center; gap: .8rem; height: 100%;
    padding: 1rem; background: #fff;
    border: 1px solid var(--mh-app-line); border-radius: 16px;
    box-shadow: 0 1px 2px rgba(16, 24, 40, .04), 0 12px 28px -18px rgba(16, 24, 40, .16);
}
.mh-stat__ico {
    display: inline-flex; align-items: center; justify-content: center;
    width: 2.6rem; height: 2.6rem; flex: none; border-radius: .75rem;
    background: var(--mh-violet-soft); color: var(--mh-violet);
}
.mh-stat__ico svg { width: 1.15rem; height: 1.15rem; }
.mh-stat__ico--amber { background: #FEF3E2; color: #C77700; }
.mh-stat__ico--green { background: #E6F7EF; color: #12855C; }
.mh-stat__ico--slate { background: #EEF0F5; color: #5A6478; }
.mh-stat__label { font-size: .8125rem; color: #6B6B80; }
.mh-stat__value { font-size: 1.4rem; font-weight: 700; line-height: 1.2; }

@media (max-width: 575.98px) {
    .mh-stat { padding: .75rem; gap: .6rem; }
    .mh-stat__ico { width: 2.1rem; height: 2.1rem; }
    .mh-stat__value { font-size: 1.15rem; }
}

/* ---- pill tabs -------------------------------------------------------- */
.mh-pilltabs { display: flex; flex-wrap: wrap; gap: .5rem; }
.mh-pill {
    display: inline-flex; align-items: center; gap: .4rem;
    padding: .4rem .85rem; min-height: 38px;
    border: 1px solid var(--mh-app-line); border-radius: 999px;
    background: #fff; color: #4A4A5A; font-size: .875rem; font-weight: 500;
    text-decoration: none;
}
.mh-pill:hover { border-color: #CFC9FB; color: var(--mh-violet-ink); }
.mh-pill.is-active {
    background-image: linear-gradient(135deg, #7C6BF7 0%, #6D5DF6 100%);
    border-color: transparent; color: #fff;
    box-shadow: 0 8px 18px -10px rgba(109, 93, 246, .9);
}
.mh-pill__count {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 1.35rem; padding: 0 .35rem; height: 1.35rem;
    border-radius: 999px; font-size: .75rem; font-weight: 600;
    background: #F1F1F7; color: #5A5A6E;
}
.mh-pill.is-active .mh-pill__count { background: rgba(255, 255, 255, .25); color: #fff; }

/* ---- filter bar ------------------------------------------------------- */
.site-app .mh-filterbar {
    background: #fff;
    border: 1px solid var(--mh-app-line) !important;
    border-radius: 16px !important;
    box-shadow: 0 1px 2px rgba(16, 24, 40, .04), 0 12px 28px -18px rgba(16, 24, 40, .16);
}

/* ---- selectable option card (condition, and anything like it) --------- */
.mh-option {
    position: relative; display: block; cursor: pointer;
    flex: 1 1 auto; min-width: 150px;
    padding: .7rem .85rem;
    border: 1.5px solid var(--mh-app-line); border-radius: .8rem; background: #fff;
}
.mh-option:hover { border-color: #CFC9FB; }
.mh-option input { margin-right: .4rem; }
.mh-option__label { font-weight: 600; }
.mh-option__hint { font-size: .8125rem; color: #6B6B80; }
/* :has is supported everywhere this app runs; the checked state is the
   whole card, not just the dot, because the card is what gets tapped. */
.mh-option:has(input:checked) {
    border-color: var(--mh-violet);
    background: var(--mh-violet-soft);
}
.mh-option:has(input:checked) .mh-option__label { color: var(--mh-violet-ink); }

/* ---- record rows ------------------------------------------------------ */
.site-app .rec-card,
.site-app .mh-rec-card {
    border: 1px solid var(--mh-app-line-soft) !important;
    border-radius: .9rem !important;
    background: #fff;
    text-decoration: none;
}
.site-app .rec-card:hover,
.site-app .mh-rec-card:hover {
    border-color: #CFC9FB !important;
    box-shadow: 0 10px 22px -16px rgba(16, 24, 40, .35);
}

/* Section titles inside detail cards pick up the accent glyph. */
.site-app .mh-section-title { display: inline-flex; align-items: center; gap: .5rem; font-weight: 600; }
.site-app .mh-section-title .mh-ico { color: var(--mh-violet); }

/* A panel that is not a Bootstrap .card but should look like one -- the
   device page groups its facts this way. */
.site-app .mh-panel {
    background: #fff;
    border: 1px solid var(--mh-app-line);
    border-radius: 16px;
    box-shadow: 0 1px 2px rgba(16, 24, 40, .04), 0 12px 28px -18px rgba(16, 24, 40, .16);
}


/* ==========================================================================
   Customer transactions — one history, both directions.
   ========================================================================== */

.mh-custcard {
    display: flex; align-items: center; gap: .8rem; height: 100%;
    padding: .9rem; background: #fff; text-decoration: none; color: inherit;
    border: 1px solid var(--mh-app-line); border-radius: 16px;
    box-shadow: 0 1px 2px rgba(16, 24, 40, .04), 0 12px 28px -18px rgba(16, 24, 40, .16);
}
.mh-custcard:hover { border-color: #CFC9FB; color: inherit; }
.mh-custcard__avatar {
    display: inline-flex; align-items: center; justify-content: center;
    width: 2.6rem; height: 2.6rem; flex: none; border-radius: 999px;
    background: var(--mh-violet-soft); color: var(--mh-violet-ink); font-weight: 700;
}
.mh-custcard__body { flex: 1 1 auto; min-width: 0; }
.mh-custcard__counts { display: flex; flex-wrap: wrap; gap: .35rem; margin-top: .4rem; }

/* The type chip. Icon AND word, never colour alone -- a badge that only
   differs by hue is not a label to someone who cannot see the hue. */
.mh-txn-chip {
    display: inline-flex; align-items: center; gap: .3rem;
    padding: .15rem .55rem; border-radius: 999px;
    font-size: .75rem; font-weight: 700; letter-spacing: .02em;
}
.mh-txn-chip--purchase { background: #FEF3E2; color: #8A5300; }
.mh-txn-chip--sale { background: #E6F7EF; color: #0B6B49; }

/* ---- timeline --------------------------------------------------------- */
.mh-timeline { display: flex; flex-direction: column; gap: .75rem; }

.mh-txn {
    display: grid; gap: .9rem;
    grid-template-columns: 2.5rem 1fr 12rem;
    padding: 1rem; background: #fff;
    border: 1px solid var(--mh-app-line); border-radius: 16px;
    box-shadow: 0 1px 2px rgba(16, 24, 40, .04), 0 12px 28px -18px rgba(16, 24, 40, .16);
}

.mh-txn__rail { display: flex; justify-content: center; }
.mh-txn__dot {
    display: inline-flex; align-items: center; justify-content: center;
    width: 2.3rem; height: 2.3rem; flex: none; border-radius: 999px;
}
.mh-txn__dot svg { width: 1.05rem; height: 1.05rem; }
.mh-txn__dot--purchase { background: #FEF3E2; color: #C77700; }
.mh-txn__dot--sale { background: #E6F7EF; color: #12855C; }

.mh-txn__head { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; margin-bottom: .4rem; }
.mh-txn__device + .mh-txn__device { margin-top: .5rem; padding-top: .5rem; border-top: 1px dashed var(--mh-app-line-soft); }

.mh-txn__side { text-align: right; border-left: 1px solid var(--mh-app-line-soft); padding-left: .9rem; }
.mh-txn__amount { font-size: 1.15rem; font-weight: 700; margin-top: .2rem; }

@media (max-width: 767.98px) {
    /* A card on a phone: the rail and the invoice column fold under the
       body rather than squeezing into columns nobody can read. */
    .mh-txn { grid-template-columns: 2.5rem 1fr; padding: .85rem; }
    .mh-txn__body { grid-column: 2; }
    .mh-txn__side {
        grid-column: 1 / -1; text-align: left;
        border-left: 0; padding-left: 0;
        border-top: 1px solid var(--mh-app-line-soft); padding-top: .6rem;
        display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
    }
    .mh-txn__side .btn { margin-top: 0 !important; margin-left: auto; }
    .mh-txn__amount { margin-top: 0; }
}


/* ==========================================================================
   Quick actions — the two things a counter does all day.
   ========================================================================== */
.mh-quickfab {
    position: fixed;
    bottom: calc(env(safe-area-inset-bottom, 0px) + 1.25rem);
    z-index: 1030;
    /* A circle holding one glyph, at every width. It used to be a wide
       pill with the words in it above 992px, so the same control looked
       like two different things depending on the screen -- and the pill
       covered a strip of whatever it was floating over. The words live
       on aria-label and title now. */
    display: inline-flex; align-items: center; justify-content: center;
    width: 56px; height: 56px; padding: 0;
    border-radius: 999px; border: 0;
    background-image: linear-gradient(135deg, #7C6BF7 0%, #6D5DF6 100%);
    color: #fff; text-decoration: none; font-weight: 600;
    box-shadow: 0 10px 26px -8px rgba(109, 93, 246, .55);
    transition: transform .12s ease, box-shadow .12s ease;
}
.mh-quickfab:hover, .mh-quickfab:focus-visible {
    color: #fff; transform: translateY(-2px);
    box-shadow: 0 14px 30px -8px rgba(109, 93, 246, .7);
}
.mh-quickfab:active { transform: translateY(0); }
.mh-quickfab svg { width: 1.35rem; height: 1.35rem; flex: none; }

.mh-quickfab--left { left: calc(env(safe-area-inset-left, 0px) + 1.25rem); }
.mh-quickfab--right { right: calc(env(safe-area-inset-right, 0px) + 1.25rem); }

/* The sidebar owns the left edge on a desktop, so the purchase button
   starts after it rather than under it. */
@media (min-width: 992px) {
    .mh-quickfab--left { left: calc(var(--mh-side-w, 260px) + 1.25rem); }
    body.site-app .mh-sidebar.is-collapsed ~ .mh-app-body .mh-quickfab--left { left: 6rem; }
}

/* On a phone the button sits above the bottom bar, and is a little
   smaller so two of them plus the bar do not fill the thumb zone. The
   shape itself is no longer set here -- it is round everywhere. */
@media (max-width: 991.98px) {
    .mh-quickfab {
        /* Clear of the bottom bar and the home indicator. */
        bottom: calc(var(--mh-bottom-h, 64px) + env(safe-area-inset-bottom, 0px) + .85rem);
        width: 52px; height: 52px;
    }
}

/*
 * Out of the way when they would be in it:
 *  - a modal is open and the buttons must not float over it
 *  - an invoice form is open, which has its own sticky action bar at the
 *    bottom; two competing bars is one too many, and the button would be
 *    offering the page you are already on
 */
body.modal-open .mh-quickfab,
body:has(.has-pos-footer) .mh-quickfab,
body:has(.mh-sticky-actions) .mh-quickfab { display: none; }

@media print { .mh-quickfab { display: none; } }


/* The floating buttons are fixed, so the end of the page needs room to
   scroll out from under them -- otherwise the last row of any list is
   permanently covered. */
@media (max-width: 991.98px) {
    body.site-app:has(.mh-quickfab) main {
        padding-bottom: calc(var(--mh-bottom-h, 64px) + env(safe-area-inset-bottom, 0px) + 5.5rem);
    }
}
@media (min-width: 992px) {
    body.site-app:has(.mh-quickfab) main { padding-bottom: 5.75rem; }
}


/* ==========================================================================
   User manual — a help centre, not a wall of text.
   ========================================================================== */
.mh-manual-nav { position: sticky; top: 1rem; }
.mh-manual-nav__list { display: flex; flex-direction: column; gap: .15rem; max-height: 70vh; overflow-y: auto; }
.mh-manual-nav__item {
    display: flex; align-items: center; gap: .5rem;
    padding: .5rem .65rem; border-radius: .5rem;
    color: #4A4A5A; text-decoration: none; font-size: .9rem; min-height: 40px;
}
.mh-manual-nav__item:hover { background: var(--mh-violet-soft); color: var(--mh-violet-ink); }
.mh-manual-nav__item .mh-ico { color: var(--mh-violet); flex: none; }

@media (max-width: 991.98px) {
    /* Folded away on a phone so the manual opens on the manual, not on a
       screenful of navigation. */
    .mh-manual-nav { position: static; }
    .mh-manual-nav__list { max-height: none; }
}

.mh-manual-h {
    margin: 1.35rem 0 .5rem; padding-bottom: .3rem;
    border-bottom: 1px solid var(--mh-app-line-soft);
    color: var(--mh-violet-ink); font-weight: 600;
}
.mh-manual-h:first-of-type { margin-top: 0; }

.mh-manual-list { padding-left: 1.1rem; margin-bottom: 0; }
.mh-manual-list li { margin-bottom: .3rem; }
.mh-manual-list--notes li { color: #4A4A5A; }

.mh-manual-details {
    border: 1px solid var(--mh-app-line-soft); border-radius: .65rem;
    padding: .6rem .8rem; margin-bottom: .5rem; background: #FCFCFE;
}
.mh-manual-details > summary {
    cursor: pointer; font-weight: 600; list-style: none;
    display: flex; align-items: center; gap: .5rem;
}
.mh-manual-details > summary::-webkit-details-marker { display: none; }
.mh-manual-details > summary::before {
    content: '▸'; color: var(--mh-violet); flex: none; transition: transform .12s ease;
}
.mh-manual-details[open] > summary::before { transform: rotate(90deg); }
.mh-manual-details[open] { background: #fff; border-color: #DED9FB; }

.mh-manual-steps { margin: .6rem 0 0; padding-left: 1.3rem; }
.mh-manual-steps li { margin-bottom: .35rem; }

.mh-manual-table { display: flex; flex-direction: column; gap: .25rem; }
.mh-manual-row {
    display: grid; gap: .75rem; align-items: start;
    grid-template-columns: 12rem 7rem 1fr;
    padding: .5rem .1rem; border-bottom: 1px dashed var(--mh-app-line-soft);
}
.mh-manual-row--2 { grid-template-columns: 14rem 1fr; }
.mh-manual-row:last-child { border-bottom: 0; }

@media (max-width: 767.98px) {
    /* Never a table that scrolls sideways. */
    .mh-manual-row, .mh-manual-row--2 { grid-template-columns: 1fr; gap: .2rem; }
}

/* The contents list is sticky and the quick-action buttons are fixed, so
   the last entry needs room to clear them. */
.mh-manual-nav__list { padding-bottom: 4.5rem; }
@media (max-width: 991.98px) { .mh-manual-nav__list { padding-bottom: .25rem; } }

/* The contents list is folded away on a phone and always open from lg up.
   That is a breakpoint question, so CSS answers it -- the previous version
   asked a resize listener, which never fires if the page simply loads wide. */
@media (min-width: 992px) {
    .mh-manual-nav__body { display: block !important; }
}


/* Instant search: no button, a clear affordance, and a quiet busy hint. */
/* Block, not inline: the wrapper sits inside flex-grow-1 containers and
   an inline box would stop the field filling its column. */
.mh-instant { position: relative; display: block; width: 100%; }
.mh-instant input { padding-right: 4.75rem; }
.mh-instant__clear {
    position: absolute; top: 50%; right: 2.4rem; transform: translateY(-50%);
    width: 1.6rem; height: 1.6rem; border: 0; border-radius: 999px;
    background: #E9E9F2; color: #5A5A6E; line-height: 1;
    display: none; align-items: center; justify-content: center; font-size: .9rem;
}
.mh-instant__clear:hover { background: #DCDCE8; color: #2B2B38; }
.mh-instant.has-value .mh-instant__clear { display: inline-flex; }
.mh-instant__busy {
    position: absolute; top: 50%; right: .7rem; transform: translateY(-50%);
    width: 1rem; height: 1rem; border-radius: 999px;
    border: 2px solid var(--mh-violet-soft); border-top-color: var(--mh-violet);
    display: none; animation: mh-spin .6s linear infinite;
}
.mh-instant.is-busy .mh-instant__busy { display: block; }
@keyframes mh-spin { to { transform: translateY(-50%) rotate(360deg); } }

.mh-combobox-option.is-highlighted,
[data-combobox] button.is-highlighted { background: var(--mh-violet-soft); }


/* ==========================================================================
   Combobox suggestions.
   --------------------------------------------------------------------------
   Anchored inside the field, not placed by script.

   This used to be position:fixed with top/left/width written from JS on every
   scroll, resize and keyboard event, sized against the viewport minus whatever
   was pinned to an edge. On a form whose Save row is sticky and whose footer is
   fixed, that left a field near the bottom of the screen with about 24px of
   "room below", so the list was thrown ABOVE the field and across whatever card
   happened to be up there -- and because a sticky bar's overlap depends on
   scroll position, the answer changed as the user scrolled.

   Anchoring removes the whole problem rather than tuning it. The panel is a
   child of the field's box, so it moves with the field for free. Every ancestor
   from here to <html> is overflow:visible and none applies a transform, so
   there is nothing to clip it and nothing to shift its coordinate space.
   ========================================================================== */
.mh-cb-field { position: relative; }

.mh-cb-panel {
    position: absolute;
    top: calc(100% + .25rem);          /* directly under the input */
    left: 0;
    right: 0;                          /* exactly the field's width */

    /* Above every bar in the app: .mchrome-bottom 1035, .pos-footer 1030,
       .mh-sticky-actions 20. The wrapper is position:relative with z-index
       auto, so it creates no stacking context and this competes at the root. */
    z-index: 1060;

    /* Tall enough to be worth opening, short enough to leave the field and
       some context visible on a phone. Long lists scroll inside. */
    max-height: min(19rem, 50vh);
    overflow-y: auto;
    overscroll-behavior: contain;      /* scrolling the list stops at its end */
    -webkit-overflow-scrolling: touch;
    border-radius: .65rem;
    box-shadow: 0 12px 28px -10px rgba(16, 24, 40, .28);
    touch-action: manipulation;        /* the list must not vanish before the tap lands */
}

/* Comfortable to hit without wasting a phone screen: 44px is the tap target,
   and the text stays at its normal size. */
.mh-cb-panel button,
.mh-cb-panel .mh-cb-option { min-height: 44px; }

/* When the browser scrolls a focused field into view it now reserves room for
   the list underneath it, so opening a combobox near the bottom of a long form
   -- or with a soft keyboard up -- does not leave the suggestions off-screen.
   This is what the JS keyboard arithmetic was for; the browser does it better. */
[data-combobox] { scroll-margin-bottom: 21rem; }



/* ==========================================================================
   Top search suggestions.
   --------------------------------------------------------------------------
   Anchored inside .mh-top-search, which is already position:relative, for
   the same reason the combobox panel is anchored to its field: it then
   scrolls with the bar it belongs to and nothing has to reposition it.
   ========================================================================== */
.mh-topsearch-panel {
    position: absolute;
    top: calc(100% + .35rem);
    left: 0;
    right: 0;
    z-index: 1062;                 /* above the combobox panel at 1060 */
    max-height: min(22rem, 60vh);
    overflow-y: auto;
    overscroll-behavior: contain;
    background: #fff;
    border: 1px solid var(--mh-line, #dee2e6);
    border-radius: .65rem;
    box-shadow: 0 12px 28px -10px rgba(16, 24, 40, .28);
}

.mh-topsearch-item {
    display: block;
    padding: .55rem .75rem;
    min-height: 44px;              /* a thumb-sized target */
    text-decoration: none;
    color: inherit;
    border-bottom: 1px solid var(--mh-line, #eef1f6);
}
.mh-topsearch-item:last-child { border-bottom: 0; }
.mh-topsearch-item:hover,
.mh-topsearch-item:focus { background: var(--mh-violet-soft, #f2f0ff); }

.mh-topsearch-item__name { display: block; font-weight: 600; }
.mh-topsearch-item__sub { display: block; font-size: .8125rem; color: var(--mh-muted, #6c757d); }
.mh-topsearch-empty { padding: .75rem; font-size: .875rem; color: var(--mh-muted, #6c757d); }


/* ==========================================================================
   Report tables.
   --------------------------------------------------------------------------
   One place, so all eight reports match and a ninth inherits it.

   The complaint was that columns did not line up with their headings. The
   cause was bare <th>/<td> with no alignment: a heading sat left while the
   figure under it sat wherever it landed. In every one of these tables the
   first column is the label and the rest are figures, so the pair is
   aligned per column -- label left, figures right, header and cell agreeing.
   ========================================================================== */
.mh-report-table { width: 100%; margin-bottom: 0; }

/* Equal padding and one row height, rather than whatever .table-sm left. */
.mh-report-table > thead > tr > th,
.mh-report-table > tbody > tr > td,
.mh-report-table > tfoot > tr > td,
.mh-report-table > tfoot > tr > th {
    padding: .5rem .625rem;
    vertical-align: middle;
    line-height: 1.35;
}

.mh-report-table > thead > tr > th {
    background: var(--mh-surface-2, #f7f8fb);
    border-bottom: 1px solid var(--mh-line, #dee2e6);
    font-weight: 600;
    font-size: .8125rem;
    color: var(--mh-muted, #5a5a6e);
    white-space: nowrap;           /* a wrapped heading breaks the grid */
}

/* Label column left, every figure column right -- applied to the header and
   the cell together, which is the whole point. */
.mh-report-table > thead > tr > th:first-child,
.mh-report-table > tbody > tr > td:first-child { text-align: left; }

.mh-report-table > thead > tr > th:not(:first-child),
.mh-report-table > tbody > tr > td:not(:first-child),
.mh-report-table > tfoot > tr > td:not(:first-child) {
    text-align: right;
    font-variant-numeric: tabular-nums;   /* digits share a width, so columns of
                                             figures line up down the page */
}

.mh-report-table > tbody > tr > td { border-top: 1px solid var(--mh-line-soft, #eef1f6); }
.mh-report-table > tbody > tr:hover > td { background: var(--mh-surface-2, #f7f8fb); }

/* The heading stays put while a long report scrolls. */
.mh-report-scroll {
    overflow-x: auto;
    overflow-y: auto;
    max-height: 70vh;
    -webkit-overflow-scrolling: touch;
}
.mh-report-scroll .mh-report-table > thead > tr > th {
    position: sticky;
    top: 0;
    z-index: 2;
}

/* On a phone a five-column report has to scroll sideways; it should not make
   the PAGE scroll sideways, and it should be obvious that it can. */
@media (max-width: 767.98px) {
    .mh-report-table { min-width: 32rem; }
    .mh-report-table > thead > tr > th,
    .mh-report-table > tbody > tr > td { padding: .5rem; font-size: .875rem; }
}

/* Filters and actions on a report, so every report's controls sit the same. */
.mh-report-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: .5rem;
    margin-bottom: 1rem;
}
.mh-report-toolbar .form-label { margin-bottom: .25rem; }
.mh-report-toolbar > * { min-width: 0; }

/* The landing grid. */
.mh-report-card {
    display: flex;
    flex-direction: column;
    height: 100%;
    padding: 1rem;
    border: 1px solid var(--mh-line, #dee2e6);
    border-radius: .75rem;
    background: #fff;
    text-decoration: none;
    color: inherit;
    transition: box-shadow .15s ease, border-color .15s ease;
}
.mh-report-card:hover,
.mh-report-card:focus-visible {
    border-color: var(--mh-violet, #6c5ce7);
    box-shadow: 0 10px 24px -14px rgba(16, 24, 40, .35);
}
.mh-report-card__title { font-weight: 600; margin: .6rem 0 .2rem; }
.mh-report-card__desc { font-size: .8125rem; color: var(--mh-muted, #6c757d); margin: 0; }
.mh-report-card__cta { margin-top: auto; padding-top: .75rem; font-size: .8125rem; font-weight: 600; }


/* ==========================================================================
   The operational row on every dashboard.
   --------------------------------------------------------------------------
   auto-fit with a minimum means the tiles reflow from 2 across on a phone to
   6 on a wide screen without a breakpoint for each step, and -- the point
   after the squashed-tile bug -- no tile can be narrower than 8.5rem, so a
   two-word label has somewhere to go.
   ========================================================================== */
.mh-opsgrid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr));
    gap: .6rem;
}

.mh-opstile {
    display: flex;
    flex-direction: column;
    min-width: 0;                  /* a long label wraps instead of pushing out */
    padding: .75rem .85rem;
    background: var(--mh-white, #fff);
    border: 1px solid var(--mh-border, #dee2e6);
    border-radius: var(--mh-radius-md, .7rem);
}

/* One shape for every tile: label, then the number, then the unit. The
   number is pushed down by mt-auto equivalents so it sits on the same line
   across the row even when one label wraps to two lines. */
.mh-opstile__label {
    font-size: .75rem;
    line-height: 1.25;
    color: var(--mh-muted, #6c757d);
    text-transform: uppercase;
    letter-spacing: .02em;
    min-height: 2.5em;             /* two lines of label, so numbers align */
}
.mh-opstile__value {
    margin-top: auto;
    font-size: 1.5rem;
    font-weight: 600;
    line-height: 1.15;
    font-variant-numeric: tabular-nums;
}
.mh-opstile__unit { font-size: .75rem; color: var(--mh-muted, #6c757d); }

@media (max-width: 400px) {
    .mh-opsgrid { grid-template-columns: repeat(2, 1fr); }
    .mh-opstile__value { font-size: 1.25rem; }
}


/* ==========================================================================
   Clearance for the floating quick-action buttons.
   --------------------------------------------------------------------------
   They are position:fixed, so nothing in the flow reserves room for them and
   they were landing on top of the last dashboard tile. The page now ends
   with space for the button, the bottom tab bar beneath it, and the phone's
   own home indicator.
   ========================================================================== */
@media (max-width: 991.98px) {
    body.site-app .mh-app-body {                    /* mh-fab-clearance */
        padding-bottom: calc(9rem + env(safe-area-inset-bottom, 0px));
    }
}

/* A sticky Save row already reserves its own space and hides the buttons
   (see body:has(.mh-sticky-actions)), so it must not stack a second gap. */
@media (max-width: 991.98px) {
    body.site-app:has(.mh-sticky-actions) .mh-app-body {
        padding-bottom: calc(5rem + env(safe-area-inset-bottom, 0px));
    }
}


/* ==========================================================================
   SIDEBAR -- expanded and collapsed
   ==========================================================================
   Appended last so these rules refine the older blocks above rather than
   requiring them to be untangled. Two states, one movement between them.
   ========================================================================== */

.mh-sidebar {
    --mh-side-w: 248px;
    --mh-side-w-collapsed: 72px;
    --mh-side-ico: 18px;

    width: var(--mh-side-w);
    flex: 0 0 var(--mh-side-w);
    padding: 14px 12px;
    /* Width and padding move together; anything slower than this reads as
       lag rather than as animation. */
    transition: width .18s ease, flex-basis .18s ease, padding .18s ease;
    overflow-x: hidden;
}

.mh-sidebar.is-collapsed {
    width: var(--mh-side-w-collapsed);
    flex: 0 0 var(--mh-side-w-collapsed);
    padding-left: 10px;
    padding-right: 10px;

    /*
     * MUST stay visible, or the flyout submenu is invisible.
     *
     * The flyout is anchored at left:calc(100% + 8px) -- outside this
     * 72px rail on purpose. The base rule sets overflow-y:auto, and any
     * overflow value other than visible makes this element clip its
     * absolutely-positioned descendants, so the panel was being drawn
     * and thrown away in the same frame.
     *
     * Affordable here specifically because the collapsed rail has no
     * in-flow submenus: brand + nine icons + footer is about 500px, so
     * the scrolling the EXPANDED state needs does not apply.
     */
    overflow: visible;
}

/* ---------- labels ----------------------------------------------------- */

/*
 * Hidden by style, not by removal. The text stays in the accessibility
 * tree so a collapsed icon is still announced by name, and the width can
 * be transitioned so the label slides away with the rail instead of
 * disappearing a frame ahead of it.
 */
.mh-side-label {
    white-space: nowrap;
    overflow: hidden;
    opacity: 1;
    max-width: 12rem;
    transition: opacity .12s ease, max-width .18s ease;
}

.mh-sidebar.is-collapsed .mh-side-label {
    opacity: 0;
    max-width: 0;
    /* Nothing reserved: no stray gap where the words used to be. */
    margin: 0 !important;
    pointer-events: none;
}

.mh-sidebar.is-collapsed .mh-side-subswitch,
.mh-sidebar.is-collapsed .mh-side-divider {
    display: none;
}

/* ---------- rows ------------------------------------------------------- */

.mh-side-link {
    gap: 12px;
    padding: 9px 11px;
    border-radius: .6rem;
    transition: background-color .12s ease, color .12s ease;
}

/*
 * Qualified with .mh-side-link so it actually wins.
 *
 * The pre-existing `.mh-side-link svg { width: 18px }` scores (0,1,1)
 * against a bare `.mh-side-ico` at (0,1,0), so the unqualified version of
 * this rule lost every time -- the file declared one size and the browser
 * drew another. The variable now matches what is really rendered.
 */
.mh-sidebar .mh-side-ico,
.mh-install-btn .mh-side-ico {
    width: var(--mh-side-ico);
    height: var(--mh-side-ico);
    /* Fixed basis, so every label starts at the same x whatever the glyph. */
    flex: 0 0 var(--mh-side-ico);
    color: var(--mh-muted);
    transition: color .12s ease;
}

.mh-side-link.active .mh-side-ico,
.mh-side-link.is-branch-active .mh-side-ico {
    color: inherit;
}

.mh-sidebar.is-collapsed .mh-side-link,
.mh-sidebar.is-collapsed .mh-side-brand,
.mh-sidebar.is-collapsed .mh-side-footer,
.mh-sidebar.is-collapsed .mh-side-collapse-btn {
    justify-content: center;
    gap: 0;
    padding-left: 0;
    padding-right: 0;
}

.mh-sidebar.is-collapsed .mh-side-chevron {
    display: none;
}

.mh-side-brand img {
    border-radius: 50%;
    /* Never distorted, in either state. */
    object-fit: cover;
    flex: 0 0 28px;
}

/* ---------- collapsed tooltip ------------------------------------------ */

/*
 * CSS-only, and only while collapsed. There is no tooltip component in
 * this application, and Bootstrap's requires JS initialisation for every
 * element -- more moving parts than a label needs.
 */
.mh-sidebar.is-collapsed [data-tip]:not([data-tip=""]) {
    position: relative;
}

.mh-sidebar.is-collapsed [data-tip]:not([data-tip=""])::after {
    content: attr(data-tip);
    position: absolute;
    left: calc(100% + 10px);
    top: 50%;
    transform: translateY(-50%);
    background: var(--mh-graphite, #232733);
    color: #fff;
    font-size: .78rem;
    font-weight: 600;
    line-height: 1;
    padding: 7px 10px;
    border-radius: .4rem;
    white-space: nowrap;
    opacity: 0;
    visibility: hidden;
    transition: opacity .12s ease;
    z-index: 1080;
    pointer-events: none;
}

.mh-sidebar.is-collapsed [data-tip]:not([data-tip=""]):hover::after,
.mh-sidebar.is-collapsed [data-tip]:not([data-tip=""]):focus-visible::after {
    opacity: 1;
    visibility: visible;
}

/* ---------- submenus --------------------------------------------------- */

.mh-side-group {
    position: relative;
}

/* Expanded: in place, and only when its group is open. */
.mh-side-submenu {
    display: none;
    padding-left: 32px;
}

.mh-side-submenu.is-open {
    display: flex;
}

.mh-side-flyout-title {
    display: none;
}

/*
 * Collapsed: a panel floating beside the icon. Shown on hover and on
 * focus-within, so it is reachable by keyboard and not only by mouse.
 * .is-open is ignored here -- while collapsed, what opens a submenu is
 * pointing at it, not whatever was left open before the rail narrowed.
 */
.mh-sidebar.is-collapsed .mh-side-submenu,
.mh-sidebar.is-collapsed .mh-side-submenu.is-open {
    display: none;
    position: absolute;
    left: calc(100% + 8px);
    top: -6px;
    min-width: 210px;
    padding: 8px;
    background: #fff;
    border: 1px solid var(--mh-border, #E6E9F0);
    border-radius: .7rem;
    box-shadow: 0 12px 28px rgba(16, 20, 35, .13);
    z-index: 1070;
}

.mh-sidebar.is-collapsed .mh-side-group:hover .mh-side-submenu,
.mh-sidebar.is-collapsed .mh-side-group:focus-within .mh-side-submenu {
    display: flex;
}

.mh-sidebar.is-collapsed .mh-side-flyout-title {
    display: block;
    font-size: .7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--mh-muted, #6B7280);
    padding: 4px 10px 6px;
}

.mh-side-sublink {
    transition: background-color .12s ease, color .12s ease;
}

/* ---------- footer and collapse button --------------------------------- */

.mh-sidebar.is-collapsed .mh-side-footer-meta,
.mh-sidebar.is-collapsed .mh-side-status {
    display: none;
}

.mh-side-collapse-btn {
    border-radius: .6rem;
    transition: background-color .12s ease;
}

.mh-side-collapse-btn .mh-side-ico {
    transition: transform .18s ease;
}

/* ---------- keyboard --------------------------------------------------- */

.mh-side-link:focus-visible,
.mh-side-sublink:focus-visible,
.mh-side-collapse-btn:focus-visible,
.mh-side-brand:focus-visible {
    outline: 2px solid var(--mh-accent, #6D4AFF);
    outline-offset: 2px;
}

/* ---------- main content ----------------------------------------------- */

/*
 * The body is already flex:1 beside the rail, so it follows the width on
 * its own. Only min-width:0 is restated -- without it a wide table inside
 * refuses to shrink and pushes the page into horizontal scroll as the
 * sidebar expands.
 */
body.site-app > .mh-app-body {
    min-width: 0;
}

@media (prefers-reduced-motion: reduce) {
    .mh-sidebar,
    .mh-side-label,
    .mh-side-ico,
    .mh-side-collapse-btn .mh-side-ico {
        transition: none;
    }
}


/* ==========================================================================
   INSTALL BUTTON, SIGN-IN SCREEN, CREDIT
   ========================================================================== */

/* ---------- install button --------------------------------------------- */

.mh-install-wrap {
    margin-top: 4px;
}

.mh-install-btn {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    padding: 9px 11px;
    border: 1px dashed var(--mh-border, #E6E9F0);
    border-radius: .6rem;
    background: transparent;
    color: var(--mh-graphite, #232733);
    font-size: .85rem;
    font-weight: 600;
    text-align: left;
    cursor: pointer;
    transition: background-color .12s ease, border-color .12s ease;
}

.mh-install-btn:hover {
    background: #F3F5F9;
    border-color: var(--mh-accent, #6D4AFF);
}

.mh-install-btn:focus-visible {
    outline: 2px solid var(--mh-accent, #6D4AFF);
    outline-offset: 2px;
}

/* Centred on the collapsed rail, exactly like every other row. */
.mh-sidebar.is-collapsed .mh-install-btn {
    justify-content: center;
    gap: 0;
    padding-left: 0;
    padding-right: 0;
}

.mh-install-hint {
    margin: 6px 2px 0;
    font-size: .75rem;
    line-height: 1.35;
    color: var(--mh-muted, #6B7280);
}

.mh-sidebar.is-collapsed .mh-install-hint {
    display: none;
}

/* On the sign-in card it is an offer, not a menu row. */
.mh-install-wrap--card {
    margin-top: 14px;
    padding-top: 14px;
    border-top: 1px solid var(--mh-border, #E6E9F0);
}

/* ---------- the credit -------------------------------------------------- */

.mh-credit {
    margin: 10px 2px 2px;
    font-size: .72rem;
    line-height: 1.3;
    color: var(--mh-muted, #6B7280);
    text-align: center;
}

.mh-credit strong {
    font-weight: 700;
    color: var(--mh-graphite, #232733);
}

/* ---------- sign-in screen ---------------------------------------------- */

.mh-login-page {
    margin: 0;
    min-height: 100dvh;
    background: linear-gradient(180deg, #F7F8FB 0%, #EFF1F6 100%);
    display: flex;
}

.mh-login-shell {
    margin: auto;
    width: 100%;
    max-width: 420px;
    /* Breathing room on a phone, and clear of the notch. */
    padding: 24px 18px calc(24px + env(safe-area-inset-bottom));
}

.mh-login-card {
    background: #fff;
    border: 1px solid var(--mh-border, #E6E9F0);
    border-radius: 1rem;
    padding: 26px 22px 22px;
    box-shadow: 0 18px 40px rgba(16, 20, 35, .08);
}

.mh-login-brand {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 20px;
}

.mh-login-brand img {
    border-radius: 50%;
    object-fit: cover;
    flex: 0 0 52px;
}

.mh-login-title {
    margin: 0;
    font-size: 1.15rem;
    font-weight: 800;
    letter-spacing: -.01em;
    color: var(--mh-graphite, #232733);
}

.mh-login-sub {
    margin: 2px 0 0;
    font-size: .8rem;
    color: var(--mh-muted, #6B7280);
}

/* 44px minimum: this is used on a phone, at a counter, in a hurry. */
.mh-login-card .form-control {
    min-height: 44px;
}

.mh-login-submit {
    min-height: 46px;
    font-weight: 700;
}

.mh-login-help {
    margin: 16px 0 0;
    font-size: .78rem;
    text-align: center;
    color: var(--mh-muted, #6B7280);
}

/* ==========================================================================
   ATTENDANCE LIST + LARGER FORM FIELDS
   ========================================================================== */

.mh-attend-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
    /* Ten or twelve staff should not push the rest of the dashboard down. */
    max-height: 260px;
    overflow-y: auto;
}

.mh-attend-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 5px 2px;
}

.mh-attend-name {
    font-size: .85rem;
    font-weight: 600;
    color: var(--mh-graphite, #232733);
    /* A long name must not push the status off the row. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mh-attend-state {
    margin-left: auto;
    font-size: .76rem;
    font-weight: 700;
    white-space: nowrap;
}

.mh-attend-state.is-present { color: #157347; }
.mh-attend-state.is-absent  { color: var(--mh-muted, #6B7280); font-weight: 600; }

.mh-attend-time {
    font-weight: 500;
    color: var(--mh-muted, #6B7280);
    margin-left: 4px;
}

/* An absent member of staff is greyed rather than coloured -- present is
   the state worth picking out at a glance. */
.mh-avatar-sm.is-out {
    background: #EEF1F6 !important;
    color: var(--mh-muted, #6B7280) !important;
}

/* ---------- form fields that have to hold real values ------------------ */

/*
 * 46px, and a slightly larger figure. The Money Counter's Date and Amount
 * were 120px-wide, 31px-tall controls: a lakh figure was cut off and a
 * date showed without its year. An owner has to be able to read back what
 * they typed before pressing Record.
 */
.mh-field-lg {
    min-height: 46px;
    font-size: 1rem;
}

.mh-amount {
    font-variant-numeric: tabular-nums;
    letter-spacing: .01em;
}

.mh-amount-echo {
    min-height: 1.1em;
    font-weight: 600;
    color: var(--mh-graphite, #232733);
}

/* ===== VALUATION PRICE DISCLAIMER (owner, 2026-09-26) =====
   The old wording was three lines of accurate prose that customers skipped.
   This is the same promise in one sentence, in danger colours, sitting
   against the price rather than in small print below it. Warning, not alarm:
   a tinted panel and a red left edge, no shouting. */
.qv__pricedisc--warn,
.vq-disclaim {
    display: flex; align-items: flex-start; gap: .55rem;
    margin: .75rem auto 0; max-width: 34rem;
    padding: .7rem .85rem; border-radius: 12px;
    background: #FEF2F2; border: 1px solid #FECACA; border-left: 4px solid #DC2626;
    color: #991B1B; font-size: .8rem; line-height: 1.5; text-align: left;
}
.qv__pricedisc--warn svg,
.vq-disclaim svg { flex: 0 0 auto; margin-top: .1rem; color: #DC2626; }
.qv__pricedisc--warn strong,
.vq-disclaim strong { color: #7F1D1D; }
.qv__pricedisc__sub,
.vq-disclaim__sub { display: block; margin-top: .15rem; font-weight: 600; opacity: .85; }
.vq-disclaim { max-width: none; margin-top: 1rem; font-size: .85rem; }

/* The page is dark in the Midnight/dark themes; a white-red panel would
   glare. Same meaning, readable ground. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .qv__pricedisc--warn,
    :root:not([data-theme="light"]) .vq-disclaim {
        background: rgba(220, 38, 38, .12); border-color: rgba(248, 113, 113, .4); color: #FCA5A5;
    }
    :root:not([data-theme="light"]) .qv__pricedisc--warn strong,
    :root:not([data-theme="light"]) .vq-disclaim strong { color: #FECACA; }
}

/* ===== WARRANTY: MONTHS OR DATE (owner, 2026-09-26) ===== */
.dv__seg { display: inline-flex; padding: 3px; border-radius: 12px; background: var(--mh-page, #F6F8FB); border: 1px solid var(--mh-border, #E4E9F0); gap: 3px; }
.dv__seg__btn {
    border: 0; background: transparent; cursor: pointer;
    padding: .42rem .85rem; border-radius: 10px; font-size: .82rem; font-weight: 600;
    color: var(--mh-muted, #64707F);
}
.dv__seg__btn.is-on { background: #FFFFFF; color: var(--mh-ink, #0B0F16); box-shadow: 0 1px 3px rgba(11, 15, 22, .12); }

/* ==========================================================================
   Sidebar developer credit (owner, 2026-10-06)
   ==========================================================================
   Replaces the single "Product of Prabhabi Infocom" line with the owner's
   two-line attribution and the circular mark.

   The mark sits outside .mh-side-label on purpose: when the rail collapses
   to 72px every label is hidden, and a 20px circle is the only thing that
   still fits -- so the attribution survives the collapse instead of
   disappearing or wrapping into an awkward column.

   Sidebar width is untouched; this only lays out what was already there.
   ========================================================================== */

.mh-credit {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
}

.mh-credit__mark {
    display: inline-flex;
    line-height: 0;
    border-radius: 50%;
    /* The asset is already circular; the radius is here so a focus ring
       follows the shape rather than boxing it. */
    opacity: .85;
    transition: opacity .15s ease;
}

.mh-credit__mark:hover,
.mh-credit__mark:focus-visible { opacity: 1; }

.mh-credit__mark img {
    width: 20px;
    height: 20px;
    border-radius: 50%;
    display: block;
}

.mh-credit__text { text-wrap: balance; }

/* The second sentence reads as its own line without a <br>, which would
   also break at the wrong place on a narrow rail. */
.mh-credit__line { display: block; margin-top: 2px; }

.mh-credit a {
    color: inherit;
    text-decoration: none;
}

.mh-credit a:hover,
.mh-credit a:focus-visible { text-decoration: underline; }

/* ==========================================================================
   User Manual: the tour invitation and the visual index (owner, 2026-10-06)
   ==========================================================================
   The manual already had search, a contents list and per-section icons.
   What it lacked was a way to see the SHAPE of the application without
   reading a list of names, which is what the tile grid below is for. It
   hides itself the moment a search is typed, because then the matching
   sections are the answer.
   ========================================================================== */

.mh-tour-invite {
    display: flex;
    align-items: center;
    gap: .9rem;
    padding: .9rem 1rem;
    margin-bottom: 1rem;
    border: 1px solid var(--mh-line, #E5E7EB);
    border-radius: 14px;
    background: var(--mh-brand-soft, #EFF4FF);
    color: inherit;
    text-decoration: none;
    transition: transform .15s ease, box-shadow .15s ease;
}

.mh-tour-invite:hover,
.mh-tour-invite:focus-visible {
    color: inherit;
    transform: translateY(-1px);
    box-shadow: 0 6px 18px rgba(16, 24, 40, .08);
}

.mh-tour-invite__ico {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border-radius: 11px;
    background: var(--mh-surface, #FFF);
    color: var(--mh-brand, #2563EB);
}

.mh-tour-invite__ico svg { width: 19px; height: 19px; }

.mh-tour-invite__text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.mh-tour-invite__text span { font-size: .84rem; color: var(--mh-muted, #6B7280); }
.mh-tour-invite__go { margin-left: auto; color: var(--mh-muted, #6B7280); flex: 0 0 auto; }
.mh-tour-invite__go svg { width: 18px; height: 18px; }

/* ---------- the visual index ------------------------------------------- */

.mh-manual-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    gap: .75rem;
    margin-bottom: 1.25rem;
}

.mh-manual-tile {
    display: flex;
    flex-direction: column;
    gap: .3rem;
    padding: .9rem;
    border: 1px solid var(--mh-line, #E5E7EB);
    border-radius: 14px;
    background: var(--mh-surface, #FFF);
    color: inherit;
    text-decoration: none;
    transition: border-color .15s ease, transform .15s ease;
}

.mh-manual-tile:hover,
.mh-manual-tile:focus-visible {
    color: inherit;
    border-color: var(--mh-brand, #2563EB);
    transform: translateY(-1px);
}

.mh-manual-tile__ico {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    margin-bottom: .2rem;
    border-radius: 9px;
    background: var(--mh-brand-soft, #EFF4FF);
    color: var(--mh-brand, #2563EB);
}

.mh-manual-tile__ico svg { width: 17px; height: 17px; }

.mh-manual-tile__title { font-weight: 600; line-height: 1.25; }

.mh-manual-tile__blurb {
    font-size: .8rem;
    line-height: 1.4;
    color: var(--mh-muted, #6B7280);
}

.mh-manual-tile__meta {
    margin-top: auto;
    padding-top: .35rem;
    font-size: .72rem;
    color: var(--mh-muted, #6B7280);
}

@media (prefers-reduced-motion: reduce) {
    .mh-tour-invite,
    .mh-manual-tile { transition: none; }
    .mh-tour-invite:hover,
    .mh-manual-tile:hover { transform: none; }
}


/* ---------- User Manual: handover polish (2026-10-16) -------------------
   Numbered step badges, check-marked feature lists, styled arrows between
   stages, bold leading labels (set by UserManual::rich) and a floating
   "Top" button. Presentation only; the words are unchanged. */
.mh-manual-steps { list-style: none; counter-reset: mhstep; margin: .6rem 0 0; padding-left: 0; }
.mh-manual-steps li {
    position: relative;
    margin-bottom: .4rem;
    padding: .5rem .7rem .5rem 2.5rem;
    border-radius: 10px;
    background: #F8F8FD;
    line-height: 1.5;
}
.mh-manual-steps li::before {
    counter-increment: mhstep;
    content: counter(mhstep);
    position: absolute;
    left: .6rem;
    top: .55rem;
    width: 1.45rem;
    height: 1.45rem;
    border-radius: 50%;
    display: grid;
    place-items: center;
    background: var(--mh-violet, #6D5DF6);
    color: #FFF;
    font-size: .74rem;
    font-weight: 700;
}
.mh-manual-list--checks { list-style: none; padding-left: 0; }
.mh-manual-list--checks li { position: relative; padding-left: 1.6rem; }
.mh-manual-list--checks li::before {
    content: "\2713";
    position: absolute;
    left: .15rem;
    top: 0;
    color: #16A34A;
    font-weight: 700;
}
.mh-manual-list--notes { list-style: none; padding-left: 0; }
.mh-manual-list--notes li { position: relative; padding-left: 1.6rem; }
.mh-manual-list--notes li::before {
    content: "i";
    position: absolute;
    left: .15rem;
    top: .25rem;
    width: 1.05rem;
    height: 1.05rem;
    border-radius: 50%;
    display: grid;
    place-items: center;
    background: var(--mh-violet-soft, #EFEDFF);
    color: var(--mh-violet, #6D5DF6);
    font-size: .7rem;
    font-weight: 700;
    font-style: italic;
}
.mh-manual-arrow { margin: 0 .15rem; color: var(--mh-violet, #6D5DF6); font-weight: 700; }
.mh-manual-steps li strong,
.mh-manual-list li strong { color: var(--mh-ink, #111827); }
.mh-manual-details > summary { font-weight: 600; }
.mh-manual-h { display: flex; align-items: center; gap: .5rem; }
.mh-manual-h::before { content: ""; width: 4px; height: 1rem; border-radius: 2px; background: var(--mh-violet, #6D5DF6); }
.mh-manual-top {
    position: fixed;
    right: 16px;
    bottom: calc(16px + env(safe-area-inset-bottom));
    z-index: 1030;
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    padding: .5rem .85rem;
    border-radius: 999px;
    background: var(--mh-ink, #111827);
    color: #FFF;
    font-size: .85rem;
    font-weight: 600;
    text-decoration: none;
    box-shadow: 0 10px 24px -12px rgba(17, 24, 39, .6);
}
.mh-manual-top:hover, .mh-manual-top:focus { color: #FFF; }
@media (max-width: 991.98px) {
    /* Clear the mobile bottom bar. */
    .mh-manual-top { bottom: calc(76px + env(safe-area-inset-bottom)); }
}
@media (prefers-reduced-motion: reduce) {
    .mh-manual-top { transition: none; }
}
