/* ════════════════════════════════════════════════════════════════════════════════
   OneCRM mobile portal

   A theme of its own, deliberately NOT part of site.css. Every selector here is
   prefixed `mp-` and everything lives inside `.mp-app`, so nothing in this file
   can reach the desk layout and nothing there styles this one by class. The few
   element rules Bootstrap and site.css apply to headings, paragraphs and links
   are reset inside `.mp-app` rather than fought selector by selector.

   Tokens sit on `.mp-app`, not `:root`, so the CRM's `data-theme` switch does
   not reach them: the portal follows the phone's own light/dark preference, or
   whatever the portal's own switch has pinned. Light is the usual answer because
   this gets read in corridors, plant rooms and car parks, where a near-black
   ground is a mirror.
   ════════════════════════════════════════════════════════════════════════════ */

.mp-app {
    /* Ground */
    --mp-ground: #f3f5f8;
    --mp-surface: #ffffff;
    --mp-sunken: #eceff4;
    --mp-line: #e4e8ee;
    --mp-line-soft: #f1f3f7;

    /* Ink — every one of these clears 4.5:1 on the surface above it */
    --mp-ink: #10151c;
    --mp-ink-2: #4b5563;
    --mp-ink-3: #6b7280;
    --mp-ink-faint: #9aa3af;

    /* Brand. The accent darkens from the desk's #0ea5e9 so it can carry text on
       a light ground; the lighter value stays for fills and icons. */
    --mp-accent: #0369a1;
    --mp-accent-fill: #0ea5e9;
    --mp-accent-tint: #e0f2fe;
    --mp-accent-deep: #0c4a6e;
    --mp-on-deep: #a5d8f3;

    /* Status */
    --mp-good: #15803d;
    --mp-good-bg: #dcfce7;
    --mp-warn: #b45309;
    --mp-warn-bg: #fef3c7;
    --mp-warn-line: #fcd34d;
    --mp-bad: #b91c1c;
    --mp-bad-bg: #fee2e2;
    --mp-bad-line: #fca5a5;
    --mp-bad-ink: #7f1d1d;
    --mp-warn-ink: #78350f;
    --mp-violet: #6d28d9;
    --mp-violet-bg: #ede9fe;

    --mp-shadow: 0 1px 2px rgba(16, 21, 28, 0.05);
    --mp-r-sm: 9px;
    --mp-r-md: 13px;
    --mp-r-lg: 16px;

    --mp-bar: 56px;
    --mp-tabs: 64px;

    /* Own the viewport. The portal is an app shell: one fixed frame with its own
       scrolling body, so the page behind it never scrolls underneath. */
    position: fixed;
    inset: 0;
    z-index: 1;

    display: flex;
    flex-direction: column;
    overflow: hidden;

    background: var(--mp-ground);
    color: var(--mp-ink);
    font-family: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
    font-size: 14px;
    line-height: 1.45;
    -webkit-font-smoothing: antialiased;
    -webkit-tap-highlight-color: transparent;
}

/* Dark is driven by an attribute rather than the media query directly, so the
   switch can pin a choice that disagrees with the phone. A pre-paint script in
   index.html resolves 'follow the system' to this attribute before first paint,
   which is what keeps a dark phone from flashing white on load. */
html[data-mp-theme="dark"] .mp-app {
    --mp-ground: #0c0e12;
    --mp-surface: #12151a;
    --mp-sunken: #1a1e24;
    --mp-line: #2a303a;
    --mp-line-soft: #1f242d;

    --mp-ink: #f1f3f5;
    --mp-ink-2: #c3c9d2;
    --mp-ink-3: #9ca3af;
    --mp-ink-faint: #6b7280;

    /* On a dark ground the lighter sky reads better and still passes */
    --mp-accent: #4cc3f7;
    --mp-accent-fill: #0ea5e9;
    --mp-accent-tint: rgba(14, 165, 233, 0.16);
    --mp-accent-deep: #0b3a55;
    --mp-on-deep: #9fd4ee;

    --mp-good: #4ade80;
    --mp-good-bg: rgba(34, 197, 94, 0.16);
    --mp-warn: #fbbf24;
    --mp-warn-bg: rgba(245, 158, 11, 0.16);
    --mp-warn-line: rgba(245, 158, 11, 0.4);
    --mp-bad: #f87171;
    --mp-bad-bg: rgba(239, 68, 68, 0.16);
    --mp-bad-line: rgba(239, 68, 68, 0.42);
    --mp-bad-ink: #fca5a5;
    --mp-warn-ink: #fcd34d;
    --mp-violet: #c4b5fd;
    --mp-violet-bg: rgba(139, 92, 246, 0.18);

    --mp-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
}

/* ── Resets, so the desk stylesheet's element rules do not leak in ── */

