/* ===== A: SHELL ===== */
/*
 * Enigma mobile restyle — Batch A (global shell).
 * Every rule is media-scoped so desktop (>=992px) renders BYTE-IDENTICAL.
 * Module <style> blocks inject later in DOM order, so geometry overrides use
 * `html body`-prefixed selectors + pragmatic !important (this is an override sheet).
 * Breakpoints (per spec):
 *   - phone layer      : max-width 640.98px   (primary targets 360 / 390 / 412)
 *   - touch layer      : max-width 991.98px   (phones + tablets — input ergonomics)
 *   - tablet-only layer: 641px .. 991.98px    (light fixes only)
 * Deploy concatenates css/mobile-a.css (+ later batches' sections) -> css/mobile.css.
 */

/* =====================================================================
 * PHONE LAYER  (<= 640.98px)
 * ===================================================================== */
@media (max-width: 640.98px) {

  /* --- Body: drop the tiled watermark pattern behind content (calmer). ------ */
  html body {
    background:
      linear-gradient(135deg, var(--primary-bg) 0%, var(--secondary-bg) 100%) !important;
    background-attachment: fixed !important;
  }

  /* --- Navbar: compact (~52px). Brand img has an inline height:52px -> !important. */
  html body .navbar {
    padding-top: 0.15rem !important;
    padding-bottom: 0.15rem !important;
  }
  html body .navbar > .container-fluid {
    padding-left: 8px !important;
    padding-right: 8px !important;
  }
  html body .navbar-brand img {
    height: 38px !important;
  }

  /* --- Padding chain kill: the single biggest win on 360/390. --------------- */
  html body .main-content {
    margin-top: 56px !important;                 /* was inline 76px (matched 52px logo) */
    padding: 0.5rem 0 !important;                /* was 2rem 0 */
    min-height: calc(100vh - 56px) !important;
  }
  html body .main-content > .container-fluid {
    padding-left: 8px !important;                /* was 12px */
    padding-right: 8px !important;
  }
  html body #tab-content.tab-content {
    padding: 12px 8px !important;                /* was 2rem */
  }
  html body #tab-content .card-body {
    padding: 0.75rem !important;                 /* was 1rem */
  }

  /* --- Tab strip: single row, swipeable, hidden scrollbar, snap. ------------ */
  html body #tab-bar.tab-bar {
    flex-wrap: nowrap !important;                /* was wrap (3 rows of chrome) */
    overflow-x: auto !important;
    overflow-y: hidden !important;
    -webkit-overflow-scrolling: touch !important;
    scroll-snap-type: x proximity !important;
    scrollbar-width: none !important;            /* Firefox */
  }
  html body #tab-bar.tab-bar::-webkit-scrollbar {
    height: 0 !important;
    display: none !important;                    /* WebKit */
  }
  html body #tab-bar .tab-button {
    flex: 0 0 auto !important;
    max-width: 46vw !important;
    min-height: 44px !important;
    align-items: center !important;
    scroll-snap-align: start !important;
    padding-right: 44px !important;              /* room for the enlarged close hit-area */
  }
  /* Close x: a solid 40x44 tap target (was an 18px glyph). */
  html body #tab-bar .tab-close {
    top: 0 !important;
    right: 2px !important;
    transform: none !important;
    width: 40px !important;
    height: 100% !important;
    min-height: 44px !important;
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
    font-size: 20px !important;
  }

  /* --- Buttons inside tab-content + modals: 42px, wrap at word boundary. ----- */
  html body #tab-content .btn-sm,
  html body .modal .btn-sm {
    min-height: 44px !important; /* raised 42->44: the !important here beat every later 44px batch rule */
    padding: 0.45rem 0.7rem !important;
    white-space: normal !important;              /* allow wrap ... */
    word-break: normal !important;               /* ... but never mid-word */
    overflow-wrap: break-word !important;
  }
  html body #tab-content .btn,
  html body .modal .btn {
    white-space: normal !important;
    word-break: normal !important;
    overflow-wrap: break-word !important;
  }

  /* --- Forms: 16px kills iOS input-zoom; 44px tap targets. ------------------ */
  html body #tab-content input:not([type="checkbox"]):not([type="radio"]),
  html body #tab-content select,
  html body #tab-content textarea,
  html body .modal input:not([type="checkbox"]):not([type="radio"]),
  html body .modal select,
  html body .modal textarea {
    font-size: 16px !important;
  }
  html body #tab-content input:not([type="checkbox"]):not([type="radio"]),
  html body #tab-content select,
  html body .modal input:not([type="checkbox"]):not([type="radio"]),
  html body .modal select {
    min-height: 44px !important;
  }

  /* --- Modals -> bottom sheets: full-width, pinned bottom, internal scroll. -- */
  html body .modal-dialog {
    position: fixed !important;
    margin: 0 !important;
    left: 0 !important;
    right: 0 !important;
    bottom: 0 !important;
    top: auto !important;
    width: auto !important;                      /* left/right:0 -> full width, no 100vw overflow */
    max-width: none !important;
    max-height: 94dvh !important;
  }
  html body .modal-content {
    border-radius: 16px 16px 0 0 !important;
    max-height: 94dvh !important;
  }
  html body .modal-body {
    overflow-y: auto !important;
    -webkit-overflow-scrolling: touch !important;
  }

  /* Confirm/alert dialogs stay centered, not bottom sheets (2026-08-03). A
     bottom sheet suits content a user picks from or fills in; it's the wrong
     shape for a quick yes/no prompt, and it collides with the Message Centre
     toast, which also anchors to the bottom of the viewport (see the modal
     z-index fix in index.html for the other half of that bug). ID selector so
     it wins over the blanket .modal-dialog rule above regardless of source
     order (both carry !important; specificity is the tiebreaker). */
  html body #confirmationModal .modal-dialog {
    position: fixed !important;
    top: 50% !important;
    left: 50% !important;
    right: auto !important;
    bottom: auto !important;
    transform: translate(-50%, -50%) !important;
    width: calc(100% - 2rem) !important;
    max-width: 400px !important;
    margin: 0 !important;
    max-height: 90dvh !important;
  }
  html body #confirmationModal .modal-content {
    border-radius: 16px !important;
    max-height: 90dvh !important;
  }

  /* --- Nav drawer: mobile-only text labels beside the icon-only shell items. - */
  html body .nav-mobile-label {
    margin-left: 8px !important;
    font-weight: 500 !important;
    vertical-align: middle !important;
  }
  /* WA / orb items sit inline with their label on the vertical drawer. */
  html body #wa-connect,
  html body #orb-nav-launcher {
    vertical-align: middle !important;
  }
  /* Message-Centre indicator: keep the status dot ON the antenna, not floating
     to the far right of the now-labelled item (fixes the "stray green dot"). */
  html body #ws-status-indicator {
    padding: 6px 8px !important;
  }
  html body #ws-status-indicator .mc-dot {
    left: 22px !important;
    right: auto !important;
    top: 4px !important;
  }

  /* --- flatpickr: never wider than the viewport at 360. -------------------- */
  html body .flatpickr-calendar {
    max-width: calc(100vw - 16px) !important;
  }
}

/* =====================================================================
 * TOUCH LAYER  (<= 991.98px)  — phones AND tablets
 * ===================================================================== */
@media (max-width: 991.98px) {
  /* Hide number spinners app-wide on touch surfaces (kept media-scoped so
     desktop mouse rendering stays byte-identical). */
  html body input[type="number"] {
    -moz-appearance: textfield !important;
    appearance: textfield !important;
  }
  html body input[type="number"]::-webkit-outer-spin-button,
  html body input[type="number"]::-webkit-inner-spin-button {
    -webkit-appearance: none !important;
    margin: 0 !important;
  }
}

/* =====================================================================
 * TABLET-ONLY LAYER  (641px .. 991.98px)  — light fixes only
 * ===================================================================== */
@media (min-width: 641px) and (max-width: 991.98px) {
  html body #tab-content.tab-content {
    padding: 1.25rem !important;                 /* between phone 12px and desktop 2rem */
  }
}

/* ===== A-FIX: WhatsApp drawer row on one line, label tappable ===== */
@media (max-width: 991.98px) {
  html body #navbarNav .nav-item:has(> #wa-connect) { display: flex !important; align-items: center !important; }
  html body #navbarNav .nav-item > #wa-connect { flex: 0 0 auto; }
  html body #navbarNav .nav-item > #wa-connect + .nav-mobile-label { flex: 1 1 auto; display: flex !important; align-items: center; }
}

