/* PRJ-006: Mobile Interactions Engine */
/* All rules gated on body.mobile-mode — zero effect on desktop */

/* Body locking for when drawers or zoom states are active */
body.mobile-mode.mobile-interaction-active {
    touch-action: pan-y;
}

/* ----------------------------------------------------------------------
   PANEL 1: Dashboard Hero Area
   ---------------------------------------------------------------------- */
@media (max-width: 767.98px) {
    .mobile-dashboard-hero {
        position: relative;
        z-index: 10;
        margin-bottom: 1rem;
        transition: transform 0.3s ease;
    }
}

/* ----------------------------------------------------------------------
   PANEL 2: Bottom-Sliding Input Drawers (Header, etc)
   ---------------------------------------------------------------------- */
body.mobile-mode .mobile-drawer-target {
    position: fixed;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 85vh;
    background: #ffffff;
    z-index: 1050;
    transform: translateY(110%);
    transition: transform 0.35s cubic-bezier(0.25, 1, 0.5, 1);
    border-top-left-radius: 20px;
    border-top-right-radius: 20px;
    box-shadow: 0 -10px 40px rgba(0, 0, 0, 0.15);
    overflow-y: auto;
}

body.mobile-mode .mobile-drawer-target.drawer-open {
    transform: translateY(0);
}

body.mobile-mode .drawer-header {
    position: sticky;
    top: 0;
    z-index: 1060;
    border-top-left-radius: 20px;
    border-top-right-radius: 20px;
}

/* ----------------------------------------------------------------------
   PREMIUM INPUTS: Bronze Script & Gold Pinstripes
   ---------------------------------------------------------------------- */
@media (max-width: 767.98px) {
    .mobile-input-premium {
        border: none !important;
        border-bottom: 2px solid rgba(176, 141, 87, 0.3) !important;
        border-radius: 0 !important;
        padding-left: 0;
        padding-right: 0;
        background-color: transparent !important;
        font-family: inherit;
        transition: border-color 0.2s;
    }

    .mobile-input-premium:focus {
        box-shadow: none !important;
        border-bottom-color: #0f1c2d !important;
    }

    .bronze-script::placeholder {
        color: #b08d57;
        font-style: italic;
        font-family: 'Georgia', serif;
        opacity: 0.8;
    }
}

/* ----------------------------------------------------------------------
   PANEL 3: Nested Contexts (The Zoom Effect)
   ---------------------------------------------------------------------- */
@media (max-width: 767.98px) {
    .mobile-line-card {
        background: #ffffff;
        border-radius: 12px;
        box-shadow: 0 2px 10px rgba(0, 0, 0, 0.03);
        margin-bottom: 1rem;
        padding: 1.2rem;
        display: block !important;
        border-left: 4px solid #0f1c2d;
        transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
        cursor: pointer;
    }

    .mobile-line-card td {
        display: block;
        border: none;
        padding: 0.2rem 0;
    }

    .mobile-line-card td:first-child {
        font-weight: bold;
        color: #6c757d;
        font-size: 0.85rem;
    }

    .mobile-line-card td:nth-child(2) {
        font-size: 1.1rem;
        margin-bottom: 0.5rem;
    }

    .mobile-line-card td:nth-child(3):before {
        content: 'Qty: ';
        color: #6c757d;
        font-size: 0.85rem;
    }

    .mobile-line-card td:nth-child(4):before {
        content: 'Price: ';
        color: #6c757d;
        font-size: 0.85rem;
    }

    .mobile-line-card td:last-child {
        font-size: 1.2rem;
        font-weight: 700;
        color: #0f1c2d;
        text-align: left !important;
        margin-top: 0.5rem;
        border-top: 1px dashed #e9ecef;
        padding-top: 0.5rem;
    }

    .mobile-line-card td:last-child:before {
        content: 'Total: ';
        color: #6c757d;
        font-size: 0.85rem;
        font-weight: normal;
    }

    /* P12: Transaction edit — mobile table override
   Disables the Level 3 Shield (min-width, fixed layout, thead) on mobile
   where desktop rows are hidden and only card rows render. */
    #lines-table {
        min-width: 0 !important;
        table-layout: auto !important;
        border-collapse: collapse !important;
    }

    #lines-table thead {
        display: none !important;
    }

    #lines-table td {
        background-color: transparent !important;
        padding: 0 !important;
        border: none !important;
    }

    #lines-table tr.d-md-none {
        display: table-row !important;
    }

    /* P12: Transaction edit line item cards */
    .mobile-line-item-card {
        background: #f8f9fa !important;
        border-radius: 10px;
        border-left: 4px solid #0f1c2d;
        border-bottom: none !important;
        box-shadow: 0 1px 6px rgba(0, 0, 0, 0.08);
        margin: 0.5rem 0;
        overflow: hidden;
        position: relative;


    }

    .mobile-line-item-card .mobile-card-inner {
        background: #f8f9fa !important;
        padding-top: 0.5em !important;
        padding-left: 0.5em !important;
    }

    .mobile-line-item-card .mobile-card-inner>div {
        background: #f8f9fa;
    }

    .mobile-line-item-card:active {
        transform: scale(0.98);
    }

    /* Unified cents treatment for ALL mobile money displays (sticky strip,
       line totals, total card): 0.8 × the whole-number size, aligned top.
       Each cents span's 0.8em must resolve against the same base as its
       sibling whole-number span — containers set that base (see
       .mobile-line-total below). Colour/opacity stay per-context via the
       modifier classes that follow. Mobile-only (this media query): the
       total card's split spans render unstyled/full-size on desktop. */
    .mobile-money-cents {
        font-family: 'Roboto Mono', monospace;
        font-weight: 600;
        font-size: 0.8em;
        vertical-align: top;
    }

    /* PRJ-031 B3: light-card line total (dark-strip equivalent is
       .mobile-doc-strip-money-* further down). The wrapper sets the em base
       for .mobile-money-cents; the whole span inherits it. */
    .mobile-line-total {
        font-size: 0.9rem;
    }

    .mobile-line-total-whole {
        font-family: 'Roboto Mono', monospace;
        font-weight: 700;
        color: #1a1a1a;
    }

    .mobile-line-total-cents {
        opacity: 0.65;
        color: #1a1a1a;
    }

    /* Bottom total card (Total Amount Due) */
    .amount-large-cents {
        opacity: 0.85;
    }

    /* Bugfix (post-B4): #add-line-form (master_editor()) only carries col-md-*
   classes — desktop-oriented, since its only reachable home used to be the
   wide "+ Add Line" collapse panel. Below 768px, Bootstrap applies none of
   those column widths (they're gated inside a min-width:768px media query),
   so each field renders at native/intrinsic width with nothing to wrap or
   stack it — the .row ends up far wider than the viewport, and everything
   past the first field is pushed off-screen to the right. Force every column
   to stack full-width on mobile, in both its original "+ Add Line" location
   and the new PRJ-031 post-B4 line-tap-to-edit slot. */
    #add-line-form .row>[class*="col-"] {
        flex: 0 0 100%;
        max-width: 100%;
        /* Flex items default to min-width:auto, so a wide <select> (long item
       codes/descriptions) can still force this column past its 100% basis
       and blow out the row — min-width:0 lets it actually shrink/wrap. */
        min-width: 0;
    }

    #add-line-form select,
    #add-line-form input,
    #add-line-form textarea {
        max-width: 100%;
    }

    /* Same failure class as the col-* stacking fix above, one level deeper:
       the calculation preview (#line-summary-block) is an unwrapped desktop
       flex row (gap-5 / gap-4 / border-end pe-5) — on mobile it must wrap and
       drop the desktop-only divider/right-alignment. */
    #add-line-form #line-summary-block .card-body {
        flex-wrap: wrap;
        justify-content: flex-start;
        gap: 0.75rem !important; /* overrides gap-5 */
    }

    #add-line-form #line-summary-block .card-body > .border-end {
        border-right: none !important;
        padding-right: 0 !important;
        flex-wrap: wrap;
        gap: 0.5rem 1rem !important; /* overrides gap-4 */
    }

    #add-line-form #line-summary-block .d-flex.flex-column {
        min-width: 0; /* neutralize inline min-width:150px pull */
        align-items: flex-start !important;
    }

    /* Bugfix (post-B4): .mobile-card-inner is a shared display:flex row (see the
   P18 swipe-actions rule further down) — .mobile-line-edit-slot sits as a
   direct sibling of the summary content div inside it, so without wrapping it
   was laid out as a second flex item in the SAME row instead of stacking
   below, and flex items default to min-width:auto (won't shrink below their
   widest descendant), so the edit form pushed the whole row far past the
   viewport. Scoped to line-item cards only — .mobile-card-inner is reused
   elsewhere (list_view.html, _ledger_macros.html) where this doesn't apply. */
    .mobile-line-item-card .mobile-card-inner {
        flex-wrap: wrap;
    }

    .mobile-line-edit-slot {
        flex: 1 1 100%;
        width: 100%;
        min-width: 0;
    }

    /* When editing a line on mobile, the sticky Save Line/Cancel footer
   (.zoom-action-footer .footer-line-actions) is the single source of truth
   for committing/discarding the edit — the form's own embedded submit/cancel
   controls stay functional (the footer buttons trigger them via .click())
   but must not also be visible, or the card shows two competing action rows.
   Scoped to the mobile edit slot only — untouched in the form's other homes
   (desktop, and the mobile "+ Add Line" collapse panel). */
    .mobile-line-edit-slot .line-form-actions-col {
        display: none;
    }

    /* PRJ-031: mobile Add Line uses the zoom popup exclusively — hide the desktop
   concertina panel below 768px (its trigger is already d-none d-md-flex). This
   also neutralizes the zero-lines case where Jinja's show_editor auto-opens it. */
    #addLineForm {
        display: none !important;
    }

    /* Mobile "+ Add line" row — audit doc §3: left-aligned plain text-link, gold,
   no pill/border, its own row with a top divider. */
    .mobile-add-line-card {
        background: #ffffff !important;
        border-left: none;
        box-shadow: none;
        border-top: 1px solid rgba(0, 0, 0, 0.06);
        border-radius: 0;
        margin: 0;
    }

    .mobile-add-line-label {
        padding: 12px 16px;
        color: #b08d57;
        font-weight: 600;
        font-size: 0.85rem;
        font-family: 'Inter', sans-serif;
    }

    .mobile-add-line-label i {
        margin-right: 4px;
    }

    /* Document-pricing banner at the top of the add/edit popups. Deliberately
   muted + labelled "Document pricing": the toggle is document-level state,
   not per-line — flipping it re-interprets every line's entered price. */
    .mobile-pricing-strip {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 8px;
        padding: 10px 14px;
        background: #eef0f2;
        border-bottom: 1px solid rgba(0, 0, 0, 0.08);
    }

    .mobile-pricing-strip.d-none {
        display: none;
    }

    .mobile-pricing-strip-label {
        font-size: 0.7rem;
        text-transform: uppercase;
        letter-spacing: 0.06em;
        font-weight: 700;
        color: #6c757d;
        white-space: nowrap;
    }

    /* The relocated .v-tax-toggle-wrapper carries its own "Pricing Mode:" label,
   redundant next to the strip's DOCUMENT PRICING label — hide it here only. */
    .mobile-pricing-strip .v-tax-toggle-wrapper>span {
        display: none;
    }
}