/* :where() keeps this at the specificity of `.mp-app` alone, so it outranks the
   element-level rules in site.css and Bootstrap but still loses to any component
   class below. Written as `.mp-app h2` it was (0,1,1) and beat `.mp-section-title`
   at (0,1,0) — which silently flattened every section heading's margin to zero and
   sat the headings directly on top of their cards.

   What it is overriding: site.css styles every heading `color: var(--text-primary)`,
   and Bootstrap uses --bs-heading-color. Both are desk-theme tokens, so without this
   the portal's headings follow the CRM's theme rather than their own. */
.mp-app :where(h1, h2, h3, p, dl, dd, address) {
    margin: 0;
    font-style: normal;
    color: inherit;
}

/* :where() again: written as `.mp-app a` this was (0,1,1) and beat every component
   class at (0,1,0), so a styled link silently ignored its own colour. That is why the
   three <a> quick actions rendered in ink while the one <button> among them took the
   accent from .mp-action and came out blue. */
.mp-app :where(a) {
    color: inherit;
    text-decoration: none;
}

/* Same reason as the rule in site.css: FocusOnNavigate focuses the page heading and
   the browser rings it. Repeated here so the portal does not inherit the fix by
   accident if site.css ever changes. */
.mp-app [tabindex="-1"]:focus {
    outline: none;
}

.mp-app button {
    font-family: inherit;
    cursor: pointer;
}

.mp-app ::-webkit-scrollbar {
    width: 0;
    height: 0;
}

/* Chrome is for tapping, not for selecting. Content — names, numbers, addresses,
   note bodies — stays selectable so it can still be copied. */
.mp-bar,
.mp-tabbar,
.mp-section-title,
.mp-eyebrow,
.mp-field-label,
.mp-card-note,
.mp-letter,
.mp-seg-btn,
.mp-fchip,
.mp-chip {
    -webkit-user-select: none;
    user-select: none;
}

/* ════════════════════════════  Shell  ════════════════════════════ */

.mp-bar {
    flex: none;

    /* With viewport-fit=cover the page paints under the status bar and the notch,
       so the bar carries that inset itself. Putting it here rather than on .mp-app
       means the bar's own background fills the space, instead of leaving a strip of
       the page ground above it. */
    min-height: calc(var(--mp-bar) + env(safe-area-inset-top));
    box-sizing: border-box;
    padding: env(safe-area-inset-top) 6px 0 16px;
    display: flex;
    align-items: center;
    gap: 6px;
    background: var(--mp-surface);
    border-bottom: 1px solid var(--mp-line);
}

/* A second row under the bar — filter chips, a cycle stepper — that scrolls away
   with nothing, because it belongs to the bar rather than the content. */
.mp-bar-stack {
    flex: none;
    background: var(--mp-surface);
    border-bottom: 1px solid var(--mp-line);
}

.mp-bar-stack .mp-bar {
    border-bottom: 0;
}

/* The CRM's own mark. A transparent ring, so it carries on both grounds without
   a plate behind it — the desk sidebar pairs the same file with the wordmark. */
.mp-logo {
    width: 28px;
    height: 28px;
    flex: none;
    object-fit: contain;
}

.mp-bar-name {
    font-size: 16px;
    font-weight: 700;
    letter-spacing: -0.01em;
}

.mp-bar-text {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    line-height: 1.25;
}