/* ===== HARMONISATION: no number-input spinners at ANY width ===== */
input[type=number] { -moz-appearance: textfield; appearance: textfield; }
input[type=number]::-webkit-outer-spin-button,
input[type=number]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
/* ===== B: GRIDS ===== */
/*
 * Batch B — generic list grids reborn as record cards, one pagination engine,
 * search-pane + header stacking for the grid modules.
 *
 * EVERY rule below lives inside a @media block scoped to the phone layer
 * (max-width:640.98px) or the light-tablet layer, so desktop (>=992px) rendering
 * is untouched by this sheet. The card reflow is driven by attributes/classes that
 * js/mobile-cards.js stamps at all widths but that no desktop rule reads.
 *
 * Selectors are `html body`-prefixed with pragmatic !important because module
 * <style> blocks inject later in DOM order (see spec: cascade trap) — this is an
 * override sheet.
 */

/* ============================================================
 *  PHONE LAYER  (portrait phones — primary targets 360/390/412)
 * ============================================================ */
@media (max-width: 640.98px) {

  /* ---------- Card-ify opted-in list grids ---------- */

  html body .m-cards,
  html body .m-cards tbody,
  html body .m-cards tr,
  html body .m-cards td {
    display: block;
    width: auto;
  }

  /* Header row is encoded per-cell via data-label — hide the real <thead>. */
  html body .m-cards thead {
    position: absolute !important;
    left: -9999px !important;
    top: auto;
    width: 1px;
    height: 1px;
    overflow: hidden;
  }

  /* Fixed desktop column widths must not constrain the card layout. */
  html body .m-cards colgroup { display: none !important; }

  /* Each data row becomes a record card. */
  html body .m-cards > tbody > tr {
    border: 1px solid rgba(0, 0, 0, 0.12) !important;
    border-radius: 12px;
    margin-bottom: 0.5rem;
    padding: 12px;
    background: #fff;
    box-shadow: var(--shadow-sm);
  }

  /* Kill Bootstrap's cell borders/padding; each cell is a label:value flex row. */
  html body .m-cards > tbody > tr > td {
    border: none !important;
    padding: 4px 0 !important;
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 12px;
    font-size: 14px;
    min-height: 0;
    white-space: normal;
    word-break: break-word;
  }

  html body .m-cards > tbody > tr > td[data-label]::before {
    content: attr(data-label);
    flex: 0 0 40%;
    max-width: 40%;
    color: #6c757d;
    font-size: 12px;
    font-weight: 600;
    text-align: left;
  }

  html body .m-cards > tbody > tr > td[data-label] {
    text-align: right;
  }

  /* First cell = the card title line (bold, full width, no label). */
  html body .m-cards > tbody > tr > td:first-child {
    display: block;
    text-align: left;
    font-size: 15px;
    font-weight: 700;
    padding-bottom: 6px !important;
    margin-bottom: 6px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.08) !important;
    word-break: break-word;
  }
  html body .m-cards > tbody > tr > td:first-child::before { display: none; }

  /* Hide genuinely empty cells so cards don't grow blank rows. */
  html body .m-cards > tbody > tr > td:empty { display: none !important; }

  /* Photo/media cell → full-width thumbnail. */
  html body .m-cards > tbody > tr > td.m-media {
    display: block;
    padding: 6px 0 !important;
  }
  html body .m-cards > tbody > tr > td.m-media::before { display: none; }
  html body .m-cards > tbody > tr > td.m-media img {
    width: 100%;
    max-height: 160px;
    object-fit: cover;
    border-radius: 8px;
  }

  /* Actions cell → full-width wrapping row of 44px buttons at the card foot. */
  html body .m-cards > tbody > tr > td.m-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    padding-top: 10px !important;
    margin-top: 6px;
    border-top: 1px solid rgba(0, 0, 0, 0.08) !important;
  }
  html body .m-cards > tbody > tr > td.m-actions::before { display: none; }
  html body .m-cards > tbody > tr > td.m-actions .btn {
    flex: 1 1 auto;
    min-width: calc(50% - 4px);
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    white-space: nowrap;
    margin: 0 !important;
  }

  /* Loading / empty / error single-cell rows: a plain centred message, not a card. */
  html body .m-cards > tbody > tr.m-cardless {
    border: none !important;
    box-shadow: none;
    background: transparent;
    padding: 0;
    margin: 0;
  }
  html body .m-cards > tbody > tr > td.m-fullcell {
    display: block;
    text-align: center;
    padding: 16px 4px !important;
    color: #6c757d;
    font-size: 14px;
  }
  html body .m-cards > tbody > tr > td.m-fullcell::before { display: none; }

  /* price-changes: keep the whole card tappable (module already wires the tr click). */
  html body #price-changes-container .m-cards > tbody > tr {
    cursor: pointer;
  }

  /* The lead-origin amber stripe is a tr.lead-origin-row rule in index.html's
     shared stylesheet, deliberately scoped to outrank the card border above.
     It was an inline style until 2026-08-17, which that !important border ate. */


  /* ---------- ONE pagination engine, mobile trim ---------- */

  html body .pagination-container {
    flex-wrap: wrap;
    gap: 8px 12px;
    justify-content: center !important;
    margin-top: 0.75rem;
  }
  /* Count on its own line, centred, above the nav. */
  html body .pagination-container .pagination-count {
    flex: 1 1 100%;
    text-align: center;
  }
  html body .pagination-container .pagination-pages {
    flex-wrap: wrap;
    gap: 4px;
    justify-content: center;
  }
  html body .pagination-container .pagination-pages .btn {
    min-height: 42px;
    min-width: 42px;
  }
  /* Trim the page-number list to Previous · current · Next (kills overflow). */
  html body .pagination-container .pagination-pages .btn:not(.pagination-prev):not(.pagination-next):not(.active) {
    display: none;
  }
  html body .pagination-container .pagination-pages .pagination-ellipsis { display: none; }


  /* ---------- Search-buyers / search-property: pagination below table ---------- */
  /* search-property markup is moved below the table in its own file; search-buyers'
     container lives in an un-owned Dust template, so on phones we reorder the flex
     children of .search-results to put the pager under the results (see MANIFEST). */
  html body .search-results {
    display: flex;
    flex-direction: column;
  }
  html body .search-results > .search-status      { order: 1; }
  html body .search-results > .table-responsive    { order: 2; }
  html body .search-results > .pagination-container { order: 3; }
  html body .search-results > .no-results           { order: 4; }


  /* ---------- Buyers search panes: full-width stacking (QA #4/#8) ---------- */
  html body #search-mode-panels .input-group {
    flex-wrap: wrap;
    gap: 6px;
  }
  html body #search-mode-panels .input-group > .form-control {
    flex: 1 1 100%;
    width: 100%;
    min-width: 0;
    min-height: 44px;
    font-size: 16px;              /* prevents iOS input zoom */
    border-radius: 8px !important;
  }
  html body #search-mode-panels .input-group > .btn {
    flex: 1 1 auto;
    min-height: 44px;
    border-radius: 8px !important;
  }
  html body #search-mode-panels .search-mode-card .card-body { padding: 12px; }
  html body #new-system-btn { min-height: 44px; }


  /* ---------- Header toolbars → stack (title row, then full-width buttons) ---------- */
  /* .search-controls is used only by search-property + search-buyers (both Batch B). */
  html body .card-header:has(.search-controls) { flex-wrap: wrap; }
  /* Non-:has fallback for the one header we can id-scope (search-property). */
  html body #search-property-container .card-header { flex-wrap: wrap; }
  html body .card-header .search-controls {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    width: 100%;
    margin-top: 8px;
  }
  html body .card-header .search-controls .btn {
    flex: 1 1 auto;
    min-height: 44px;
    margin-left: 0 !important;
  }
  /* sales-kyc toolbar (New Sale + badge). */
  html body #sales-kyc-container .card-header { flex-wrap: wrap; }
  html body #sales-kyc-container .card-header > div {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    width: 100%;
    margin-top: 8px;
  }
  html body #sales-kyc-container .card-header > div .btn {
    flex: 1 1 auto;
    min-height: 44px;
    margin-right: 0 !important;
  }


  /* ---------- Match-property: stack the "matched" banner + phone filters ---------- */
  html body #match-property-container .property-input-section .col-md-6 { width: 100%; }
  html body #property-match-display .alert-success > .d-flex {
    flex-direction: column;
    align-items: stretch !important;
    gap: 10px;
  }
  html body #property-match-display .alert-success .btn {
    min-height: 44px;
    flex: 1 1 auto;
  }
  html body #property-match-display .alert-success > .d-flex > div:last-child {
    display: flex;
    gap: 8px;
  }
  html body #property-match-display .alert-success .btn.ms-2 { margin-left: 0 !important; }


  /* ---------- Search-property: filters collapse toggle (phone only) ---------- */
  html body #search-filters-toggle { min-height: 44px; }

}