/* ----------------------------------------------------------------------
   UNIFIED STICKY PORTAL (Single Compact Strip)
   ---------------------------------------------------------------------- */
@media (max-width: 767.98px) {
    .mobile-sticky-portal {
        /* PRJ-006: clears the fixed #mobileTopBar (52px, z-index:1099 in modern_sidebar.css).
       Without this the portal sticks at the same y as the top bar and gets hidden behind it
       (top bar has the higher z-index). If this value changes, update the coupled offset on
       .v-sticky-header-bar-wrapper.sticky-top in modern_sidebar.css to match. */
        top: 52px;
        z-index: 2000;
        background: transparent;
    }

    .mobile-doc-strip {
        transition: all 0.3s ease;
        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
        cursor: pointer;
    }

    .mobile-doc-strip:active {
        opacity: 0.85;
    }

    /* PRJ-031 B1: entity-name-primary / cents-superscript / plain-text status treatment */
    .mobile-doc-strip-entity {
        font-weight: 700;
        color: #fff;
        font-size: 0.95rem;
        font-family: 'Merriweather', serif;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        min-width: 0;
    }

    .mobile-doc-strip-money-whole {
        font-family: 'Roboto Mono', monospace;
        font-weight: 700;
        font-size: 1rem;
        color: var(--color-gold);
    }

    .mobile-doc-strip-money-cents {
        /* Size/alignment come from the shared .mobile-money-cents class */
        opacity: 0.85;
        color: var(--color-gold);
    }

    .mobile-doc-strip-status {
        text-transform: lowercase;
        color: rgba(255, 255, 255, 0.55);
        font-size: 0.75rem;
    }
}

/* Luxury Gold Button (State-Aware) */
body.mobile-mode .header-edit-trigger {
    background: #b08d57 !important;
    color: #fff !important;
    border: none !important;
    font-weight: 700;
    letter-spacing: 2px;
    text-transform: uppercase;
    transition: all 0.3s;
    box-shadow: 0 4px 15px rgba(176, 141, 87, 0.3);
}

/* Zoom Context Recession */
body.mobile-mode #mobile-orchestrator-root.zoomed-context .mobile-section-card:not(.active-zoomed),
body.mobile-mode #lineItemsContainer.zoomed-context .mobile-line-item-card:not(.active-zoomed) {
    transform: scale(0.92) !important;
    opacity: 0.1 !important;
    filter: blur(8px) !important;
    pointer-events: none;
}

/* PRJ-031 Phase A: a .mobile-section-card that itself wraps independently-zoomable
   children (e.g. a line-items outer card wrapping .mobile-line-card rows) would
   otherwise get recessed by the rule above even while one of its own children is
   the thing being zoomed — CSS filters apply to the whole subtree regardless of
   the child's own computed style. Cancel recession for that case.
   PRJ-031 B3: the line-items container (#lineItemsContainer) is itself a
   .mobile-section-card AND receives the 'zoomed-context' class directly on itself
   (mobileOrchestrator.focusLine() targets the container, not a descendant) — so
   :has(.zoomed-context) alone misses it; without the self-matching clause below,
   the container (and everything under it, via pointer-events inheritance) gets
   recessed and the zoomed row becomes unclickable after the first tap. */
body.mobile-mode #mobile-orchestrator-root.zoomed-context .mobile-section-card:has(.zoomed-context),
body.mobile-mode #mobile-orchestrator-root.zoomed-context .mobile-section-card.zoomed-context {
    transform: none !important;
    opacity: 1 !important;
    filter: none !important;
    pointer-events: auto !important;
}

/* Lower sticky headers when zoomed so the zoomed card can stay on top */
body.mobile-mode #mobile-orchestrator-root.zoomed-context .mobile-sticky-portal {
    z-index: 5 !important;
    opacity: 0.1 !important;
    filter: blur(12px) !important;
    pointer-events: none;
}

/* Unlocks scroll for in-place zoom, but lock-intent is kept for drawer modules */
body.mobile-mode.mobile-interaction-active:not(.drawer-context) {
    overflow: visible !important;
}