.mp-bar-title {
    font-size: 15px;
    font-weight: 700;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mp-bar-sub {
    font-size: 11px;
    font-weight: 600;
    color: var(--mp-ink-3);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mp-spacer {
    margin-left: auto;
}

/* 44px everywhere, including the icon-only controls */
.mp-iconbtn {
    width: 44px;
    height: 44px;
    flex: none;
    border: 0;
    background: transparent;
    border-radius: 12px;
    color: var(--mp-ink-2);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 19px;
}

.mp-iconbtn.is-accent {
    color: var(--mp-accent);
}

.mp-iconbtn:disabled {
    opacity: 0.4;
}

.mp-textbtn {
    height: 36px;
    flex: none;
    padding: 0 13px;
    border: 1px solid var(--mp-line);
    background: var(--mp-surface);
    border-radius: 10px;
    color: var(--mp-ink-2);
    font-size: 13px;
    font-weight: 700;
}

.mp-body {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-y: contain;
}

/* The padded variant: most screens. A list screen wants its rows edge to edge. */
.mp-body.is-padded {
    box-sizing: border-box;
    padding: 14px 16px calc(24px + env(safe-area-inset-bottom));
    display: flex;
    flex-direction: column;
    gap: 13px;
}

/* Cards keep their natural height instead of being shrunk to fit the column.
   Without this a flex child compresses rather than overflowing, so the body's
   scrollHeight equals its clientHeight, the content is clipped, and the screen
   cannot be scrolled at all. */
.mp-body.is-padded > * {
    flex: none;
}

.mp-tabbar {
    flex: none;

    /* The home indicator's swipe zone sits over the bottom of the screen, so the bar
       has to clear it or every tap near a tab fights the gesture. max() keeps a floor
       of 8px on hardware with no indicator, where the inset reports 0 — the tabs
       themselves should not sit flush against the edge either. */
    height: calc(var(--mp-tabs) + max(env(safe-area-inset-bottom), 8px));
    box-sizing: border-box;
    padding: 0 8px max(env(safe-area-inset-bottom), 8px);
    display: flex;
    align-items: stretch;
    background: var(--mp-surface);
    border-top: 1px solid var(--mp-line);
}

.mp-tab {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    color: var(--mp-ink-3);
    font-size: 11px;
    font-weight: 600;
}

.mp-tab i {
    font-size: 19px;
}

.mp-tab.active {
    color: var(--mp-accent);
    font-weight: 700;
}

/* ════════════════════════════  Pieces  ════════════════════════════ */

.mp-eyebrow {
    display: block;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--mp-ink-3);
}

.mp-greeting {
    margin-top: 4px;
    font-size: 23px;
    line-height: 1.2;
    font-weight: 800;
    letter-spacing: -0.02em;
}

.mp-section-title {
    /* More air above than below, so the heading reads as belonging to the card
       underneath rather than floating between two of them. */
    margin: 4px 2px 9px;
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--mp-ink-3);
    display: flex;
    align-items: baseline;
    gap: 8px;
}

.mp-section-title .mp-spacer {
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0;
    text-transform: none;
    color: var(--mp-ink-2);
}

/* A white box: either a card with a header, or a plain container for rows */
.mp-card {
    background: var(--mp-surface);
    border: 1px solid var(--mp-line);
    border-radius: var(--mp-r-lg);
    overflow: hidden;
}

.mp-card-head {
    box-sizing: border-box;
    padding: 13px 14px 0;
    display: flex;
    align-items: center;
    gap: 8px;
}

.mp-card-head.is-ruled {
    padding-bottom: 11px;
}

.mp-card-head i {
    color: var(--mp-accent);
    font-size: 16px;
}

.mp-card-title {
    font-size: 14px;
    font-weight: 700;
}

.mp-card-note {
    margin-left: auto;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--mp-ink-3);
}

.mp-card-pad {
    box-sizing: border-box;
    padding: 12px 14px;
}

/* ── Search field ── */

.mp-searchshell {
    height: 48px;
    box-sizing: border-box;
    padding: 0 6px 0 13px;
    display: flex;
    align-items: center;
    gap: 9px;
    background: var(--mp-ground);
    border: 1px solid var(--mp-line);
    border-radius: var(--mp-r-md);
}

.mp-searchshell i {
    color: var(--mp-ink-3);
    font-size: 17px;
}

.mp-searchshell input {
    flex: 1;
    min-width: 0;
    height: 44px;
    border: 0;
    background: transparent;
    font-family: inherit;

    /* 16px exactly, and not a pixel less: iOS Safari zooms the page in on focus for
       any field below 16px, and that is the only thing that triggers it. Fixing it
       here rather than with user-scalable=no keeps pinch-zoom working for anyone who
       needs it. */
    font-size: 16px;
    color: var(--mp-ink);
    outline: none;
}

.mp-searchclear {
    width: 36px;
    height: 36px;
    flex: none;
    border: 0;
    border-radius: 10px;
    background: var(--mp-line);
    color: var(--mp-ink-2);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
}

/* Search results sitting inside a padded body — the dashboard — still run to the
   edges, so a row looks the same there as it does on the Search tab. */
.mp-inline-results {
    margin: 0 -16px;
}

/* ── KPI tiles ── */

.mp-kpis {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
}

.mp-kpi {
    box-sizing: border-box;
    padding: 13px;
    background: var(--mp-surface);
    border: 1px solid var(--mp-line);
    border-radius: var(--mp-r-md);
    display: flex;
    flex-direction: column;
    gap: 6px;
    color: var(--mp-ink);
}