/* ============================================================
 *  LIGHT TABLET LAYER  (641–991px) — targeted fixes only
 * ============================================================ */
@media (min-width: 641px) and (max-width: 991.98px) {
  /* Grids keep the desktop table here (fits), but give the promoted pager room. */
  html body .pagination-container { flex-wrap: wrap; gap: 8px; }
  html body .pagination-container .pagination-pages { flex-wrap: wrap; }
}

/* ===== B-FIX: kill zebra/hover tint inside card mode ===== */
@media (max-width: 640.98px) {
  html body .m-cards tbody tr,
  html body .m-cards tbody td {
    background: #fff !important;
    --bs-table-bg-type: transparent;
    --bs-table-accent-bg: transparent !important;
    --bs-table-striped-bg: transparent !important;
    box-shadow: none !important;
  }
}
/* ===== C: PIPELINE ===== */
/*
 * Batch C — pipeline (buyers-update), pipeline detail, BR editor/view, matches-tab.
 * Every rule is media-scoped, so >=992px desktop rendering is byte-identical.
 * Selectors are `html body`-prefixed with pragmatic !important to win over the
 * module <style>/JS-injected CSS that loads after this sheet (cascade-trap note).
 * Deploy: concatenate AFTER the A-SHELL section (relies on Batch A's compact
 * navbar, .btn-sm min-height:42px and padding-chain trims).
 */

/* ------------------------------------------------------------------ */
/* PHONE LAYER (portrait phones) — primary targets 360 / 390 / 412    */
/* ------------------------------------------------------------------ */
@media (max-width: 640.98px) {

  /* --- Pipeline Dashboard header: no page overflow; badges wrap; compact labels --- */
  html body #bu-dash-header { flex-wrap: wrap; }
  html body #bu-header-badges {
    flex-wrap: wrap;
    width: 100%;
    margin-top: 0.4rem;
    row-gap: 0.35rem;
    column-gap: 0.4rem;
  }
  /* Refresh stays right-aligned even after the badges wrap */
  html body #bu-header-badges > button { margin-left: auto; }
  html body #bu-header-badges .bu-header-badge {
    font-size: 0.72rem;
    white-space: nowrap;
  }
  /* Swap the full section label for its compact form ("Due within 24 hours" -> "24h") */
  html body #bu-header-badges .bu-badge-full  { display: none !important; }
  html body #bu-header-badges .bu-badge-short { display: inline !important; }

  /* --- Buyer tiles: full-bleed (trim the padding chain) + 2-line title clamp --- */
  html body .module-content > .p-3 {
    padding-left: 0.5rem !important;
    padding-right: 0.5rem !important;
  }
  html body [id^="bu-content-"] {
    padding-left: 0.5rem !important;
    padding-right: 0.5rem !important;
  }
  html body .bu-buyer-title {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    line-height: 1.25;
    word-break: break-word;
  }

  /* --- Section pager: relabelled Previous/Next; wrap instead of colliding --- */
  html body .bu-pager { flex-wrap: wrap; gap: 0.5rem; }
  html body .bu-pager .btn-group { flex-wrap: wrap; }
  html body .bu-pager .btn { min-height: 42px; }

  /* --- Pipeline detail: split view stacks (col-lg-*); tighten gutters/padding --- */
  html body .pipeline-detail-view { padding: 0.25rem !important; }
  html body .pipeline-detail-view .row.g-3 { --bs-gutter-y: 0.75rem; }

  /* --- Events editor (right panel): Mark-Result tap targets + Start Step wrap fix --- */
  html body [data-action="complete-event"] { min-height: 42px; }
  html body [data-action="manual-start"] {
    white-space: nowrap;   /* never split "Start Step" mid-word */
    min-height: 42px;
  }
  /* Manual-override row: let the select go full width and the button drop below it */
  html body .card.border-secondary .d-flex.align-items-center.gap-2 { flex-wrap: wrap; }
  html body #obdash-manual-step {
    flex: 1 1 100%;
    max-width: 100% !important;
  }

  /* --- Matches tab (buyer direction): 2-col already stacks via col-lg-*; tidy spacing --- */
  html body .matches-tab-content { padding: 0.5rem !important; }
  html body .matches-tab-content .row.g-3 { --bs-gutter-y: 0.75rem; }
  /* Row action buttons already outline (canon); keep them a comfortable tap height */
  html body #tab-content .table-responsive .btn-sm { min-height: 42px; }

  /* --- Buyer View (read-only BR, .br-details) --------------------------------- */
  /* "Edit BR" header button no longer wraps to 3 lines */
  html body .br-details > .d-flex {
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
  }
  html body .br-details > .d-flex .btn {
    white-space: nowrap;
    flex-shrink: 0;
  }
  html body .br-details > .d-flex h3 { font-size: 1.15rem; }

  /* Read-only (disabled) form -> flat label:value text, not a dead greyed form */
  html body .br-details fieldset[disabled] .form-control,
  html body .br-details fieldset[disabled] .form-select {
    border: 0 !important;
    background-color: transparent !important;
    background-image: none !important;   /* also drops the <select> caret */
    box-shadow: none !important;
    padding-left: 0 !important;
    padding-right: 0 !important;
    min-height: 0 !important;
    height: auto !important;
    color: #212529 !important;
    -webkit-text-fill-color: #212529 !important;  /* override UA disabled greying */
    opacity: 1 !important;
    font-weight: 500;
  }
  html body .br-details fieldset[disabled] .form-label {
    font-size: 12px;
    margin-bottom: 0;
    color: #6c757d;
    font-weight: 600;
  }
  html body .br-details fieldset[disabled] .input-group-text {
    border: 0 !important;
    background: transparent !important;
    padding-left: 0 !important;
  }

  /* Embedded contact table inside a note -> contained horizontal scroll (never the page) */
  html body .br-details .notes-list .card-text {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
  html body .br-details .notes-list .card-text > table,
  html body .br-details .notes-list .card-text table.table {
    margin-bottom: 0;
  }
}

/* ------------------------------------------------------------------ */
/* LIGHT TABLET BAND — only where QA shows breakage (header overflow) */
/* ------------------------------------------------------------------ */
@media (min-width: 641px) and (max-width: 991.98px) {
  /* Full labels stay, but let the badge row wrap so it can never pan the page */
  html body #bu-dash-header { flex-wrap: wrap; }
  html body #bu-header-badges { flex-wrap: wrap; }
}
/* ===== D: VIEWINGS ===== */
/* Phone-only layer for the viewings module (modules/viewing.html).
   Every rule is inside the ≤640.98px media query, so desktop (≥992px) and the
   641–991 band render byte-identical — the harmonisation icon/outline button
   changes live in viewing.html markup, not here.
   The module injects an ID-scoped <style id="viewings-module-styles"> at load
   (higher up the cascade, no media query), and the session UI + all wizard/PVR/
   edit modals render at document.body level. Geometry overrides are therefore
   `html body`-prefixed + pragmatic !important, and the modal rules are scoped by
   their own IDs (#vw-pvr-modal / #vw-new-modal / #vw-edit-modal). */