@media (max-width: 767.98px) {

    .mobile-section-card,
    .mobile-line-item-card {
        transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
        /* PRJ-031 Phase A: mobileOrchestrator.focusHeader()'s scrollIntoView({block:'start'})
       aligns this card's top with viewport y=0, but the fixed #mobileTopBar (52px) plus
       the sticky portal (~75px, see .mobile-sticky-portal above) permanently cover that
       space — without this the card ends up scrolled partly behind them. */
        scroll-margin-top: 132px;
    }

    /* PRJ-031 B2: replaces the Bootstrap `collapse` accordion for the Details/Addresses
   and Message/Terms cards — body is hidden until the card is zoomed. Scoped to this
   media query only, so desktop's `d-md-block` (Bootstrap utility, !important, ≥768px)
   is untouched. */
    .mobile-section-card .mobile-section-body {
        display: none;
    }

    .mobile-section-card.active-zoomed .mobile-section-body {
        display: block;
    }

    .mobile-section-card.active-zoomed .mobile-toggle-icon {
        transform: rotate(90deg);
    }

    /* Bugfix (post-B4): .active-zoomed applies a `transform` to the card
   (scale/translateY below), which breaks `position: sticky` on descendants —
   sticky is computed against the pre-transform layout box but painted through
   the transform, so as the page scrolls the header and the receded background
   behind it fall out of sync and bleed through each other. Once zoomed, the
   header should scroll with the rest of the card instead of staying pinned. */
    .mobile-section-card.active-zoomed .v-sticky-header-bar-wrapper {
        position: static !important;
        top: auto !important;
    }
}

/* Zoom State - Active Card (VICTORY LAYER) */
body.mobile-mode .mobile-section-card.active-zoomed,
body.mobile-mode .mobile-line-item-card.active-zoomed {
    transform: scale(1.05) translateY(-5px) !important;
    box-shadow: 0 40px 100px rgba(0, 0, 0, 0.45) !important;
    z-index: 5000 !important;
    position: relative;
    border-radius: 15px !important;
    border-left: 6px solid #b08d57 !important;
    background: #ffffff !important;
    opacity: 1 !important;
    filter: none !important;
}

body.mobile-mode .active-zoomed .header-edit-fields {
    display: block !important;
}

body.mobile-mode .active-zoomed .header-edit-trigger {
    display: none !important;
}

/* Support scrolling past the bottom when zoomed */
body.mobile-mode #mobile-orchestrator-root.zoomed-context {
    padding-bottom: 400px !important;
}

/* ----------------------------------------------------------------------
   STICKY FOOTER (Main vs Zoom)
   ---------------------------------------------------------------------- */
@media (max-width: 767.98px) {
    .v-sticky-footer-mobile {
        position: fixed;
        bottom: 0;
        left: 0;
        width: 100%;
        z-index: 1040;
        transition: transform 0.3s ease;
    }
}

body.mobile-mode #mobile-orchestrator-root.zoomed-context~.v-sticky-footer-mobile {
    transform: translateY(100%);
    pointer-events: none;
}

body.mobile-mode .zoom-action-footer {
    position: fixed;
    bottom: 0;
    left: 0;
    width: 100%;
    z-index: 6000;
    background: #ffffff;
    border-top: 1px solid rgba(176, 141, 87, 0.2);
    padding: 1rem;
    box-shadow: 0 -10px 30px rgba(0, 0, 0, 0.1);
    display: none;
}

body.mobile-mode.zoom-mode-active .zoom-action-footer {
    display: block !important;
    z-index: 9999 !important;
}

/* PRJ-031 post-B4: line-scoped Save Line/Cancel pair replaces the header's
   FINALIZE CHANGES button while a line row is zoomed for editing. Header-zoom
   never carries .line-zoom-mode, so it keeps the single-button layout unchanged. */
.zoom-action-footer .footer-line-actions {
    display: none;
}

body.line-zoom-mode .zoom-action-footer .footer-btn-finalize {
    display: none;
}

body.line-zoom-mode .zoom-action-footer .footer-line-actions {
    display: flex;
}

/* ----------------------------------------------------------------------
   SATISFACTION HAPTICS (Odometer Roll)
   ---------------------------------------------------------------------- */
@keyframes odometerRollUp {
    0% {
        transform: translateY(15px);
        opacity: 0;
    }

    100% {
        transform: translateY(0);
        opacity: 1;
    }
}

body.mobile-mode .odometer-rolling {
    display: inline-block;
    animation: odometerRollUp 0.35s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards;
}

/* ──────────────────────────────────────────────────────────────────────────
   DASHBOARD — Mobile Layout (PRJ-006)
   ────────────────────────────────────────────────────────────────────────── */

body.mobile-mode .briefing-header {
    margin-top: 0;
}

body.mobile-mode .briefing-header h1 {
    font-size: 1.4rem;
}

/* KPI Cards — 2-column grid; last card spans full width */
body.mobile-mode .metrics-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 12px;
}

body.mobile-mode .metrics-grid .metric-card:last-child {
    grid-column: 1 / -1;
}

body.mobile-mode .metric-value {
    font-size: 1.4rem;
}

body.mobile-mode .metric-title {
    font-size: 0.72rem;
}

/* Action Centre — 44px min touch target */
body.mobile-mode .btn-approve {
    min-height: 44px;
    padding: 10px 14px;
    white-space: nowrap;
}

body.mobile-mode .drawer-table {
    font-size: 0.78rem;
}

body.mobile-mode .drawer-table td {
    padding: 4px 6px;
}

/* Quick Actions — full-width stacked */
body.mobile-mode .quick-actions-bar .d-flex {
    flex-direction: column;
    align-items: stretch;
}

body.mobile-mode .quick-actions-bar .btn {
    width: 100%;
    padding: 12px;
    font-size: 1rem;
}

/* Charts — stack vertically */
body.mobile-mode .dashboard-split {
    grid-template-columns: 1fr;
    gap: 16px;
}

/* Takealot hover popup — no hover on mobile */
body.mobile-mode .takealot-popup {
    display: none !important;
}

/* ===== Phase 4: List View Card Stack =====
   Scoped to .ledger-container ancestor to avoid hiding takealot/index.html tables
   which use .ledger-table without a .ledger-container ancestor.
   Note: table is nested .ledger-container > .table-responsive > .ledger-table,
   so descendant combinator (not >) is required. */
/* table/card swap already in @media block below — body.mobile-mode kept as progressive enhancement */
body.mobile-mode .ledger-container .ledger-table {
    display: none !important;
}

body.mobile-mode .mobile-list-card {
    display: flex !important;
}

.mobile-list-card {
    display: none;
    align-items: stretch;
    background: #fff;
    border-bottom: 1px solid rgba(0, 0, 0, 0.06);
    cursor: pointer;
    transition: background 0.15s;
    text-decoration: none;
    color: inherit;
}

.mobile-list-card:active {
    background: rgba(212, 176, 104, 0.08);
}

.mobile-card-accent {
    width: 4px;
    flex-shrink: 0;
}

.mobile-card-body {
    flex: 1;
    padding: 12px 14px;
    min-width: 0;
}

.mobile-card-docno {
    font-size: 0.85rem;
    color: #2C3539;
    white-space: nowrap;
}