.mp-kpi-icon {
    width: 30px;
    height: 30px;
    border-radius: var(--mp-r-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 15px;
}

.mp-kpi-value {
    font-size: 24px;
    font-weight: 800;
    letter-spacing: -0.03em;
    line-height: 1;
}

.mp-kpi-label {
    font-size: 12px;
    font-weight: 600;
    color: var(--mp-ink-2);
}

/* ── Segmented control (the duty tabs, and anywhere else two views share a card) ── */

.mp-seg {
    box-sizing: border-box;
    margin: 11px 14px 0;
    padding: 3px;
    display: flex;
    gap: 3px;
    background: var(--mp-ground);
    border-radius: 11px;
}

.mp-seg.is-flush {
    margin: 0 0 12px;
}

.mp-seg-btn {
    flex: 1;
    height: 38px;
    border: 0;
    border-radius: var(--mp-r-sm);
    background: transparent;
    color: var(--mp-ink-2);
    font-size: 13px;
    font-weight: 600;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
}

.mp-seg-btn.active {
    background: var(--mp-surface);
    color: var(--mp-accent);
    font-weight: 700;
    box-shadow: 0 1px 2px rgba(16, 21, 28, 0.12);
}

.mp-seg-count {
    font-size: 11px;
    opacity: 0.75;
}

/* ── Rows: the shape every list on the portal takes ── */

.mp-rows {
    box-sizing: border-box;
    padding: 0 14px 6px;
}

.mp-row {
    min-height: 56px;
    box-sizing: border-box;
    padding: 11px 14px;
    display: flex;
    align-items: center;
    gap: 12px;
    border-bottom: 1px solid var(--mp-line-soft);
    color: var(--mp-ink);
}

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

.mp-row.is-top {
    align-items: flex-start;
}

.mp-rows .mp-row {
    padding-left: 0;
    padding-right: 0;
}

.mp-row-main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.mp-row-title {
    font-size: 15px;
    font-weight: 700;
    line-height: 1.25;
}

.mp-row-title.is-small {
    font-size: 14px;
    font-weight: 600;
}

.mp-row-meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 4px 10px;
    font-size: 12px;
    color: var(--mp-ink-3);
}

.mp-row-meta i {
    font-size: 12px;
    margin-right: 3px;
}