@media (max-width: 640.98px) {

    /* --- Padding-chain trim: the module adds its own p-3 (16px) on top of the
       shell's tab-content gutters. Bring it to the 8px app-frame gutter. -------- */
    html body #viewings-container { padding: 0.5rem !important; }

    /* --- Today tab: compact toolbar + a real tap target on the row edit btn --- */
    html body #viewings-container .vw-toolbar { row-gap: 8px; }
    html body #viewings-container .vw-row { padding: 12px 8px !important; }
    html body #viewings-container .vw-row .vw-time { font-size: 1rem; }
    html body #viewings-container .vw-buyer,
    html body #viewings-container .vw-props { word-break: break-word; }
    /* Edit-appointment button was a bare icon link (p-0); the markup now makes it
       a real outline-secondary button — give it a ≥42px hit area on phone. */
    html body #viewings-container .vw-edit-btn {
        min-height: 42px;
        min-width: 42px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        padding: 0.3rem 0.55rem;
    }

    /* --- Session toolbar: stack Add-by-REF / Pull-up-matches / Radius full width.
       The columns are col-sm-6 / col-sm-auto, which below 576px are unsized flex
       children (they would otherwise shrink-to-content and sit ragged). ---------- */
    html body #viewings-container #vw-session-body .row.align-items-end > * {
        flex: 0 0 100%;
        max-width: 100%;
    }
    html body #viewings-container #vw-matchnow-btn { width: 100%; min-height: 44px; }
    html body #viewings-container #vw-add-ref-btn { min-height: 44px; white-space: nowrap; }

    /* --- Brochure + match cards: single column, larger photo, 44px stacked CTAs.
       col-sm-6/col-md-4 have no base col-* class, so force full width on phone. -- */
    html body #viewings-container #vw-brochure > [class*="col-"],
    html body #viewings-container #vw-matches > [class*="col-"] {
        flex: 0 0 100%;
        max-width: 100%;
    }
    html body #viewings-container .vw-bcard .vw-photo { height: 200px !important; }
    html body #viewings-container .vw-bcard .card-body .d-grid { gap: 0.5rem !important; }
    html body #viewings-container .vw-bcard .card-body .btn { min-height: 44px; }
    html body #viewings-container .vw-bcard .vw-addr-toggle {
        min-height: 32px;
        min-width: auto;
    }

    /* --- PVR review modal: comfortable questionnaire tap targets + no iOS zoom -- */
    html body #vw-pvr-modal .vw-q-group.d-grid { gap: 0.5rem !important; }
    html body #vw-pvr-modal .vw-choice {
        min-height: 48px;
        padding: 0.6rem 0.85rem;
        display: flex;
        align-items: center;
        line-height: 1.3;
    }
    html body #vw-pvr-modal textarea.form-control,
    html body #vw-pvr-modal input.form-control { font-size: 16px; }
    html body #vw-pvr-modal #vw-pvr-sig-clear { min-height: 42px; }

    /* --- New-viewing wizard + edit modal ------------------------------------- */
    /* Comfortable client / BR pick rows. */
    html body #vw-new-modal .list-group-item-action { min-height: 44px; }
    /* Re-flow the Date / Time / Hrs row: Date on its own line (col-6 → full),
       Time + Hrs share the next line (col-3 → half) so type=time isn't clipped. */
    html body #vw-new-modal .row > .col-6,
    html body #vw-edit-modal .row > .col-6 { flex: 0 0 100%; max-width: 100%; }
    html body #vw-new-modal .row > .col-3,
    html body #vw-edit-modal .row > .col-3 { flex: 0 0 50%; max-width: 50%; }
    html body #vw-new-modal .form-control,
    html body #vw-edit-modal .form-control { font-size: 16px; }

    /* --- Summary recap: let the header + Back button wrap instead of squeezing - */
    html body #viewings-container #vw-summary .d-flex.justify-content-between {
        flex-wrap: wrap;
        gap: 8px;
    }
}
/* ===== E: FOLLOWUPS ===== */
/* Daily Follow-Ups (modules/daily-followups.html). Phone-only geometry: all rules
   live inside the phone media query so desktop (>=641px) renders byte-identical.
   Module injects its own #daily-followups-container CSS via document.head at load
   (after this stylesheet in DOM order), so overrides are html body-prefixed +
   !important per the cascade-trap convention. */
@media (max-width: 640.98px) {

    /* AI-draft / reply textarea → ~6 lines tall on phone.
       QA: it showed ~3.5 lines with an inner scrollbar. rows="3" stays in the
       markup (desktop keeps 3 lines); min-height only grows it on phones. */
    html body #daily-followups-container .fu-textarea {
        min-height: 160px !important;
    }

    /* Card + header action buttons → canon 44px tap targets (QA: btn-sm ~31px tall). */
    html body #daily-followups-container #fu-refresh-btn,
    html body #daily-followups-container .fu-br-btn,
    html body #daily-followups-container .fu-send-btn {
        min-height: 44px;
    }

    /* 'Hide options' split-caret → real >=44px hit area (QA: caret was 22x31px,
       near-untappable). Widen and heighten the split toggle only. */
    html body #daily-followups-container .fu-row .dropdown-toggle-split {
        min-height: 44px;
        min-width: 48px;
    }
}
/* ===== F: SHORTLISTS ===== */
/*
 * Shortlist view tab — phone pass (rendered by js/shortlist-view-tab.js).
 *
 * NOTE: QA reached 0 shortlists (no read-only path on the inspected buyers),
 * so there are no negotiator screenshots of this surface. The rules below are
 * derived directly from the rendered markup and kept deliberately conservative:
 * they reflow the existing flex rows into stacked record cards and enforce the
 * 44px tap-target canon — no new components, no behaviour change.
 *
 * Every rule is inside the phone media query, so desktop (>=992px) and the
 * light-tablet band (641-991px) render byte-identically — the property row and
 * action bar have ample width there and need no fix.
 *
 * Selectors are html body-prefixed with pragmatic !important because module
 * geometry (inline styles + late <style> injection) otherwise wins — this is an
 * override sheet, per the spec's cascade-trap note.
 */

@media (max-width: 640.98px) {

    /* --- Reclaim the doubled inner gutter -------------------------------- *
     * The tab pane already trims to ~8px (Batch A shell). This viewer wraps
     * its own content in .p-3 (16px) on top of that, so content sat ~24px in
     * from each edge. Bring the wrapper down to the 8px app-frame gutter; the
     * cards inside keep their own body padding. */
    html body .shortlist-view-tab-content {
        padding: 0.5rem !important;
    }

    /* --- Header: copyable public-URL group ------------------------------ *
     * Was max-width:480px (fine on desktop, forces a cramped inline row on a
     * phone). Let it use the full width and make the Copy control a real tap
     * target; the readonly URL input scrolls internally as before. */
    html body .shortlist-view-tab-content .input-group {
        max-width: 100% !important;
    }
    html body .shortlist-view-tab-content .input-group > .btn,
    html body .shortlist-view-tab-content .input-group > .form-control,
    html body .shortlist-view-tab-content .input-group > .input-group-text {
        min-height: 44px;
    }

    /* --- Property rows -> stacked record cards --------------------------- *
     * Desktop is a single flex row:  [thumb] [ref/price/meta] [feedback] [View]
     * At ~250px usable width that squeezes the feedback badge and the View
     * button off the edge. Wrap it into a card:
     *     line 1:  [thumb] [ref / price / meta]
     *     line 2:  [feedback badge + detail, full width]
     *     line 3:  [View — full-width 44px action] */
    html body .slv-prop-row {
        flex-wrap: wrap;
        row-gap: 6px;
    }
    /* Let the info column shrink so a long "type · locality" line wraps
       instead of forcing horizontal overflow. */
    html body .slv-prop-row > .flex-grow-1 {
        min-width: 0;
    }
    /* Feedback badge block onto its own full-width line (drops the ms-2). */
    html body .slv-prop-row > .slv-feedback-block {
        flex: 1 1 100%;
        margin-left: 0 !important;
    }
    /* Its detail text was capped at 200px inline — free it to the card width
       and keep the single-line ellipsis (needs min-width:0 to shrink in flex). */
    html body .slv-prop-row > .slv-feedback-block .text-muted {
        max-width: 100% !important;
        min-width: 0;
    }
    /* View button: full-width 44px action row at the card foot. */
    html body .slv-prop-row > .btn {
        flex: 1 1 100%;
        margin-left: 0 !important;
        min-height: 44px;
    }

    /* --- Bottom action bar (Send / Export PDF / Convert) ----------------- *
     * Stack full-width so each primary action is an unambiguous 44px target
     * (the .btn-success WhatsApp state logic in JS is untouched). */
    html body .slv-actions {
        flex-direction: column;
        align-items: stretch;
    }
    html body .slv-actions > .btn {
        width: 100%;
        min-height: 44px;
    }
}
/* ===== G: CALENDAR+PROFILE ===== */
/* Phone layer only (≤640.98px). All rules are media-scoped so desktop ≥992px is
   byte-identical. Module CSS (#cal-module-css / #profile-module-css) is JS-injected
   into <head> AFTER this sheet, so overrides use `html body`-prefixed selectors
   (higher specificity) plus pragmatic !important on the exact properties they beat.
   Agenda / chip classes (.cal-ag-*, .cal-agenda) are new markup produced only on
   phones by calendar.html's renderWeekAgenda — no desktop element ever matches them. */