.mobile-card-entity {
    font-size: 0.78rem;
    margin-top: 2px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* PRJ-026 Phase 8.8: name-first hierarchy for ledger_row()'s mobile card
   (invoices/quotes/bills/orders/returns). Separate classes from
   .mobile-card-docno/.mobile-card-entity above — those stay as-is for
   linear_item_row() (Customers/Suppliers/Inventory/etc.), which keeps the
   original doc-number-first hierarchy per user decision (2026-08-15). */
.mobile-card-entity-primary {
    font-size: 0.85rem;
    color: #2C3539;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mobile-card-docno-secondary {
    font-size: 0.78rem;
    color: #6C757D;
    margin-top: 2px;
    white-space: nowrap;
}

.mobile-card-amount {
    font-family: 'Roboto Mono', monospace;
    font-size: 0.9rem;
    color: #2C3539;
    white-space: nowrap;
}

/* ===== PRJ-024 Phase 1: Cashbook Mobile ===== */

/* Hide desktop table on mobile; cashbook cards take over */
body.mobile-mode #cashbookTable {
    display: none !important;
}

body.mobile-mode .mobile-cashbook-card {
    display: flex !important;
}

/* ── Cashbook Card ── */
.mobile-cashbook-card {
    display: none;
    position: relative;
    background: #fff;
    border-bottom: 1px solid rgba(0, 0, 0, 0.07);
    cursor: pointer;
    user-select: none;
    -webkit-user-select: none;
    transition: background 0.12s;
    overflow: hidden;
}

.mobile-cashbook-card:active {
    background: rgba(212, 175, 55, 0.07);
}

.mcb-accent {
    width: 4px;
    flex-shrink: 0;
    background: var(--color-gold, #D4B068);
}

.mcb-accent.reconciled {
    background: #10B981;
}

.mcb-accent.unallocated {
    background: #ccc;
}

.mcb-body {
    flex: 1;
    padding: 12px 14px;
    min-width: 0;
}

.mcb-row1 {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 8px;
    margin-bottom: 2px;
}

.mcb-type {
    font-size: 0.78rem;
    font-weight: 600;
    color: #2C3539;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    flex: 1;
}

.mcb-date {
    font-size: 0.75rem;
    color: #6c757d;
    white-space: nowrap;
    flex-shrink: 0;
}

.mcb-entity {
    font-size: 0.85rem;
    font-weight: 500;
    color: #2C3539;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    margin-bottom: 1px;
}

.mcb-desc {
    font-size: 0.75rem;
    color: #6c757d;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mcb-row3 {
    display: flex;
    justify-content: flex-end;
    margin-top: 4px;
}

.mcb-amount {
    font-family: 'Roboto Mono', monospace;
    font-size: 0.95rem;
    font-weight: 700;
}

/* Status icon area (lock / pencil / duplicate) */
.mcb-status-icons {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 0 10px 0 6px;
    gap: 4px;
    color: #6c757d;
    font-size: 0.85rem;
    flex-shrink: 0;
}

.mcb-status-icons .reconciled-icon {
    color: #10B981;
}

.mcb-status-icons .dup-icon {
    color: var(--color-gold, #D4B068);
}

/* ── Selection Mode ── */
.mobile-selection-mode .mobile-cashbook-card {
    cursor: default;
}

.mobile-card-checkbox {
    display: none;
    position: absolute;
    left: 14px;
    top: 50%;
    transform: translateY(-50%);
    width: 20px;
    height: 20px;
    cursor: pointer;
    z-index: 2;
    accent-color: var(--color-gold, #D4B068);
}

.mobile-selection-mode .mobile-card-checkbox {
    display: block;
}

.mobile-selection-mode .mcb-accent {
    opacity: 0;
}

.mobile-selection-mode .mcb-body {
    padding-left: 42px;
}

#mobileSelectionToolbar {
    display: none;
    position: fixed;
    bottom: 70px;
    left: 0;
    right: 0;
    z-index: 1060;
    background: #2C3539;
    color: #fff;
    padding: 10px 16px;
    gap: 10px;
    align-items: center;
    justify-content: space-between;
}

#mobileSelectionToolbar.visible {
    display: flex;
}

/* ── Sticky Context Bar ── */
#mobileCashbookBar {
    position: sticky;
    top: 0;
    z-index: 1020;
    background: #2C3539;
    color: #fff;
    padding: 12px 16px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    transition: padding 0.2s, font-size 0.2s;
    border-bottom: 2px solid var(--color-gold, #D4B068);
}

#mobileCashbookBar.collapsed {
    padding: 8px 16px;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
}

#mobileCashbookBar .bar-account-name {
    font-size: 1rem;
    font-weight: 700;
    color: var(--color-gold, #D4B068);
}

#mobileCashbookBar.collapsed .bar-account-name {
    font-size: 0.85rem;
}

#mobileCashbookBar .bar-subtitle {
    font-size: 0.75rem;
    color: rgba(255, 255, 255, 0.7);
}

#mobileCashbookBar.collapsed .bar-subtitle {
    display: none;
}

#mobileCashbookBar .bar-total {
    font-family: 'Roboto Mono', monospace;
    font-size: 0.9rem;
    color: #fff;
}

/* ── Bottom Sheet ── */
.mobile-sheet-backdrop {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.45);
    z-index: 1070;
}

.mobile-sheet-backdrop.visible {
    display: block;
}

.mobile-bottom-sheet {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    background: #fff;
    border-radius: 16px 16px 0 0;
    box-shadow: 0 -4px 24px rgba(0, 0, 0, 0.18);
    z-index: 1080;
    max-height: 92vh;
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    transform: translateY(100%);
    transition: transform 0.3s cubic-bezier(0.32, 0.72, 0, 1);
}

.mobile-bottom-sheet.open {
    transform: translateY(0);
}

.mobile-bottom-sheet.stacked {
    z-index: 1090;
    max-height: 88vh;
}

.mobile-sheet-handle {
    width: 36px;
    height: 4px;
    background: #ddd;
    border-radius: 2px;
    margin: 12px auto 0;
}

.mobile-sheet-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 16px 8px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.08);
}

.mobile-sheet-title {
    font-size: 0.8rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: #2C3539;
}

.mobile-sheet-body {
    padding: 16px;
}

.mobile-sheet-label {
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: #6c757d;
    margin-bottom: 4px;
}

.mobile-sheet-input {
    width: 100%;
    padding: 12px;
    font-size: 1rem;
    border: 1px solid #dee2e6;
    border-radius: 8px;
    background: #fafafa;
    margin-bottom: 12px;
    color: #2C3539;
    -webkit-appearance: none;
}

.mobile-sheet-input:focus {
    outline: none;
    border-color: var(--color-gold, #D4B068);
    box-shadow: 0 0 0 2px rgba(212, 175, 55, 0.15);
    background: #fff;
}

.mobile-sheet-input:disabled {
    background: #f5f5f5;
    color: #aaa;
}

.mobile-amount-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
    margin-bottom: 12px;
}

.mobile-drawer-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    width: 100%;
    padding: 14px;
    border-radius: 8px;
    font-size: 0.9rem;
    font-weight: 600;
    border: none;
    cursor: pointer;
    margin-bottom: 10px;
}

.mobile-drawer-btn-match {
    background: rgba(212, 175, 55, 0.1);
    color: #2C3539;
    border: 1px solid rgba(212, 175, 55, 0.4);
}

.mobile-drawer-btn-delete {
    background: rgba(166, 44, 43, 0.08);
    color: #A62C2B;
    border: 1px solid rgba(166, 44, 43, 0.2);
}

.mobile-drawer-btn-save {
    background: var(--color-gold, #D4B068);
    color: #2C3539;
    font-size: 1rem;
    font-weight: 700;
    padding: 16px;
    margin-top: 6px;
    margin-bottom: 0;
}

.mobile-drawer-btn-save:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

/* ── Sticky Footer (Post & Reconcile) ── */
#mobileCashbookFooter {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 1050;
    padding: 10px 16px;
    background: #fff;
    border-top: 1px solid rgba(0, 0, 0, 0.1);
    box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.08);
}