.mp-row-value {
    flex: none;
    max-width: 148px;
    font-size: 12px;
    font-weight: 600;
    color: var(--mp-ink-3);
    text-align: right;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mp-row-amount {
    flex: none;
    text-align: right;
}

.mp-row-amount strong {
    display: block;
    font-size: 15px;
    font-weight: 800;
    letter-spacing: -0.01em;
    font-variant-numeric: tabular-nums;
}

.mp-row-amount span {
    display: block;
    margin-top: 2px;
    font-size: 11px;
    font-weight: 600;
    color: var(--mp-warn);
}

/* Rows in a virtualised list must all be the same height, or the scrollbar drifts
   as you go: Virtualize sizes its spacers from one ItemSize. Clamping the two text
   lines to one line each is what makes that true — and reads tidier besides. */
.mp-row.is-uniform {
    height: 72px;
    align-items: center;
}

.mp-row.is-uniform .mp-row-title {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mp-row.is-uniform .mp-row-meta {
    flex-wrap: nowrap;
    overflow: hidden;
    white-space: nowrap;
}

/* Virtualize measures against the nearest scrolling ancestor. A card clipped with
   overflow:hidden would stand in for the real one and the window would never move. */
.mp-card.is-virtual {
    overflow: visible;
}

.mp-chev {
    flex: none;
    color: var(--mp-ink-faint);
    font-size: 17px;
}

.mp-when {
    flex: none;
    padding: 4px 9px;
    border-radius: 999px;
    background: var(--mp-ground);
    color: var(--mp-ink-2);
    font-size: 11px;
    font-weight: 600;
}

/* Time column on a schedule row */
.mp-slot {
    width: 46px;
    flex: none;
    text-align: center;
}

.mp-slot strong {
    display: block;
    font-size: 13px;
    font-weight: 800;
    color: var(--mp-accent);
}

.mp-slot.is-pm strong {
    color: var(--mp-warn);
}

.mp-slot span {
    display: block;
    font-size: 10px;
    font-weight: 600;
    color: var(--mp-ink-3);
}

/* ── Avatars ── */

.mp-avatar {
    width: 42px;
    height: 42px;
    flex: none;
    border-radius: var(--mp-r-md);
    display: flex;
    align-items: center;
    justify-content: center;
    /* Site codes run to five characters, so the type is sized for the longest
       rather than the typical three. */
    padding: 0 3px;
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 0;
    text-transform: uppercase;
    background: var(--mp-accent-tint);
    color: var(--mp-accent);
    overflow: hidden;
}

.mp-avatar.is-round {
    border-radius: 50%;
}

.mp-avatar.is-sm {
    width: 36px;
    height: 36px;
    font-size: 11px;
}

.mp-avatar.is-xs {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    font-size: 10px;
}

.mp-avatar.is-lg {
    width: 54px;
    height: 54px;
    border-radius: var(--mp-r-lg);
    font-size: 15px;
}

/* The padding above exists to fit a long site code. A photo has no such problem and
   must reach the edge, so it is dropped where the tile holds an image — otherwise the
   portrait sits 3px short on each side and the tint shows around it. */
.mp-avatar:has(img) {
    padding: 0;
}

.mp-avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Customer-type colours. Their own scale, picked to pass on both grounds rather
   than reusing the desk's type-* classes. */
.mp-t-education { background: var(--mp-accent-tint); color: var(--mp-accent); }
.mp-t-business { background: var(--mp-warn-bg); color: var(--mp-warn); }
.mp-t-academytrust { background: var(--mp-violet-bg); color: var(--mp-violet); }
.mp-t-localauthority { background: var(--mp-good-bg); color: var(--mp-good); }
.mp-t-charity { background: var(--mp-bad-bg); color: var(--mp-bad); }
.mp-t-government { background: var(--mp-sunken); color: var(--mp-ink-2); }
.mp-t-default { background: var(--mp-sunken); color: var(--mp-ink-2); }

/* ── Chips & badges ── */

.mp-chip {
    padding: 3px 9px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 700;
    white-space: nowrap;
}

.mp-chip.is-plain { background: var(--mp-ground); color: var(--mp-ink-2); }
.mp-chip.is-good { background: var(--mp-good-bg); color: var(--mp-good); }
.mp-chip.is-warn { background: var(--mp-warn-bg); color: var(--mp-warn); }
.mp-chip.is-bad { background: var(--mp-bad-bg); color: var(--mp-bad); }
.mp-chip.is-accent { background: var(--mp-accent-tint); color: var(--mp-accent); }
.mp-chip.is-violet { background: var(--mp-violet-bg); color: var(--mp-violet); }

.mp-code {
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 11px;
    font-weight: 600;
    color: var(--mp-ink-2);
}

.mp-dot {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 11px;
    font-weight: 600;
    color: var(--mp-good);
}

.mp-dot::before {
    content: '';
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
}

.mp-dot.is-off {
    color: var(--mp-ink-3);
}

/* ── Filter chip scroller ── */

.mp-chips {
    box-sizing: border-box;
    padding: 0 16px 12px;
    display: flex;
    gap: 7px;
    overflow-x: auto;
}

.mp-fchip {
    flex: none;
    height: 36px;
    padding: 0 14px;
    border: 1px solid var(--mp-line);
    background: var(--mp-surface);
    border-radius: 999px;
    color: var(--mp-ink-2);
    font-size: 13px;
    font-weight: 600;
    white-space: nowrap;
}

.mp-fchip.active {
    background: var(--mp-accent);
    border-color: var(--mp-accent);
    color: #ffffff;
    font-weight: 700;
}

html[data-mp-theme="dark"] .mp-fchip.active {
    color: #04121b;
}

/* ── Alerts. Never collapsed: on site they are the reason someone looked. ── */

.mp-alert {
    box-sizing: border-box;
    padding: 12px 13px;
    border-radius: 14px;
    display: flex;
    align-items: flex-start;
    gap: 10px;
    font-size: 13px;
    line-height: 1.45;
    font-weight: 600;
}

.mp-alert i {
    flex: none;
    margin-top: 1px;
    font-size: 16px;
}

.mp-alert.is-bad {
    background: var(--mp-bad-bg);
    border: 1px solid var(--mp-bad-line);
    color: var(--mp-bad-ink);
}

.mp-alert.is-warn {
    background: var(--mp-warn-bg);
    border: 1px solid var(--mp-warn-line);
    color: var(--mp-warn-ink);
}

.mp-alert span {
    white-space: pre-wrap;
}

/* ── Quick actions ── */

.mp-actions {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 8px;
}

.mp-action {
    min-height: 68px;
    box-sizing: border-box;
    padding: 9px 4px;
    background: var(--mp-surface);
    border: 1px solid var(--mp-line);
    border-radius: 14px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 5px;
    color: var(--mp-ink);
    font-size: 11px;
    font-weight: 700;
    text-align: center;
}

.mp-action i {
    color: var(--mp-ink-2);
}

.mp-action i {
    font-size: 18px;
}

.mp-action.is-off {
    color: var(--mp-ink-faint);
}

/* ── Collapsible group ── */

.mp-acc-head {
    width: 100%;
    min-height: 52px;
    box-sizing: border-box;
    margin-bottom: 9px;
    padding: 0 14px;
    display: flex;
    align-items: center;
    gap: 11px;
    background: var(--mp-surface);
    border: 1px solid var(--mp-line);
    border-radius: var(--mp-r-md);
    font-family: inherit;
    color: var(--mp-ink);
    text-align: left;
}

.mp-acc-head.is-empty {
    background: transparent;
    border-style: dashed;
    color: var(--mp-ink-3);
}

.mp-acc-head > i:first-child {
    flex: none;
    font-size: 17px;
    color: var(--mp-accent);
}

.mp-acc-head.is-empty > i:first-child {
    color: var(--mp-ink-faint);
}

.mp-acc-title {
    flex: 1;
    min-width: 0;
    font-size: 14px;
    font-weight: 700;
}

.mp-acc-count {
    flex: none;
    padding: 2px 9px;
    border-radius: 999px;
    background: var(--mp-ground);
    font-size: 11px;
    font-weight: 700;
    color: var(--mp-ink-2);
}

.mp-acc-head.is-empty .mp-acc-count {
    background: transparent;
    color: var(--mp-ink-faint);
}

.mp-acc-chev {
    flex: none;
    font-size: 15px;
    color: var(--mp-ink-faint);
    transition: transform var(--transition-fast, 150ms) ease;
}

.mp-acc-chev.is-open {
    transform: rotate(180deg);
}

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

.mp-acc-body {
    margin-bottom: 4px;
}

/* ── Action sheet ──
   Sits inside .mp-app, which is a stacking context of its own, so these z-indexes
   are local to the portal: toasts and the session overlay live outside it and still
   come out on top. */

.mp-sheet-backdrop {
    position: fixed;
    inset: 0;
    z-index: 40;
    background: rgba(8, 11, 16, 0.45);
}

.mp-sheet {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 41;
    box-sizing: border-box;
    padding: 6px 12px calc(12px + max(env(safe-area-inset-bottom), 8px));
    background: var(--mp-surface);
    border-top-left-radius: 20px;
    border-top-right-radius: 20px;
    box-shadow: 0 -8px 30px rgba(8, 11, 16, 0.28);
    animation: mp-sheet-in 160ms ease-out;
}

@keyframes mp-sheet-in {
    from { transform: translateY(16px); opacity: 0; }
    to { transform: none; opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .mp-sheet { animation: none; }
}

.mp-sheet-head {
    padding: 12px 10px 10px;
    text-align: center;
}

.mp-sheet-title {
    display: block;
    font-size: 12px;
    font-weight: 800;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--mp-ink-3);
}

.mp-sheet-sub {
    display: block;
    margin-top: 4px;
    font-size: 13px;
    font-weight: 600;
    color: var(--mp-ink-2);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mp-sheet-item {
    min-height: 56px;
    box-sizing: border-box;
    padding: 0 10px;
    display: flex;
    align-items: center;
    gap: 14px;
    border-radius: 12px;
    font-size: 16px;
    font-weight: 600;
    color: var(--mp-ink);
}

.mp-sheet-item i {
    width: 24px;
    flex: none;
    font-size: 20px;
    text-align: center;
    color: var(--mp-accent);
}

.mp-sheet-cancel {
    width: 100%;
    min-height: 52px;
    margin-top: 8px;
    border: 0;
    border-radius: 12px;
    background: var(--mp-ground);
    color: var(--mp-accent);
    font-family: inherit;
    font-size: 16px;
    font-weight: 700;
}

/* The quick-action tile as a real <button>, for the ones that open a sheet. */
button.mp-action {
    width: 100%;
    font-family: inherit;
}

/* ── The deep panel: one answer, stated once ── */

.mp-hero {
    box-sizing: border-box;
    padding: 14px;
    background: var(--mp-accent-deep);
    border-radius: var(--mp-r-lg);
    display: flex;
    align-items: center;
    gap: 12px;
}

.mp-hero-icon {
    width: 40px;
    height: 40px;
    flex: none;
    border-radius: 12px;
    background: rgba(255, 255, 255, 0.14);
    color: #ffffff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 18px;
}

.mp-hero-text {
    flex: 1;
    min-width: 0;
}

.mp-hero-label {
    display: block;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--mp-on-deep);
}

.mp-hero-value {
    display: block;
    margin-top: 2px;
    font-size: 15px;
    font-weight: 700;
    color: #ffffff;
}

.mp-hero-big {
    display: block;
    margin-top: 5px;
    font-size: 32px;
    font-weight: 800;
    letter-spacing: -0.03em;
    line-height: 1;
    color: #ffffff;
}

.mp-hero-chips {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 12px;
}

.mp-hero-chips span {
    padding: 4px 10px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.14);
    color: #ffffff;
    font-size: 11px;
    font-weight: 700;
}

/* ── Label / value fields, in place of the desk's definition lists ── */

.mp-field {
    min-height: 60px;
    box-sizing: border-box;
    padding: 11px 14px;
    display: flex;
    align-items: center;
    gap: 12px;
    border-bottom: 1px solid var(--mp-line-soft);
    color: var(--mp-ink);
}

.mp-field:last-child {
    border-bottom: 0;
}

.mp-field-main {
    flex: 1;
    min-width: 0;
}

.mp-field-label {
    display: block;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--mp-ink-3);
}