@media (max-width: 640.98px) {

  /* --- Calendar: tighten the wrap, comfortable app-frame gutters --- */
  html body .cal-wrap { padding: 8px !important; }

  /* Toolbar tap targets ≥44px; prev/next square, chevron icons legible --- */
  html body .cal-bar .btn { min-height: 44px; }
  html body .cal-bar .cal-views .btn { min-height: 44px; }
  html body .cal-bar #cal-prev,
  html body .cal-bar #cal-next {
    min-width: 44px; padding-left: .5rem; padding-right: .5rem;
  }
  html body .cal-bar #cal-prev i,
  html body .cal-bar #cal-next i { font-size: 1rem; line-height: 1; }
  html body .cal-title { min-width: 0; font-size: 1rem; }

  /* --- Legend: single scrollable chip row (was wrapping to 3 rows) --- */
  html body .cal-legend {
    flex-wrap: nowrap !important;
    overflow-x: auto !important;
    -webkit-overflow-scrolling: touch;
    gap: 6px;
    margin: 6px 0 10px;
    padding-bottom: 2px;
    scrollbar-width: none;
  }
  html body .cal-legend::-webkit-scrollbar { display: none; }
  html body .cal-legend > span {
    flex: 0 0 auto;
    white-space: nowrap;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    background: rgba(0, 0, 0, .04);
    border: 1px solid rgba(0, 0, 0, .08);
    border-radius: 12px;
    padding: 4px 9px;
    font-size: .72rem;
  }

  /* --- Week → 7-day vertical agenda list (phone-only render) --- */
  html body .cal-agenda { display: block; }
  html body .cal-ag-sec { margin-bottom: 14px; }
  html body .cal-ag-dayhd {
    display: flex;
    align-items: center;
    gap: 8px;
    font-weight: 600;
    font-size: .9rem;
    color: #212529;
    padding: 4px 2px;
    border-bottom: 2px solid #dee2e6;
  }
  html body .cal-ag-sec.today .cal-ag-dayhd { color: #0d6efd; border-bottom-color: #0d6efd; }
  html body .cal-ag-todaytag {
    font-size: .66rem;
    font-weight: 600;
    color: #fff;
    background: #0d6efd;
    border-radius: 10px;
    padding: 1px 8px;
  }
  html body .cal-ag-empty {
    color: #adb5bd;
    font-size: .82rem;
    padding: 8px 2px 2px;
  }
  html body .cal-ag-ev {
    display: flex;
    gap: 10px;
    align-items: flex-start;
    min-height: 44px;
    margin-top: 8px;
    padding: 10px 12px;
    background: #fff;
    border: 1px solid #e9ecef;
    border-radius: 8px;
    cursor: pointer;
  }
  html body .cal-ag-ev:active { background: #f1f3f5; }
  html body .cal-ag-time {
    flex: 0 0 auto;
    min-width: 78px;
    padding-top: 1px;
    font-weight: 600;
    font-size: .8rem;
    color: #343a40;
  }
  html body .cal-ag-main { flex: 1 1 auto; min-width: 0; }
  html body .cal-ag-title {
    font-weight: 600;
    font-size: .95rem;
    line-height: 1.25;
    color: #212529;
    word-break: break-word;
  }
  html body .cal-ag-rep { font-size: .72rem; color: #6c757d; margin-left: 2px; }
  html body .cal-ag-where {
    margin-top: 2px;
    font-size: .8rem;
    color: #6c757d;
    word-break: break-word;
  }
  html body .cal-ag-where i { margin-right: 3px; }
  html body .cal-ag-type {
    display: flex;
    align-items: center;
    gap: 5px;
    margin-top: 3px;
    font-size: .72rem;
    color: #6c757d;
  }

  /* --- Profile: minor canon alignment (tap targets, edge gutters) --- */
  html body .pf-wrap { padding: 10px !important; }
  html body .pf-block .bact button {
    min-width: 40px;
    min-height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 1rem;
  }
  html body #pf-block-add,
  html body #pf-save,
  html body #pf-reload,
  html body #pf-pw-save { min-height: 44px; }
}

/* ===== DEFG-FIX: verify-D punch items ===== */
@media (max-width: 640.98px) {
  /* Viewings row: gutter between time and client name */
  html body #viewings-container .vw-time { padding-right: .6rem !important; }
  /* Dropdown menu items comfortable to tap */
  html body #tab-content .dropdown-item { min-height: 40px; display: flex; align-items: center; }
  /* Profile add-block overlay behaves like the app's bottom sheets */
  html body .pf-modal { align-items: flex-end !important; padding: 0 !important; }
  html body .pf-modal .pf-mcard { max-width: 100% !important; border-radius: 16px 16px 0 0 !important; margin: 0 !important; max-height: 94dvh; overflow-y: auto; }
  /* Profile day chips to a comfortable tap size */
  html body .pf-daychip { min-height: 36px; display: inline-flex; align-items: center; }
}
/* ===== H: ADMIN ===== */
/*
 * Enigma mobile restyle — Batch H (admin surfaces).
 *
 * Scope: lead-detail cockpit stacking, Property Updates card layout, and the
 * admin calendar/profile pickers. EVERY rule below lives inside a media query
 * scoped to the phone layer (max-width: 767.98px), so desktop (>=768px, and
 * therefore the >=992px desktop the spec protects) renders BYTE-IDENTICAL.
 *
 * The 767.98px breakpoint is deliberate: it matches the matchMedia
 * '(max-width: 767.98px)' guard in modules/updates.html (renderUpdates) and the
 * <768px stacking called for in the Batch H work items, so the CSS layout and
 * the JS render path always agree about what "phone" means.
 *
 * Selectors are `html body`-prefixed with pragmatic !important because module
 * <style> blocks + inline styles inject later in DOM order (see spec: cascade
 * trap) — this is an override sheet. Deploy concatenates css/mobile-h.css onto
 * the batch-ordered css/mobile.css.
 */

/* ============================================================
 *  PHONE LAYER  (<= 767.98px)  — primary targets 360 / 390 / 412 / 768
 * ============================================================ */
@media (max-width: 767.98px) {

  /* ------------------------------------------------------------------
   * 1) LEAD-DETAIL COCKPIT — stack the two panes (P1: right pane -> 0px).
   *    Desktop is a 2-column d-flex (left context 320px + right timeline/
   *    composer flex:1). In ~302px of phone width the right pane collapses to
   *    0px: timeline = colour slivers, composer textarea ~1 char/line, Send
   *    off-canvas. On phones we stack: context pane first, full-width, then a
   *    bounded-height timeline, then a full-width composer with Send reachable.
   *    Hooks .lead-cockpit / .lead-pane-left / .lead-pane-main are stamped by
   *    js/lead-detail-tab.js (buildHtml); they carry no desktop styling.
   * ------------------------------------------------------------------ */
  html body .lead-cockpit {
    flex-direction: column !important;   /* was row */
    height: auto !important;             /* was calc(100vh - 160px) */
    min-height: 0 !important;            /* was 480px */
  }

  /* Left context pane: full width, flow all content (no clip), sits on top. */
  html body .lead-cockpit > .lead-pane-left {
    flex: 0 0 auto !important;           /* was 0 0 320px */
    max-width: none !important;          /* was 340px */
    width: 100% !important;
    overflow: visible !important;        /* was hidden */
    border-right: 0 !important;          /* border-end is meaningless when stacked */
    border-bottom: 1px solid rgba(0, 0, 0, 0.12) !important;
  }
  /* Its inner scroller (style="height:100%;overflow-y:auto") must flow, not clip. */
  html body .lead-cockpit > .lead-pane-left > div {
    height: auto !important;
    overflow: visible !important;
  }

  /* Right pane: full width. */
  html body .lead-cockpit > .lead-pane-main {
    flex: 1 1 auto !important;
    width: 100% !important;
    min-width: 0 !important;
  }

  /* Timeline: a bounded scroll region so the composer below stays reachable
     (the column is now height:auto, so without this the timeline would run to
     full content height and push Send far down / off the reading flow). */
  html body .lead-cockpit [data-lead-scroll] {
    max-height: 55vh !important;
    overflow-y: auto !important;
    -webkit-overflow-scrolling: touch !important;
  }

  /* Composer: full-width stacked textarea + Send (was a squeezed input-group). */
  html body .lead-cockpit .input-group {
    flex-wrap: wrap !important;
  }
  html body .lead-cockpit .input-group > textarea[data-lead-fld="composer"] {
    flex: 1 1 100% !important;
    width: 100% !important;
    min-height: 96px !important;         /* ~4-5 lines (was rows=3 squeezed to ~16px wide) */
    font-size: 16px !important;          /* prevents iOS input zoom */
    border-radius: 8px !important;
  }
  html body .lead-cockpit .input-group > .btn[data-lead-act="send"] {
    flex: 1 1 100% !important;
    width: 100% !important;
    min-height: 44px !important;
    margin: 6px 0 0 0 !important;        /* clear Bootstrap's input-group negative margin */
    border-radius: 8px !important;
  }


  /* ------------------------------------------------------------------
   * 2) PROPERTY UPDATES — mobile card layout (rendered by
   *    updates.html renderUpdatesCards; the desktop table is untouched).
   *    Photo strip on top, ref + location header, each update line with the
   *    NOTE prominent, flags, and a 44px action row.
   * ------------------------------------------------------------------ */

  /* Trim the module's own nested container so cards run near full-bleed. */
  html body #property-updates-content > .container-fluid {
    padding-left: 8px !important;
    padding-right: 8px !important;
  }
  html body .upd-cards {
    padding: 4px !important;
  }

  html body .upd-card {
    border: 1px solid rgba(0, 0, 0, 0.12) !important;
    border-radius: 12px !important;
    background: #fff !important;
    box-shadow: var(--shadow-sm) !important;
    overflow: hidden !important;         /* clip the photo strip to the radius */
    margin-bottom: 12px !important;
  }
  html body .upd-card:last-child { margin-bottom: 0 !important; }

  /* Photo strip — override the inline 96x72 the enrichment paints. */
  html body .upd-card .upd-card-photo {
    display: block !important;
    width: 100% !important;
  }
  html body .upd-card .upd-card-photo .upd-card-photo-ph {
    width: 100% !important;
    height: auto !important;
    aspect-ratio: 3 / 2 !important;
    max-height: 220px !important;
    background: #e9ecef !important;
  }
  html body .upd-card .upd-card-photo img {
    display: block !important;
    width: 100% !important;
    /* Harmonised 2026-07-21 with the .prop-thumb card hero (Section I) so every
       property photo in Enigma reads at the same 3:2 ratio on a phone. Was a
       fixed 150px, i.e. a shallower ~2:1 crop than every other surface. */
    height: auto !important;
    aspect-ratio: 3 / 2 !important;
    max-height: 220px !important;
    object-fit: cover !important;
    border-radius: 0 !important;         /* .upd-card clips the corners */
  }

  html body .upd-card .upd-card-body {
    padding: 12px !important;
  }

  /* Header: ref (title) · invisible badge · location. */
  html body .upd-card .upd-card-head {
    display: flex !important;
    flex-wrap: wrap !important;
    align-items: baseline !important;
    gap: 4px 10px !important;
    margin-bottom: 8px !important;
  }
  html body .upd-card .upd-card-ref {
    font-size: 16px !important;
    font-weight: 700 !important;
  }
  html body .upd-card .upd-card-loc {
    font-size: 13px !important;
    color: #6c757d !important;
    margin-left: auto !important;        /* push location to the right of the header */
  }
  html body .upd-card .upd-card-loc small { font-size: 13px !important; }
  html body .upd-card .upd-invis .badge { vertical-align: middle !important; }

  /* Flags. */
  html body .upd-card .upd-card-flags {
    display: flex !important;
    flex-wrap: wrap !important;
    gap: 4px !important;
    margin-bottom: 8px !important;
  }
  html body .upd-card .upd-card-flags .badge { font-size: 12px !important; }

  /* Update lines — the NOTE is the point, so it gets the visual weight. */
  html body .upd-card .upd-card-lines { margin-bottom: 4px !important; }
  html body .upd-card .upd-line {
    padding: 8px 0 !important;
    border-top: 1px solid rgba(0, 0, 0, 0.06) !important;
  }
  html body .upd-card .upd-card-lines > .upd-line:first-child {
    border-top: 0 !important;
    padding-top: 0 !important;
  }
  html body .upd-card .upd-line-meta {
    font-size: 12px !important;
    color: #6c757d !important;
    margin-bottom: 3px !important;
  }
  html body .upd-card .upd-line-note {
    font-size: 15px !important;
    line-height: 1.4 !important;
    color: #212529 !important;
    white-space: pre-wrap !important;
    word-break: break-word !important;
  }

  /* Actions — full-width wrapping row of 44px canon outline buttons. */
  html body .upd-card .upd-card-actions {
    display: flex !important;
    flex-wrap: wrap !important;
    gap: 8px !important;
    padding-top: 10px !important;
    margin-top: 6px !important;
    border-top: 1px solid rgba(0, 0, 0, 0.08) !important;
  }
  /* Scoped under #updates-list (an id) so this out-specifies Batch A's generic
     `#tab-content .btn-sm` rule and the 44px app-standard tap target holds. */
  html body #updates-list .upd-card .upd-card-actions .btn {
    flex: 1 1 auto !important;
    min-width: calc(50% - 4px) !important;
    min-height: 44px !important;
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    gap: 6px !important;
    white-space: nowrap !important;
    margin: 0 !important;
  }


  /* ------------------------------------------------------------------
   * 3) ADMIN PICKERS — calendar agent-picker + profile user-picker >=44px.
   *    #cal-user is a form-select-sm (renders ~31px) with an inline width:auto;
   *    give it a proper touch height without forcing its width. #pf-userpick /
   *    #pf-access are the profile "edit another user" selects.
   * ------------------------------------------------------------------ */
  html body #cal-user,
  html body #pf-userpick,
  html body #pf-access {
    min-height: 44px !important;
    font-size: 16px !important;          /* also prevents iOS zoom on focus */
  }
}