/* Hide desktop cashbook chrome on mobile — wrapped in .cashbook-desktop-chrome by the template */
body.mobile-mode .cashbook-desktop-chrome {
    display: none !important;
}

/* Hide the list.header() page title on the cashbook page — context bar replaces it */
body.mobile-mode .v-crm-header-top {
    display: none !important;
}

/* ── Mobile Filter Panel ── */
#mobileCashbookFilters {
    background: #2C3539;
    padding: 0 16px;
    overflow: hidden;
    max-height: 0;
    transition: max-height 0.3s ease, padding 0.3s ease;
}

#mobileCashbookFilters.open {
    max-height: 300px;
    padding: 12px 16px 16px;
}

.mobile-filter-label {
    font-size: 0.68rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: rgba(255, 255, 255, 0.55);
    margin-bottom: 4px;
}

.mobile-filter-select {
    width: 100%;
    padding: 10px 12px;
    font-size: 0.9rem;
    border: 1px solid rgba(212, 175, 55, 0.35);
    border-radius: 8px;
    background: #1e2a2f;
    color: #fff;
    margin-bottom: 10px;
    -webkit-appearance: none;
}

.mobile-filter-select option {
    background: #1e2a2f;
    color: #fff;
}

.mobile-filter-view-toggle {
    display: flex;
    border-radius: 8px;
    overflow: hidden;
    border: 1px solid rgba(212, 175, 55, 0.35);
    margin-bottom: 12px;
}

.mobile-filter-view-btn {
    flex: 1;
    padding: 10px;
    background: transparent;
    color: rgba(255, 255, 255, 0.6);
    border: none;
    font-size: 0.82rem;
    font-weight: 600;
    cursor: pointer;
    text-decoration: none;
    text-align: center;
}

.mobile-filter-view-btn.active {
    background: var(--color-gold, #D4B068);
    color: #2C3539;
}

/* ── FAB (Add Transaction) ── */
#mobileCashbookFab {
    position: fixed;
    bottom: 80px;
    right: 16px;
    z-index: 1055;
    width: 52px;
    height: 52px;
    border-radius: 50%;
    background: var(--color-gold, #D4B068);
    color: #2C3539;
    border: none;
    font-size: 1.4rem;
    font-weight: 700;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: transform 0.15s, box-shadow 0.15s;
}

#mobileCashbookFab:active {
    transform: scale(0.92);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}

/* Shift FAB up when selection toolbar is visible */
#mobileSelectionToolbar.visible~* #mobileCashbookFab {
    bottom: 140px;
}

/* ── Mobile Empty State ── */
.mobile-empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 48px 24px;
    text-align: center;
    color: rgba(255, 255, 255, 0.45);
}

.mobile-empty-icon {
    font-size: 2.8rem;
    margin-bottom: 12px;
    color: var(--color-gold, #D4B068);
    opacity: 0.5;
}

.mobile-empty-title {
    font-size: 1rem;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.7);
    margin-bottom: 6px;
}

.mobile-empty-hint {
    font-size: 0.82rem;
    color: rgba(255, 255, 255, 0.4);
    line-height: 1.5;
}

@media (max-width: 767.98px) {
    .ledger-card {
        padding: 0 !important;
        box-shadow: none !important;
        border-radius: 0 !important;
        background: transparent !important;
    }

    .ledger-card .table-responsive {
        max-height: none !important;
    }
}

.mobile-card-status .v-badge-glass {
    font-size: 0.55rem;
}

/* ===== PRJ-025: Mobile Action Sheet =====
   Bottom sheet for document workflow actions (Post, PDF, Email, etc.)
   Reuses .mobile-sheet-handle from cashbook bottom sheet pattern. */

.mobile-action-sheet-backdrop {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.45);
    z-index: 1070;
}

.mobile-action-sheet-backdrop.visible {
    display: block;
}

.mobile-action-sheet {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    background: #fff;
    border-radius: 16px 16px 0 0;
    box-shadow: 0 -4px 24px rgba(0, 0, 0, 0.18);
    z-index: 1080;
    max-height: 85vh;
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    transform: translateY(100%);
    transition: transform 0.3s cubic-bezier(0.32, 0.72, 0, 1);
    padding-bottom: env(safe-area-inset-bottom, 0);
}

.mobile-action-sheet.open {
    transform: translateY(0);
}

.mobile-action-sheet-list {
    padding: 8px 0;
}

.mobile-action-sheet-row {
    display: flex;
    align-items: center;
    gap: 14px;
    width: 100%;
    padding: 16px 20px;
    background: none;
    border: none;
    border-bottom: 1px solid rgba(0, 0, 0, 0.05);
    font-size: 1rem;
    color: #2C3539;
    cursor: pointer;
    text-align: left;
    min-height: 52px;
}

.mobile-action-sheet-row:active {
    background: rgba(212, 175, 55, 0.08);
}

.mobile-action-sheet-row:last-child {
    border-bottom: none;
}

.mobile-action-sheet-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: 8px;
    background: rgba(44, 53, 57, 0.06);
    color: #2C3539;
    font-size: 1.1rem;
    flex-shrink: 0;
}

.mobile-action-sheet-label {
    font-weight: 600;
    flex: 1;
}

.mobile-action-sheet-desc {
    font-size: 0.78rem;
    color: #6c757d;
    margin-left: auto;
    flex-shrink: 0;
}

.mobile-action-sheet-separator {
    height: 1px;
    background: rgba(166, 44, 43, 0.15);
    margin: 4px 20px;
}

.mobile-action-sheet-danger .mobile-action-sheet-icon {
    background: rgba(166, 44, 43, 0.08);
    color: #A62C2B;
}

.mobile-action-sheet-danger .mobile-action-sheet-label {
    color: #A62C2B;
}

.mobile-action-sheet-cancel {
    padding: 8px 16px 16px;
    border-top: 1px solid rgba(0, 0, 0, 0.08);
}

.mobile-action-sheet-cancel-btn {
    display: block;
    width: 100%;
    padding: 14px;
    background: rgba(44, 53, 57, 0.06);
    border: none;
    border-radius: 12px;
    font-size: 1rem;
    font-weight: 600;
    color: #2C3539;
    cursor: pointer;
    min-height: 48px;
}

.mobile-action-sheet-cancel-btn:active {
    background: rgba(44, 53, 57, 0.12);
}

/* ── Mobile Action Bar: floating pill row (PRJ-031 B4) ──
   Ported from templates/dev/mobile_card_stack_mockup.html's .csm-action-bar.
   Post/dominant action (btn-viljoen-gold) fills most of the row; the
   secondary action (btn-platinum) is a small outlined icon+label pill;
   "more" is a small circular icon button. All 7 document types' mobile
   action bars use exactly this two-button shape (one gold, one platinum),
   confirmed against every *_edit.html route file, so this is a CSS-only
   port — no macro/template changes needed. */