.mp-field-value {
    display: block;
    margin-top: 2px;
    font-size: 15px;
    font-weight: 600;
    overflow-wrap: anywhere;
}

.mp-field-value.is-link {
    color: var(--mp-accent);
    font-weight: 700;
}

.mp-field-value.is-mono {
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-weight: 700;
}

.mp-field-value.is-muted {
    color: var(--mp-ink-faint);
    font-weight: 500;
}

/* A compact inline pair — label left, value right — where the value is short */
.mp-field.is-inline {
    min-height: 54px;
}

.mp-field.is-inline .mp-field-main {
    font-size: 14px;
    font-weight: 600;
    color: var(--mp-ink-2);
}

.mp-field-right {
    flex: none;
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 14px;
    font-weight: 700;
    text-align: right;
}

/* Two short facts sharing a row: the only place the portal leaves one column */
.mp-pair {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    border-bottom: 1px solid var(--mp-line-soft);
}

.mp-pair:last-child {
    border-bottom: 0;
}

.mp-pair > div {
    box-sizing: border-box;
    padding: 12px 14px;
}

.mp-pair > div:first-child {
    border-right: 1px solid var(--mp-line-soft);
}

.mp-act-strip {
    min-height: 52px;
    box-sizing: border-box;
    padding: 12px 14px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    border-top: 1px solid var(--mp-line-soft);
    background: var(--mp-ground);
    font-size: 14px;
    font-weight: 700;
    color: var(--mp-accent);
}