/* ===== FINAL-FIX: remaining sub-44px tap targets (final QA sweep) ===== */
@media (max-width: 640.98px) {
  /* Yes/No/Don't-care segmented filter toggles (search panes) */
  html body #tab-content .btn-group .btn,
  html body #tab-content .btn-group-sm .btn { min-height: 40px !important; }
  /* Header action buttons that ride custom markup (Edit BR, End viewing/Summary) */
  html body #tab-content .card-header .btn,
  html body #tab-content h5 + .btn, html body #tab-content .btn-sm.btn-outline-primary { min-height: 42px; }
  /* Inline btn-link actions get a real hit area without changing their look */
  html body #tab-content .btn-link.btn-sm, html body #tab-content .btn-link { min-height: 40px; display: inline-flex; align-items: center; }
  /* Modal close X */
  html body .modal .btn-close { min-width: 40px; min-height: 40px; background-size: 14px; }
}

/* ===== FINAL-FIX2: last polish (design judge + final verify) ===== */
@media (max-width: 640.98px) {
  /* BR view header Edit BR button */
  html body #tab-content .br-view-edit { min-height: 44px !important; }
  /* Leads list: the three per-card chips become real tap targets, dates never break mid-string */
  html body #tab-content .lead-row .btn-sm,
  html body #tab-content .lead-row .badge[data-lead-act] { min-height: 38px !important; display: inline-flex; align-items: center; }
  html body #tab-content .lead-row .text-muted { overflow-wrap: normal; }
  html body #tab-content .lead-row .text-muted time,
  html body #tab-content .lead-row [data-ldt-date] { white-space: nowrap; }
}

/* ===== I: BR VIEW (read-only Buyer View rebuild) ===== */
/* All selectors scoped under .br-view — a root class rendered only by
   BRDetailsComponent's read-only view. brv-* classes exist nowhere else,
   so the base block cannot affect any other screen at any width. */

/* --- base (all widths): new-component styling only --- */
html body .br-view { max-width: 1080px; margin: 0 auto; }