@media (max-width: 767.98px) {
    .mobile-action-bar {
        position: fixed;
        left: 16px;
        right: 16px;
        bottom: calc(16px + env(safe-area-inset-bottom, 0));
        z-index: 1040;
        background: #fff;
        border-top: none;
        border-radius: 30px;
        padding: 8px;
        box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
        display: flex;
        align-items: center;
        gap: 8px;
    }

    .mobile-action-bar .mobile-action-primary {
        min-height: 44px;
        font-size: 0.85rem;
        font-weight: 600;
        border-radius: 24px;
        border: none;
        cursor: pointer;
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 6px;
    }

    /* Dominant action (Post/PDF/Convert — whichever route marks it gold) */
    .mobile-action-bar .mobile-action-primary.btn-viljoen-gold {
        flex-grow: 1;
        padding: 12px 16px;
        font-weight: 700;
        font-size: 0.9rem;
    }

    /* Secondary action (Save/Email/PDF — whichever route marks it platinum) */
    .mobile-action-bar .mobile-action-primary.btn-platinum {
        flex-grow: 0;
        flex-shrink: 0;
        padding: 10px 16px;
        border: 1px solid #dee2e6 !important;
        background: #fff !important;
        color: #2C3539 !important;
    }

    .mobile-action-bar .mobile-action-more {
        width: 44px;
        height: 44px;
        border-radius: 50%;
        background: #fff;
        border: 1px solid #dee2e6;
        color: #2C3539;
        font-size: 1.1rem;
        cursor: pointer;
        display: flex;
        align-items: center;
        justify-content: center;
        flex-shrink: 0;
    }

    .mobile-action-bar .mobile-action-more:active {
        background: rgba(44, 53, 57, 0.06);
    }
}

/* Hide action bar when zoom mode is active — FINALIZE footer takes over */
body.mobile-mode.zoom-mode-active .mobile-action-bar {
    display: none;
}

/* ===== PRJ-025 Phase 3: Mobile Selection Mode =====
   Long-press to select, tap to toggle, bottom toolbar for bulk actions. */