/* The same strip as a real <button>, for the actions that are not links. */
button.mp-act-strip {
    width: 100%;
    border: 0;
    border-top: 1px solid var(--mp-line-soft);
    font-family: inherit;
}

.mp-postcode {
    display: inline-block;
    margin-top: 8px;
    padding: 4px 10px;
    border-radius: 8px;
    background: var(--mp-ground);
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.04em;
}

.mp-body-text {
    font-size: 14px;
    line-height: 1.6;
    color: var(--mp-ink-2);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* ── Alphabet headers on the customer list ── */

.mp-letter {
    box-sizing: border-box;
    padding: 7px 16px;
    background: var(--mp-sunken);
    border-top: 1px solid var(--mp-line);
    border-bottom: 1px solid var(--mp-line);
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 0.1em;
    color: var(--mp-ink-2);
    position: sticky;
    top: 0;
    z-index: 1;
}

.mp-listrow {
    box-sizing: border-box;
    padding: 11px 16px;
    min-height: 68px;
    display: flex;
    align-items: center;
    gap: 12px;
    background: var(--mp-surface);
    border-bottom: 1px solid var(--mp-line-soft);
    color: var(--mp-ink);
}

.mp-tick {
    width: 24px;
    height: 24px;
    flex: none;
    border-radius: 50%;
    background: var(--mp-good-bg);
    color: var(--mp-good);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
}

/* ── States ── */

.mp-empty {
    box-sizing: border-box;
    padding: 44px 32px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    text-align: center;
}

.mp-empty i {
    font-size: 28px;
    color: var(--mp-ink-faint);
}

.mp-empty strong {
    font-size: 14px;
    font-weight: 700;
    color: var(--mp-ink-2);
}

.mp-empty span {
    font-size: 13px;
    line-height: 1.5;
    color: var(--mp-ink-3);
}

.mp-quiet {
    font-size: 13px;
    color: var(--mp-ink-3);
    padding: 4px 0;
}

.mp-footnote {
    font-size: 12px;
    line-height: 1.55;
    color: var(--mp-ink-3);
    text-align: center;
    padding: 6px 0 2px;
}

.mp-loading {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    color: var(--mp-ink-3);
    font-size: 13px;
}

.mp-spinner {
    width: 26px;
    height: 26px;
    border: 2.5px solid var(--mp-line);
    border-top-color: var(--mp-accent);
    border-radius: 50%;
    animation: mp-spin 700ms linear infinite;
}

@keyframes mp-spin {
    to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
    .mp-spinner { animation-duration: 2s; }
}

/* The read-only notice, restated in the portal's own voice. Off the SD-WAN is the
   normal case for a phone, so this is information rather than a warning. */
.mp-readonly {
    box-sizing: border-box;
    padding: 10px 13px;
    display: flex;
    align-items: center;
    gap: 9px;
    background: var(--mp-sunken);
    border: 1px solid var(--mp-line);
    border-radius: 12px;
    font-size: 12px;
    line-height: 1.45;
    color: var(--mp-ink-2);
}

.mp-readonly i {
    flex: none;
    font-size: 14px;
    color: var(--mp-ink-3);
}

/* ═══════════════════════════  Deliveries  ═══════════════════════════

   The one part of the portal that writes. Controls are deliberately larger than
   the rest of the app: this screen is used standing up, one-handed, often in a
   corridor, by someone holding a box.                                        */

/* A single full-width action rather than one tile in a grid of four. */
.mp-action.is-wide {
    width: 100%;
    min-height: 46px;
    flex-direction: row;
    gap: 8px;
    font-size: 14px;
}

.mp-action.is-wide i {
    font-size: 17px;
}

/* Quantity, leading a delivery line. Tabular so a column of them lines up. */
.mp-qty {
    flex: none;
    min-width: 30px;
    padding: 3px 6px;
    border-radius: 8px;
    background: var(--mp-sunken);
    color: var(--mp-ink-2);
    font-size: 13px;
    font-weight: 750;
    font-variant-numeric: tabular-nums;
    text-align: center;
}

.mp-label {
    display: block;
    margin: 12px 0 5px;
    color: var(--mp-ink-3);
    font-size: 11px;
    font-weight: 750;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

/* 16px is not a style choice: below it, iOS zooms the page when the field takes
   focus and leaves the layout half off-screen. */
.mp-input {
    box-sizing: border-box;
    width: 100%;
    height: 46px;
    padding: 0 13px;
    border: 1px solid var(--mp-line);
    border-radius: var(--mp-r-sm);
    background: var(--mp-surface);
    color: var(--mp-ink);
    font-family: inherit;
    font-size: 16px;
}

.mp-input.is-area {
    height: auto;
    padding: 11px 13px;
    line-height: 1.45;
    resize: vertical;
}

.mp-input:focus {
    outline: none;
    border-color: var(--mp-accent-fill);
}

/* The file input itself never shows — its <label> is the button. Hidden by
   clipping rather than display:none, which would stop the label reaching it. */
.mp-file {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.mp-bigbtn {
    box-sizing: border-box;
    width: 100%;
    min-height: 52px;
    margin-top: 10px;
    padding: 0 16px;
    border: 0;
    border-radius: var(--mp-r-md);
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 9px;
    background: var(--mp-accent);
    color: #fff;
    font-family: inherit;
    font-size: 15px;
    font-weight: 700;
}

.mp-bigbtn i {
    font-size: 18px;
}

/* The photo button is a <label> wrapping a hidden file input, so it does not get
   the pointer cursor that .mp-app button gets. */
label.mp-bigbtn {
    cursor: pointer;
}

.mp-bigbtn.is-quiet {
    border: 1px solid var(--mp-line);
    background: var(--mp-surface);
    color: var(--mp-ink);
}

.mp-bigbtn.is-go {
    background: var(--mp-good);
}

.mp-bigbtn.is-bad {
    background: var(--mp-bad);
}

/* Disabled says "not yet", not "broken": the confirm button sits greyed until
   there is evidence to send, which is the whole point of the screen. */
.mp-bigbtn:disabled {
    opacity: 0.45;
    cursor: default;
}

.mp-textbtn.is-block {
    width: 100%;
    height: 44px;
    margin-top: 12px;
    border: 0;
    background: transparent;
    color: var(--mp-ink-3);
}

/* ── Signature pad ──
   Always white, in both themes. This is not decoration: the canvas is the image
   that ends up in the PDF, and a pale stroke on a dark pad prints as a black box. */

.mp-sigpad {
    margin-top: 10px;
    border: 1px solid var(--mp-line);
    border-radius: var(--mp-r-md);
    overflow: hidden;
    background: #fff;
}

.mp-sigpad-canvas {
    display: block;
    width: 100%;
    height: 180px;
    background: #fff;

    /* Without this the browser treats a drawing gesture as a scroll and the
       signature comes out as a single dot. */
    touch-action: none;
}

.mp-sigpad-foot {
    display: flex;
    align-items: center;
    padding: 7px 11px;
    border-top: 1px solid var(--mp-line-soft);
    background: var(--mp-surface);
}

.mp-sigpad-hint {
    flex: 1;
    color: var(--mp-ink-3);
    font-size: 12px;
}

.mp-sigpad-clear {
    border: 0;
    background: transparent;
    color: var(--mp-accent);
    font-family: inherit;
    font-size: 13px;
    font-weight: 700;
}

/* Signature or site photo, shown back after the event. */
.mp-evidence {
    display: block;
    width: 100%;
    margin-top: 11px;
    border: 1px solid var(--mp-line);
    border-radius: var(--mp-r-sm);
    background: #fff;
}

.mp-problem {
    margin-top: 11px;
    padding: 9px 11px;
    border-radius: var(--mp-r-sm);
    background: var(--mp-bad-bg);
    color: var(--mp-bad);
    font-size: 13px;
    font-weight: 600;
}

.mp-card.is-bad-edge {
    border-left: 3px solid var(--mp-bad);
}

.mp-spinner.is-small {
    width: 17px;
    height: 17px;
    border-width: 2px;
    border-top-color: currentColor;
}