html body .br-view .brv-head {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 8px 12px; margin-bottom: 1rem;
}
html body .br-view .brv-head-main { min-width: 0; }
html body .br-view .brv-name {
  margin: 0; font-size: 1.35rem; font-weight: 700; color: #1e3a5f;
  overflow-wrap: break-word;
}
html body .br-view .brv-meta { font-size: 12px; color: #6c757d; margin-top: 2px; }
html body .br-view .br-view-edit {
  margin-left: auto; min-height: 44px;
  display: inline-flex; align-items: center; white-space: nowrap;
}

html body .br-view .brv-grade {
  display: inline-flex; align-items: center;
  padding: 4px 12px; border-radius: 12px; border: 1px solid #b6d4fe;
  background: #e7f1ff; color: #1e3a5f;
  font-size: 12px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
}
html body .br-view .brv-grade[data-grade="Gold"]   { background:#fdf3d0; border-color:#e6d28a; color:#7a5c00; }
html body .br-view .brv-grade[data-grade="Silver"] { background:#f1f3f5; border-color:#ced4da; color:#495057; }
html body .br-view .brv-grade[data-grade="Bronze"] { background:#f6e8dc; border-color:#dcbfa4; color:#7a4a1f; }
html body .br-view .brv-grade[data-grade="Bought"] { background:#d1e7dd; border-color:#a3cfbb; color:#146c43; }
html body .br-view .brv-grade[data-grade="Removed"],
html body .br-view .brv-grade[data-grade="Duplicate"] { background:#f8d7da; border-color:#ecacb2; color:#842029; }

/* field rows */
html body .br-view .brv-field { padding: 7px 0; }
html body .br-view .brv-field + .brv-field { border-top: 1px solid rgba(0,0,0,.05); }
html body .br-view .brv-label {
  font-size: 11px; font-weight: 600; letter-spacing: .05em;
  text-transform: uppercase; color: #6c757d; margin-bottom: 2px;
}
html body .br-view .brv-value { font-size: 14px; font-weight: 500; color: #212529; overflow-wrap: break-word; }
html body .br-view .brv-prewrap { white-space: pre-wrap; }
html body .br-view .brv-empty { color: #adb5bd; font-weight: 400; }
html body .br-view .brv-value--price { font-size: 1.3rem; font-weight: 700; color: #1e3a5f; line-height: 1.2; }
html body .br-view .brv-value--any { color: #6c757d; }
html body .br-view .brv-overdue { color: #b02a37; font-weight: 600; }

/* chips (self-contained clone of the .pf-chip look) */
html body .br-view .brv-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 2px; }
html body .br-view .brv-chip {
  display: inline-flex; align-items: center;
  background: #e7f1ff; border: 1px solid #b6d4fe; color: #1e3a5f;
  border-radius: 12px; padding: 3px 10px; font-size: 13px; line-height: 1.4;
}
html body .br-view .brv-chip--all { background: #f1f3f5; border-color: #dee2e6; color: #495057; }
html body .br-view .brv-chip--hidden { display: none; }
html body .br-view .brv-chip--more {
  cursor: pointer; min-height: 38px; padding: 3px 14px;
  background: #fff; border: 1px dashed #4299e1; color: #4299e1; font-weight: 600;
}

/* flags */
html body .br-view .brv-flags { display: flex; flex-wrap: wrap; gap: 6px; padding-top: 8px; }
html body .br-view .brv-field + .brv-flags,
html body .br-view .brv-flags:not(:first-child) { border-top: 1px solid rgba(0,0,0,.05); margin-top: 4px; }
html body .br-view .brv-flag {
  display: inline-flex; align-items: center; gap: 5px;
  background: #d1e7dd; border: 1px solid #a3cfbb; color: #146c43;
  border-radius: 12px; padding: 4px 11px; font-size: 13px; font-weight: 600;
}
html body .br-view .brv-flag i { font-size: 11px; }
html body .br-view .brv-noflags { font-size: 13px; padding-top: 8px; }

/* notes */
html body .br-view .brv-note {
  background: #fff; border: 1px solid #e9ecef;
  border-radius: 8px; padding: 10px 12px; margin-bottom: 10px;
}
html body .br-view .brv-note:last-child { margin-bottom: 0; }
html body .br-view .brv-note-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px;
  font-size: 12px; color: #6c757d; margin-bottom: 4px;
}
html body .br-view .brv-note-src {
  background: #e7f1ff; border: 1px solid #b6d4fe; color: #1e3a5f;
  border-radius: 10px; padding: 1px 8px; font-size: 11px; font-weight: 600;
}
html body .br-view .brv-note-title { font-size: 14px; font-weight: 600; margin-bottom: 3px; }
html body .br-view .brv-note-body { font-size: 14px; white-space: pre-wrap; overflow-wrap: break-word; }
html body .br-view .brv-kv {
  display: grid; grid-template-columns: minmax(110px, 150px) 1fr;
  gap: 3px 12px; white-space: normal;
}
html body .br-view .brv-kv-label {
  font-size: 12px; font-weight: 600; color: #6c757d; padding-top: 1px;
}
html body .br-view .brv-kv-val { font-size: 14px; min-width: 0; overflow-wrap: anywhere; }

/* --- phone layer (matches the app's phone breakpoint) --- */
@media (max-width: 640.98px) {
  html body .br-view .brv-name { font-size: 1.15rem; }
  /* Edit BR becomes a full-width primary action row under name + badge */
  html body .br-view .br-view-edit {
    flex: 1 1 100%; margin-left: 0; justify-content: center;
  }
  /* brand canon: 12px card radius on mobile for this view's cards */
  html body .br-view .card { border-radius: 12px; }
  html body .br-view .card .card-header { border-radius: 12px 12px 0 0; }
}

/* --- desktop polish (>=992px): a touch more breathing room --- */
@media (min-width: 992px) {
  html body .br-view .brv-card .card-body { padding: 1rem 1.25rem; }
}

/* ===== J: LP — GROUPS POPUP PICKER (locality wall-buster) ===== */
/* Scoped under .fulcrum-multigroups.lp-on (resting state) and .lp-modal
   (the sheet). lp-* classes exist nowhere else in the codebase. The legacy
   .multicheckbox wall is only restyled INSIDE .lp-modal — un-enhanced
   groups fields (e.g. property Type) render byte-identical. */

/* --- collapsed (resting) state --- */
html body .fulcrum-multigroups.lp-on .lp-collapsed {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  margin-bottom: .5rem;
}
html body .fulcrum-multigroups.lp-on .lp-chips {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
}
html body .fulcrum-multigroups.lp-on .lp-chip {
  display: inline-flex; align-items: center; gap: 2px;
  background: #e7f1ff; border: 1px solid #b6d4fe; color: #1e3a5f;
  border-radius: 12px; padding: 3px 6px 3px 10px;
  font-size: 13px; line-height: 1.4; min-height: 32px;
}
html body .fulcrum-multigroups.lp-on .lp-chip--all {
  background: #f1f3f5; border-color: #dee2e6; color: #495057; padding: 3px 12px;
}
html body .fulcrum-multigroups.lp-on .lp-chip--hidden { display: none; }
html body .fulcrum-multigroups.lp-on .lp-chip-x {
  border: 0; background: none; color: #1e3a5f; font-size: 16px; line-height: 1;
  padding: 0; min-width: 28px; min-height: 28px; cursor: pointer;
  border-radius: 50%; display: inline-flex; align-items: center; justify-content: center;
}
html body .fulcrum-multigroups.lp-on .lp-chip-x:hover { background: rgba(30,58,95,.08); }
html body .fulcrum-multigroups.lp-on .lp-add,
html body .fulcrum-multigroups.lp-on .lp-more {
  display: inline-flex; align-items: center; gap: 4px; cursor: pointer;
  background: #fff; border: 1px dashed #4299e1; color: #4299e1;
  border-radius: 12px; font-size: 13px; font-weight: 600;
}
html body .fulcrum-multigroups.lp-on .lp-add { min-height: 44px; padding: 6px 14px; }
html body .fulcrum-multigroups.lp-on .lp-more { min-height: 32px; padding: 3px 12px; }

/* --- modal / sheet --- */
html body .lp-modal {
  display: none; position: fixed; inset: 0; background: rgba(0,0,0,.5);
  z-index: 2050; align-items: flex-start; justify-content: center;
  overflow: auto; padding: 4vh 12px;
}
html body .lp-modal.lp-open { display: flex; }
html body .lp-modal .lp-sheet {
  background: var(--bs-body-bg, #fff); border-radius: 12px;
  max-width: 560px; width: 100%; margin: auto;
  box-shadow: 0 8px 30px rgba(0,0,0,.3);
  display: flex; flex-direction: column; max-height: 88vh;
  padding: 14px 16px;
}
html body .lp-modal .lp-head {
  display: flex; align-items: center; gap: 10px; margin-bottom: 10px; flex: none;
}
html body .lp-modal .lp-title { font-weight: 700; font-size: 1.05rem; color: #1e3a5f; }
html body .lp-modal .lp-count { font-weight: 400; color: #6c757d; font-size: .85rem; }
html body .lp-modal .lp-done { margin-left: auto; min-height: 44px; min-width: 88px; }
html body .lp-modal .lp-filter { flex: none; margin-bottom: 8px; min-height: 44px; }
html body .lp-modal .lp-quick { flex: none; margin-bottom: 8px; }
html body .lp-modal .lp-quick select.groupselect {
  margin-bottom: 2px !important;   /* neutralise the legacy mb-2 */
  min-height: 44px;
}
html body .lp-modal .lp-quick-hint { font-size: 11px; color: #6c757d; }
html body .lp-modal .lp-body {
  flex: 1 1 auto; overflow-y: auto; -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  border: 1px solid #dee2e6; border-radius: 8px; padding: 8px;
  background: rgba(0,0,0,.02);
}
html body .lp-modal .lp-noresults { color: #6c757d; font-size: .9rem; padding: 10px 6px; }

/* grouped sections (clone of profile's .pf-grp look) */
html body .lp-modal .lp-grp { margin-bottom: 6px; }
html body .lp-modal .lp-grp > summary {
  cursor: pointer; font-weight: 600; padding: 6px 4px; list-style: none;
  min-height: 44px; display: flex; align-items: center; gap: 6px;
}
html body .lp-modal .lp-grp > summary::-webkit-details-marker { display: none; }
html body .lp-modal .lp-grp > summary:before { content: "\25B8"; color: #888; }
html body .lp-modal .lp-grp[open] > summary:before { content: "\25BE"; }
html body .lp-modal .lp-gcount { font-weight: 400; color: #6c757d; font-size: .85rem; }
html body .lp-modal .lp-pills {
  display: flex; flex-wrap: wrap; gap: 6px; padding: 2px 2px 10px 18px;
}

/* restyle the EXISTING wall badges inside the sheet only.
   State carriers stay Bootstrap's btn-outline-secondary / btn-primary,
   toggled by the untouched legacy JS. */
html body .lp-modal .multicheckbox { display: block; }  /* defeats d-flex flex-wrap */
html body .lp-modal .form-check-option { display: inline-flex; }
html body .lp-modal .form-check-option.lp-hide { display: none; }
html body .lp-modal .option-badge {
  display: inline-flex; align-items: center; margin: 0;
  border-radius: 14px; font-size: .85rem; min-height: 40px; padding: 4px 12px;
  background: #fff; border: 1px solid #ced4da; color: #333;
}
html body .lp-modal .option-badge:hover { border-color: #0d6efd; color: #0d6efd; }
html body .lp-modal .option-badge.btn-primary,
html body .lp-modal .option-badge.btn-primary:hover {
  background: #0d6efd; border-color: #0d6efd; color: #fff;
}

/* entry animation (respect reduced motion) */
@media (prefers-reduced-motion: no-preference) {
  html body .lp-modal.lp-open .lp-sheet { animation: lpSheetIn .16s ease-out; }
}
@keyframes lpSheetIn {
  from { transform: translateY(24px); opacity: .6; }
  to   { transform: none; opacity: 1; }
}

/* --- phone layer: bottom sheet (app convention, cf. .pf-modal overrides) --- */
@media (max-width: 640.98px) {
  html body .lp-modal { align-items: flex-end; padding: 0; }
  html body .lp-modal .lp-sheet {
    max-width: 100%; margin: 0; border-radius: 16px 16px 0 0;
    max-height: 92dvh;
    padding: 12px 14px calc(12px + env(safe-area-inset-bottom));
  }
  html body .lp-modal .option-badge { min-height: 44px; }
  html body .fulcrum-multigroups.lp-on .lp-chip { min-height: 36px; }
  html body .fulcrum-multigroups.lp-on .lp-chip-x { min-width: 32px; min-height: 32px; }
  html body .fulcrum-multigroups.lp-on .lp-more { min-height: 40px; }
}

/* ==========================================================================
   SECTION I — PROPERTY THUMBNAILS  (AREA E, 2026-07-21)
   --------------------------------------------------------------------------
   ⚠️ DELIBERATE EXCEPTION to this sheet's "every rule is media-scoped <992px"
   convention. `.prop-thumb` is a BRAND-NEW class: the server has emitted it
   from properties.php::inputrender_propthumb since the Matches tab shipped,
   but it had NEVER been styled anywhere in obdash — so the thumbnails were
   rendering at their raw intrinsic size with no crop, radius or aspect lock.
   Nothing else in the app uses this class, so an unscoped rule here cannot
   regress any existing desktop styling. It lives in mobile.css purely because
   mobile.css is the ONLY obdash stylesheet carrying a ?v= cache-buster
   (core-styles.php has none, so a rule added there would be served stale).
   The phone card-hero override further down is the media-scoped part.

   Vince, 7 Jul: the thumbnails shipped at 100x80 and he immediately asked for
   them to be BIGGER. Rendered box is 150x110; the image is FETCHED at
   300x220c (properties.php ENIGMA_THUMB_SIZE) so it stays crisp on retina.
   ========================================================================== */
.prop-thumb {
  display: inline-block;
  line-height: 0;
}
.prop-thumb img {
  width: 150px;
  height: 110px;
  object-fit: cover;
  border-radius: 6px;
  display: block;
  background: #f1f3f5;   /* placeholder tint while the lazy image loads */
}
/* No-photo placeholder: hold the same footprint so rows don't jump height. */
.prop-thumb-empty {
  display: inline-block;
  width: 150px;
  height: 110px;
  border-radius: 6px;
  background: #f1f3f5;
}
/* Keep the thumbnail cell from being stretched by the table's column algorithm.
   ⚠️ MUST stay scoped to the table-layout regime (>=641px). Below 641px
   mobile-cards.js card-ifies the grid and sets this cell to `display:block`,
   where `width:1%` is no longer a table-column hint but a LITERAL 1% of the
   card width (~3px) — which collapsed the thumbnail to a 3x110px vertical
   sliver. That was the 2026-07-21 "thumbnails are very thin" defect. */
@media (min-width: 641px) {
  #tab-content table.table-hover td:has(> .prop-thumb) { width: 1%; }
}

/* --- tablet/light-desktop layer: trim the thumbnail so rows stay compact --- */
@media (max-width: 991.98px) and (min-width: 641px) {
  html body .prop-thumb img,
  html body .prop-thumb-empty { width: 120px; height: 88px; }
}

/* --- phone layer: the thumbnail becomes the card HERO ---------------------
   Keyed on `.prop-thumb` rather than on `.m-media`, deliberately: the cell is
   only tagged `.m-media` when mobile-cards.js sees an img at stamp time, and
   price-reductions fills its thumbnails in asynchronously AFTER that pass, so
   its cells keep their data-label and never become `.m-media`. Keying on the
   thumbnail class itself covers every surface either way.
   The hero is width-driven with an explicit aspect ratio + object-fit:cover:
   the base rule's fixed `height:110px` MUST be reset to `auto` here, or a
   full-width image keeps a 110px height and letterboxes. */
@media (max-width: 640.98px) {
  html body .m-cards > tbody > tr > td.m-media img { max-height: 220px; }
  html body .m-cards .prop-thumb {
    display: block;
    width: 100%;
  }
  html body .m-cards .prop-thumb img {
    width: 100%;
    height: auto;
    aspect-ratio: 3 / 2;
    max-height: 220px;
    object-fit: cover;
    border-radius: 8px;
  }
  /* A photo-less property: collapse the placeholder entirely on phones rather
     than spending 110px of card height on an empty grey rectangle. */
  html body .m-cards .prop-thumb-empty { display: none; }
}