.mobile-select-checkbox {
    display: none;
    position: absolute;
    top: 8px;
    left: 8px;
    width: 22px;
    height: 22px;
    z-index: 2;
    accent-color: var(--color-gold, #D4B068);
}

.mobile-selection-mode .mobile-select-checkbox {
    display: block;
}

.mobile-selection-mode .mobile-list-card {
    padding-left: 36px !important;
    position: relative;
    user-select: none;
    -webkit-user-select: none;
    -webkit-touch-callout: none;
}

.mobile-card-selected {
    background: rgba(212, 175, 55, 0.08) !important;
    border-left: 4px solid var(--color-gold, #D4B068) !important;
}

/* Selection toolbar — fixed bottom bar */
.mobile-selection-toolbar {
    display: none;
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 1060;
    background: #2C3539;
    color: #fff;
    padding: 12px 16px;
    padding-bottom: calc(12px + env(safe-area-inset-bottom, 0));
    align-items: center;
    justify-content: space-between;
    box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.25);
}

.mobile-selection-toolbar.visible {
    display: flex;
}

.mobile-selection-toolbar .mobile-selection-count {
    font-size: 0.85rem;
    font-weight: 600;
}

.mobile-selection-toolbar .mobile-selection-actions {
    display: flex;
    gap: 8px;
    align-items: center;
}

.mobile-selection-toolbar .mobile-selection-btn {
    padding: 8px 14px;
    border-radius: 6px;
    border: none;
    font-size: 0.8rem;
    font-weight: 600;
    cursor: pointer;
    min-height: 40px;
}

.mobile-selection-toolbar .mobile-selection-btn-primary {
    background: var(--color-gold, #D4B068);
    color: #2C3539;
}

.mobile-selection-toolbar .mobile-selection-btn-danger {
    background: rgba(166, 44, 43, 0.15);
    color: #ff6b6b;
}

.mobile-selection-toolbar .mobile-selection-btn-cancel {
    background: rgba(255, 255, 255, 0.1);
    color: #fff;
}

/* FAB — Create button for list pages */
.mobile-list-fab {
    display: none;
    position: fixed;
    bottom: 24px;
    right: 16px;
    z-index: 1055;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    background: var(--color-gold, #D4B068);
    color: #2C3539;
    border: none;
    font-size: 1.5rem;
    font-weight: 700;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
    cursor: pointer;
    align-items: center;
    justify-content: center;
    transition: transform 0.15s, box-shadow 0.15s;
}

@media (max-width: 767.98px) {
    .mobile-list-fab {
        display: flex;
    }
}

.mobile-list-fab:active {
    transform: scale(0.92);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}

/* Shift FAB up when selection toolbar visible */
.mobile-selection-toolbar.visible~.mobile-list-fab {
    bottom: 80px;
}

/* ===== PRJ-025 P9: Recent Picks Strip ===== */
.recent-picks-strip {
    margin-bottom: 8px;
    padding: 0 2px;
}

.recent-picks-label {
    display: block;
    font-size: 0.65rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: #6c757d;
    margin-bottom: 4px;
}

.recent-picks-chips {
    display: flex;
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    gap: 6px;
}

.recent-pick-chip {
    display: inline-flex;
    align-items: center;
    padding: 8px 12px;
    border-radius: 16px;
    border: 1px solid var(--color-gold, #D4B068);
    background: rgba(212, 176, 104, 0.08);
    color: #2C3539;
    font-size: 0.78rem;
    font-weight: 500;
    cursor: pointer;
    white-space: nowrap;
    flex-shrink: 0;
    min-height: 44px;
    transition: background 0.15s;
}

.recent-pick-chip:active {
    background: rgba(212, 176, 104, 0.2);
}

/* ===== PRJ-025: Mobile Section Collapse Toggle =====
   Chevron rotation + compact section headers for collapsible detail areas. */
@media (max-width: 767.98px) {
    .mobile-section-toggle {
        font-size: 0.85rem;
        font-weight: 600;
        letter-spacing: 0.5px;
        color: #2C3539;
        text-transform: uppercase;
    }

    .mobile-toggle-icon {
        transition: transform 0.2s ease;
        display: inline-block;
    }

    .mobile-section-toggle[aria-expanded="true"] .mobile-toggle-icon {
        transform: rotate(90deg);
    }
}

/* ===== PRJ-025 P10: Compact List Page Headers on Mobile =====
   Hide the desktop header block (title + bulk actions) — context is clear from nav.
   Create button moves to FAB or stays as a smaller element. */
@media (max-width: 767.98px) {
    .v-crm-header-top {
        padding: 8px 0 4px !important;
        flex-wrap: wrap;
        gap: 8px;
    }

    .v-crm-header-top .v-crm-title {
        font-size: 1.1rem !important;
        margin-bottom: 0;
    }

    .v-crm-header-top .v-actions-group {
        flex-wrap: wrap;
        gap: 6px;
    }

    .v-crm-header-top .v-header-extra {
        font-size: 0.78rem;
    }

    .v-crm-header-top .v-btn-crm {
        font-size: 0.78rem;
        padding: 6px 12px;
    }
}

/* ===== PRJ-025 P11: Scrollable Filter/Status Strips =====
   Prevent horizontal overflow on status toggle groups and search composites. */
@media (max-width: 767.98px) {
    .status-toggle-group {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        flex-shrink: 0;
        margin-left: 0 !important;
        border-left: none !important;
        padding-bottom: 2px;
        max-width: 100vw;
        flex-wrap: nowrap;
    }

    .ledger-search-bar,
    .v-crm-search-composite {
        flex-wrap: wrap;
    }

    .ledger-search-bar .search-input-group {
        flex: 1 1 100%;
        margin-bottom: 6px;
    }

    .ledger-search-bar .status-toggle-group {
        flex: 1 1 100%;
        justify-content: flex-start;
        gap: 6px;
    }

    /* PRJ-026 Phase 8.1: pill-shaped filter chips (style guide §9.5) — shape/colour
       only, reuses the scroll behaviour already set on .status-toggle-group above.
       Selector doubled (.status-toggle-group .status-btn) for specificity: the
       macro's own unconditional (non-media-queried) .status-btn rule in
       _ledger_macros.html's inline <style> block renders later in <head> source
       order than this external stylesheet, so a same-specificity bare .status-btn
       rule here would lose the cascade at every viewport width, not just desktop. */
    .status-toggle-group .status-btn {
        font-size: 0.74rem;
        padding: 8px 18px;
        white-space: nowrap;
        flex-shrink: 0;
        min-height: 34px;
        border-radius: 999px;
        border: 1px solid var(--v-border, #C4C4C4);
        color: var(--v-text-grey, #6C757D);
    }

    .status-toggle-group .status-btn.active {
        border-color: var(--v-charcoal, #2C3539);
    }
}

/* ===== PRJ-025 P12: Prevent table text overflow on mobile =====
   Fallback for any table that isn't replaced by cards. */
@media (max-width: 767.98px) {

    .table th,
    .table td {
        font-size: 0.75rem;
        padding: 4px 3px;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        max-width: 80px;
    }
}

/* ===== PRJ-025: CSS-only table/card swap fallback =====
   Media query backup — doesn't depend on body.mobile-mode JS loading.
   Ensures cards show and table hides even before MobileOrchestrator runs. */
@media (max-width: 767.98px) {
    .ledger-container .ledger-table {
        display: none !important;
    }

    .mobile-list-card {
        display: flex !important;
    }
}

/* ===== PRJ-025: Global mobile overflow prevention =====
   Ensure nothing bleeds past the viewport on mobile. */
@media (max-width: 767.98px) {
    main {
        /* PRJ-006: overflow-x:hidden forces overflow-y:auto per spec, which breaks
       position:sticky for every descendant. overflow-x:clip clips the same way
       without that side-effect. See modern_sidebar.css:69 for prior art. */
        overflow-x: clip;
        max-width: 100vw;
    }

    /* PRJ-026 Phase 8.7: .v-crm-sticky-top defaults to top:0/z-index:1020
       (list_views.css), which sticks it BEHIND the fixed #mobileTopBar (52px,
       z-index:1099, modern_sidebar.css) — the same clearance problem already
       documented and solved for .mobile-sticky-portal above. Only became visible
       once mobile_context_heading() moved inside this wrapper (8.7); the search
       bar alone didn't show the overlap as clearly. */
    .v-crm-sticky-top {
        max-width: 100vw;
        overflow-x: hidden;
        top: 52px;
        z-index: 1098;
    }

    .ledger-container {
        max-width: 100vw;
        overflow-x: hidden;
        padding: 0 8px;
    }

    /* Pagination: compact on mobile */
    .v-pagination {
        flex-wrap: wrap;
        gap: 4px;
        justify-content: center;
    }

    .v-pagination .page-link {
        padding: 6px 10px;
        font-size: 0.75rem;
    }

    /* Per-page selector: compact */
    .v-per-page,
    .ledger-per-page {
        font-size: 0.75rem;
    }

    .v-per-page select,
    .ledger-per-page select {
        padding: 4px 6px;
        font-size: 0.75rem;
    }

    /* PRJ-026 Phase 8.6: Refine collapses to an icon inside the search field on
       mobile instead of wrapping to its own full-width row below the chips.
       .ledger-refine-btn-mobile is a SEPARATE button rendered inside
       .search-input-group in the macro markup (not the desktop .ledger-refine-btn
       repositioned) — sibling-absolute-positioning was tried first and rejected
       because .search-unit-container can also render .ledger-title-unit
       (takealot/staging.html passes title= into ledger_search()), which breaks any
       CSS assuming the search bar is always the first wrapped row. Two buttons,
       one drawer: both carry data-refine-toggle, so the existing global
       click-delegation handler in ledger_scripts() needs no change. The desktop
       .ledger-refine-btn is d-none d-md-flex; this one is d-md-none — exactly one
       is visible at any viewport width. */
    .search-input-group {
        position: relative;
    }

    .search-unit-container .search-bar-wrapper .search-input-group input {
        padding-right: 36px;
    }

    .ledger-refine-btn-mobile {
        position: absolute;
        top: 50%;
        right: 4px;
        transform: translateY(-50%);
        z-index: 2;
        background: transparent !important;
        border: none !important;
        padding: 6px;
        display: flex;
        align-items: center;
        justify-content: center;
    }

    .ledger-refine-btn-mobile i {
        font-size: 1.05rem;
        color: var(--v-text-grey, #6C757D);
    }

    .ledger-refine-btn-mobile.active i {
        color: var(--v-charcoal, #2C3539);
    }

    /* Search bar and filter area — stack vertically on mobile */
    .search-unit-container {
        flex-wrap: wrap !important;
        gap: 8px !important;
        padding: 10px 8px !important;
    }

    .search-unit-container .ledger-title-unit {
        flex: 1 1 100%;
        margin-right: 0 !important;
    }

    /* PRJ-026 Phase 8.6: widen the search+chips box to use the full row now that
       the desktop Refine button no longer sits beside it taking up space. */
    .search-unit-container .search-bar-wrapper {
        flex: 1 1 100%;
        width: 100%;
        min-width: 0;
        flex-wrap: wrap !important;
    }

    .search-unit-container .search-bar-wrapper .search-input-group {
        flex: 1 1 100%;
        margin-bottom: 8px;
    }
}

@media (max-width: 767.98px) {
    .search-bar-wrapper {
        flex-wrap: wrap !important;
    }

    .search-bar-wrapper .search-input-group {
        flex: 1 1 100% !important;
        margin-bottom: 6px;
    }

    .search-bar-wrapper .status-toggle-group {
        flex: 1 1 100% !important;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        padding-bottom: 4px;
    }
}

@media (max-width: 767.98px) {
    .search-unit-container .ledger-refine-btn {
        margin-left: 0 !important;
        flex-shrink: 0;
    }

    .ledger-control-row {
        max-width: 100%;
        overflow: hidden;
    }

    /* Refine drawer — full-width single-column on mobile */
    .refine-drawer {
        max-width: 100%;
        overflow-x: hidden;
        padding: 12px 8px;
    }

    .refine-drawer .refine-content {
        display: flex !important;
        flex-direction: column !important;
        gap: 10px;
    }

    .refine-drawer .grid-layout {
        grid-template-columns: 1fr !important;
    }

    .refine-drawer .refine-field {
        width: 100%;
    }

    .refine-drawer .refine-field label {
        font-size: 0.75rem;
    }

    .refine-drawer input,
    .refine-drawer select {
        width: 100%;
        font-size: 0.85rem;
    }

    .refine-drawer .apply-btn {
        width: 100%;
        min-height: 44px;
    }
}

/* Prevent ANY horizontal scroll on mobile */
@media (max-width: 767.98px) {

    html,
    body {
        /* PRJ-006: overflow-x:hidden forces overflow-y:auto per spec, breaking
           position:sticky app-wide on mobile. overflow-x:clip avoids that side-effect. */
        overflow-x: clip;
        max-width: 100vw;
    }
}

/* ===== PRJ-025 P13: Force sidebar closed on mobile =====
   CSS safety net — even if JS hasn't run yet, sidebar stays hidden. */
body.mobile-mode #sidebarMenu.pinned {
    transform: translateX(-100%) !important;
}

body.mobile-mode #sidebarMenu.pinned.show {
    transform: translateX(0) !important;
}

/* Portal must sit BELOW sidebar (sidebar z:2000) so menu covers it */
body.mobile-mode .mobile-sticky-portal {
    z-index: 1050 !important;
}

/* When sidebar is open (.show), hide the portal entirely to prevent bleed-through */
body.mobile-mode #sidebarMenu.show~main .mobile-sticky-portal,
body.mobile-mode #sidebarMenu.show~.mobile-sticky-portal {
    display: none !important;
}

/* ===== PRJ-023: Mobile Navigation — Full-Screen Accordion Drawer =====
   All rules gated on body.mobile-mode — zero desktop impact.
   Desktop hover-flyout (main.css .sidebar .v-submenu) is completely untouched.
   The click-accordion is powered by the existing .submenu-open toggle in main.js. */

/* Sidebar fills full viewport width on mobile */
body.mobile-mode #sidebarMenu {
    width: 100vw !important;
    overflow-y: auto;
    overflow-x: hidden;
}

/* 48px minimum touch targets on all nav links */
body.mobile-mode #sidebarMenu .nav-link {
    min-height: 48px !important;
    display: flex !important;
    align-items: center !important;
}

/* Convert the fixed-position flyout to a static inline block.
   positionSubmenu() in main.js sets inline top/left — they are ignored on position:static. */
body.mobile-mode .sidebar .v-submenu {
    position: static !important;
    left: auto !important;
    top: auto !important;
    display: none !important;
    width: 100% !important;
    min-width: 0 !important;
    max-height: none !important;
    box-shadow: none !important;
    border-radius: 0 !important;
    border: none !important;
    border-left: 3px solid rgba(212, 175, 55, 0.4) !important;
    margin-left: 12px !important;
    animation: none !important;
    background: rgba(255, 255, 255, 0.04) !important;
}

/* Disable the CSS hover trigger (touch "hover" is sticky on iOS/Android) */
body.mobile-mode .sidebar .nav-item:hover>.v-submenu {
    display: none !important;
}

/* Show accordion panel via the existing .submenu-open class (toggled by main.js click) */
body.mobile-mode .sidebar .nav-item.submenu-open>.v-submenu {
    display: block !important;
}

/* Rotate chevron to point down when section is expanded */
body.mobile-mode .sidebar .nav-item.submenu-open>.v-has-submenu::after {
    content: "\F282" !important;
}

/* ======================================================================
   PRJ-025 Phase 7A: Mobile List Page — KPI Bar + Avatars + Card Enhancements
   Scoped to @media queries per P17 (CSS-First). Desktop unchanged.
   ====================================================================== */

/* ── P19: Contextual Page Heading ── */
.mobile-context-heading {
    display: none;
}

@media (max-width: 767.98px) {
    .mobile-context-heading {
        display: block;
        padding: 16px 16px 8px;
        background: var(--color-charcoal, #2C3539);
        border-bottom: 2px solid var(--color-gold, #D4B068);
    }

    .mobile-context-title {
        font-family: 'Merriweather', serif;
        font-size: 1.3rem;
        font-weight: 700;
        color: var(--color-pure-white, #fff);
        margin: 0;
    }

    .mobile-context-subtitle {
        font-size: 0.75rem;
        color: rgba(255, 255, 255, 0.55);
        margin: 2px 0 0;
    }

    /* Pages with .mobile-context-heading hide the desktop header via per-page styles (P14) */
}

/* ── KPI Summary Bar ── */
.mobile-kpi-bar {
    display: none;
}

@media (max-width: 767.98px) {
    .mobile-kpi-bar {
        display: flex;
        gap: 8px;
        padding: 12px 12px 8px;
        background: var(--color-off-white, #F8F9FA);
        border-bottom: 1px solid rgba(44, 53, 57, 0.08);
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }

    .mobile-kpi-card {
        flex: 1;
        min-width: 0;
        background: var(--color-pure-white, #fff);
        border-radius: 10px;
        padding: 10px 12px;
        text-align: center;
        border: 1px solid rgba(212, 176, 104, 0.15);
        box-shadow: 0 1px 3px rgba(44, 53, 57, 0.06);
    }

    .mobile-kpi-value {
        font-family: 'Roboto Mono', monospace;
        font-size: 0.95rem;
        font-weight: 700;
        color: var(--color-charcoal, #2C3539);
        white-space: nowrap;
    }

    .mobile-kpi-value.kpi-danger {
        color: var(--color-crimson, #A62C2B);
    }

    .mobile-kpi-value.kpi-success {
        color: var(--v-banker-green, #1B4D3E);
    }

    .mobile-kpi-label {
        font-size: 0.6rem;
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: 0.06em;
        color: var(--color-text-grey, #6C757D);
        margin-top: 2px;
    }

    .mobile-kpi-count {
        font-size: 0.6rem;
        color: var(--color-text-grey, #6C757D);
        opacity: 0.6;
    }

    /* Extra padding at bottom for FAB / selection toolbar */
    .ledger-container {
        padding-bottom: 80px;
    }
}

/* ── Customer Initials Avatar ── */
.mobile-card-avatar {
    display: none;
}

@media (max-width: 767.98px) {
    .mobile-card-avatar {
        display: flex;
        align-items: center;
        justify-content: center;
        width: 38px;
        height: 38px;
        min-width: 38px;
        border-radius: 50%;
        font-size: 0.72rem;
        font-weight: 700;
        color: var(--color-pure-white, #fff);
        letter-spacing: 0.03em;
        margin: auto 0;
        margin-left: 10px;
    }

    .mobile-card-body {
        padding: 12px 14px 12px 10px;
    }

    .mobile-card-amount {
        color: var(--color-charcoal, #2C3539);
        font-size: 0.92rem;
    }
}

/* ── Relative Date + Overdue ── */
.mobile-card-reldate {
    font-size: 0.7rem;
    color: var(--color-text-grey, #6C757D);
}

.mobile-card-reldate.mobile-card-overdue {
    color: var(--color-crimson, #A62C2B);
    font-weight: 600;
}

.mobile-card-date-sub {
    font-size: 0.68rem;
    color: var(--color-text-grey, #6C757D);
    opacity: 0.5;
}

/* ── Status pills (mobile) ── */
@media (max-width: 767.98px) {
    .mobile-card-status .v-badge-glass {
        font-size: 0.58rem;
        padding: 2px 8px;
        border-radius: 10px;
        letter-spacing: 0.04em;
    }
}

/* ======================================================================
   PRJ-026 P18: Swipe Actions — reveal action tray behind card
   ====================================================================== */
@media (max-width: 767.98px) {
    .mobile-list-card {
        position: relative;
        overflow: hidden;
    }

    .mobile-card-inner {
        display: flex;
        align-items: stretch;
        background: inherit;
        position: relative;
        z-index: 1;
        transition: transform 0.3s cubic-bezier(0.25, 1, 0.5, 1);
        width: 100%;
    }

    .mobile-swipe-tray {
        position: absolute;
        right: 0;
        top: 0;
        bottom: 0;
        width: 80px;
        display: flex;
        align-items: stretch;
        z-index: 0;
    }

    .mobile-swipe-btn {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        flex: 1;
        border: none;
        cursor: pointer;
        color: var(--color-pure-white, #fff);
        font-size: 0.65rem;
        font-weight: 600;
        gap: 4px;
        padding: 8px 4px;
        min-width: 0;
    }

    .mobile-swipe-btn i {
        font-size: 1.1rem;
    }

    .mobile-swipe-btn-danger {
        background: var(--color-crimson, #A62C2B);
    }

    .mobile-swipe-btn-danger:active {
        background: #8a2424;
    }

    .mobile-swipe-btn-default {
        background: var(--color-charcoal, #2C3539);
    }

    .mobile-swipe-btn-default:active {
        background: #1a2023;
    }

    .mobile-selection-mode .mobile-card-inner {
        transform: none !important;
    }

    .mobile-selection-mode .mobile-swipe-tray {
        display: none;
    }
}

/* ===== Group A: Linear list table/card swap =====
   Mirrors the ledger-container pattern above for pages using
   the list_view.html macro system (customers, suppliers, accounts, items, bundles).
   Header hiding handled by existing body.mobile-mode rule (line 803). */
@media (max-width: 767.98px) {
    .v-linear-list .v-linear-header {
        display: none !important;
    }

    .v-linear-list .v-linear-row {
        display: none !important;
    }

    .v-linear-list .mobile-list-card {
        display: flex !important;
    }
}