/**
 * css/agent-tablet.css — iPad layout system for the Royal LePage Turner
 * Realty AGENT backend (Mobile + iPad review, Part 2 / PR-5, 2026-09-17).
 *
 * Loaded fleet-wide (well, Gander-only — this backend is Gander-only) on
 * EVERY agent page, right after css/agent.css: Hub, Dashboard, Deals, CMA,
 * Registry, Market, Talking Points, Explaining the Market, Office, Document
 * Review. It is safe to load on every page even where a page's structural
 * work is deferred to a later PR (Deals' two-pane layout is PR-6, Document
 * Review's panes/verdict bar are PR-7) — everything in this file is either
 * a `pointer:coarse`/`hover:none` baseline (harmless everywhere) or scoped
 * to a specific page's real ids/classes, so it is a no-op on pages it
 * doesn't target.
 *
 * Tokens: same var()-with-literal-fallback pattern js/agent-shell.js and
 * css/agent.css already use (--bg #0a0a0a, --panel #18181b, --panel-2
 * #212126, --border #2a2a2e, --text-dim #a0a0a8, --accent #EA002A) — this
 * file does NOT assume css/agent.css is also loaded (agent/dashboard.html's
 * generator template does NOT load it; the dashboard defines its own
 * identical inline token set instead), so every custom property reference
 * below carries its own literal fallback.
 *
 * --navh: agent/dashboard.html's own inline script (setNavH(), 2026-08-20
 * mobile pass) already keeps `--navh` on <html> in sync with the live
 * AgentShell nav's real height, for its mobile sticky viewbar. No other
 * agent page sets this variable. Real measured .ash-nav height (2026-09-17,
 * headless probe against the real agent-shell.js + real fonts, both at
 * 768px and 1024px once the nav-wrap fix below is applied): 53px. Every
 * sticky-header rule below reads `var(--navh, 56px)` — the live value on
 * the Dashboard, a 3px-safe fallback everywhere else — so a sticky table
 * header never overlaps the nav (Convention: "a sticky header that
 * overlaps the nav is a real bug").
 */

/* ── Real pre-existing bug fix, required for the sticky-header math above
   to hold: .ash-nav (js/agent-shell.js) is `display:flex;flex-wrap:wrap`,
   and the flex line-breaking algorithm lays out .ash-links (flex:1 1 auto)
   using its CONTENT width, not its post-shrink width -- so at exactly
   768px the identity control ("Miketurner ▾") gets pushed onto a second
   line, doubling the nav's real height from 53px to 92px (confirmed via a
   headless probe against the real file, both before and after this fix).
   .ash-links already has min-width:0 and its own overflow-x:auto scroller
   built for exactly this squeeze -- flex-basis:0 makes the line-breaking
   algorithm size it as "0" instead of "full content", so the row always
   fits on one line and the existing horizontal-scroll affordance takes
   over instead of wrapping. CSS-only; js/agent-shell.js is untouched
   (PR-3 owns that file). !important matches this file's other override of
   JS-injected nav CSS below (the standalone safe-area padding) and the
   dashboard's own existing pattern (.mb-ctl{font-size:16px!important}). */
@media (min-width: 768px) {
  .ash-links { flex-basis: 0 !important; }
}

/* ══════════════════════════════════════════════════════════════════════
   1. Foundational rules — tap targets, hover-only cues, standalone hooks
   ══════════════════════════════════════════════════════════════════════ */

/* Every interactive element on an agent page gets a real touch target on
   a touch device, regardless of viewport width (a phone in one hand at a
   showing needs this exactly as much as an iPad). */
@media (pointer: coarse) {
  .ash-links a,
  .ash-idbtn,
  .viewbar button,
  .ag-tile,
  .dx-btn,
  .dx-chip,
  .chip,
  .reg-chip,
  .reg-linkbtn,
  th.sortable,
  table.rowlink tbody tr,
  button:not(.reg-clear),
  a.cma-btn,
  a.hub-btn,
  a.reg-btn,
  a[class*="btn"] {
    min-height: 44px;
  }
  .ash-links a,
  .dx-btn,
  .dx-chip,
  .chip,
  .reg-chip,
  th.sortable,
  button:not(.reg-clear) {
    display: inline-flex;
    align-items: center;
  }
  th.sortable { padding-top: 12px; padding-bottom: 12px; }
  /* iOS Safari auto-zooms on focus for any text input under 16px and never
     zooms back out -- and gives it a comfortable tap height. Excludes
     checkbox/radio/range/color, which must stay their native small size. */
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]),
  select,
  textarea {
    font-size: 16px;
    min-height: 40px;
  }
}

/* Hover-only affordances that convey real information get a persistent
   touch-visible equivalent (a background tint doubles as the affordance
   here, per this PR's own instructions). Scoped to the exact rules found
   by grepping :hover across css/agent.css, agent/office.html,
   agent/registry.html and agent/cma.html -- most hits there are decorative
   (a button darkening, a chip's border tinting) or already have a static,
   always-visible affordance (.cma-prior-card's "Use these details →" line,
   .ag-tile's "Open ... →" line) so are left alone; these two are the ones
   that lose real information (this row is the clickable target) on a
   device with no hover at all. */
@media (hover: none) {
  .reg-results li { position: relative; padding-right: 30px; }
  .reg-results li::after {
    content: "\203A"; /* › */
    position: absolute; right: 12px; top: 50%; transform: translateY(-50%);
    font-size: 20px; line-height: 1; color: var(--text-dim, #a0a0a8);
  }
  .reg-vtable .lookup { text-decoration: underline; }
}

/* Standalone-chrome hooks (inert until PR-3 merges and starts setting
   data-app-mode + registering the 56px tab bar -- CSS-only, no matching
   markup exists yet, so this is a documented no-op today). Exact contract
   PR-3 is building to: html[data-app-mode="standalone"], .ash-nav, 56px. */
html[data-app-mode="standalone"] .ash-nav {
  padding-top: env(safe-area-inset-top, 0);
}
html[data-app-mode="standalone"] body {
  padding-bottom: calc(56px + env(safe-area-inset-bottom, 0));
}

/* ══════════════════════════════════════════════════════════════════════
   2. Utility classes for this PR and later ones (PR-6 Deals, PR-7 Review)
   ══════════════════════════════════════════════════════════════════════ */

/* Generic scroll-wrap + sticky header, for any table not already covered
   by the dashboard's own .tblwrap mechanism (agent/dashboard.html wraps
   every .dash table in .tblwrap via JS at render time -- see §4 below,
   which targets .tblwrap directly rather than duplicating that JS). Apply
   .ag-tblwrap to a wrapping <div> around any other page's <table>. */
.ag-tblwrap {
  position: relative;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.ag-tblwrap thead th {
  position: sticky;
  top: var(--navh, 56px);
  z-index: 5;
  background: var(--panel, #18181b);
}
/* Sticky first column -- opt in with .ag-tblwrap--pin1 alongside
   .ag-tblwrap on the same wrapper. Solid background so scrolled content
   doesn't show through behind the pinned column. */
.ag-tblwrap--pin1 table thead th:first-child,
.ag-tblwrap--pin1 table tbody td:first-child,
.ag-tblwrap--pin1 thead th:first-child,
.ag-tblwrap--pin1 tbody td:first-child {
  position: sticky;
  left: 0;
  z-index: 4;
  background: var(--panel, #18181b);
}
.ag-tblwrap--pin1 thead th:first-child { z-index: 6; }

/* Opt-in responsive card-stacking for a <table class="stackable ag-stack">
   at the 768-1023 tablet tier only -- reuses the EXACT mechanism
   agent/dashboard.html's own table.stackable already uses at <=560px
   (tools/build-agent-dashboard.py TEMPLATE), just re-scoped to the
   ag-stack marker and the tablet width range instead of duplicating a
   second, drifting copy of the same idea. At 1024+, ag-stack tables fall
   through to the ordinary sticky-header table treatment instead (no
   stacking) -- deliberately NOT repeated in the >=1024 tier below. */
@media (min-width: 768px) and (max-width: 1023px) {
  table.stackable.ag-stack,
  table.stackable.ag-stack tbody,
  table.stackable.ag-stack tr,
  table.stackable.ag-stack td {
    display: block; width: 100%;
  }
  table.stackable.ag-stack thead { display: none; }
  table.stackable.ag-stack tr {
    border: 1px solid var(--border, #2a2a2e); border-radius: var(--r-sm, 6px);
    padding: 10px 12px; margin-bottom: 8px; background: var(--panel, #18181b);
  }
  table.stackable.ag-stack tr.me { border-color: var(--accent, #EA002A); }
  table.stackable.ag-stack td { border: none; padding: 2px 0; white-space: normal; }
  table.stackable.ag-stack td::before {
    content: attr(data-l); display: block; font-size: 11px; text-transform: uppercase;
    letter-spacing: .4px; color: var(--text-dim, #a0a0a8);
  }
  table.stackable.ag-stack td:empty::before { content: none; }
}

/* ══════════════════════════════════════════════════════════════════════
   3. Hub tier (agent/index.html)
   ══════════════════════════════════════════════════════════════════════ */
@media (min-width: 768px) and (max-width: 1023px) {
  .ag-tiles-grid { grid-template-columns: repeat(2, 1fr); }
  /* "today strip" -> 2x2, scoped to the Hub's own strip only (#hub-strip)
     so Office's/Deals' identical-looking .dd-strip, built by the same
     shared DealsDash.render() component, is unaffected -- neither of
     those pages' tiers in this PR ask for a 2x2 strip. */
  #hub-strip .dd-strip { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px 20px; }
  #hub-strip .dd-strip > div { padding: 2px 0; }
}
@media (min-width: 1024px) {
  .ag-tiles-grid { grid-template-columns: repeat(3, 1fr); }
}

/* ══════════════════════════════════════════════════════════════════════
   4. Dashboard tier (tools/build-agent-dashboard.py TEMPLATE + agent/dashboard.html)
   ══════════════════════════════════════════════════════════════════════ */

/* The sticky segmented-control viewbar was @media(max-width:768px)-only
   (tools/build-agent-dashboard.py TEMPLATE inline <style>) -- extend it to
   ALL widths >=768 instead of just below, so it's sticky on an iPad too. */
@media (min-width: 768px) {
  .viewbar {
    position: sticky;
    top: var(--navh, 56px);
    z-index: 30;
    background: var(--bg, #0a0a0a);
    padding: 2px 0;
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
}

/* Sticky header (+ pinned first column on the wide comparison tables) for
   every dashboard table, via the wrapper agent/dashboard.html's own
   wrapTables() already puts around every ".dash table" -- no markup
   changes needed here. Applies at BOTH tablet tiers per the plan (768-1023
   AND 1024+ all get sticky headers; only the 768-1023 tier additionally
   stacks the five drill-down tables below via .ag-stack's own media
   block, which wins on those five ids because it demotes them to
   display:block, taking them out of the table layout this rule targets). */
@media (min-width: 768px) {
  .dash .tblwrap { position: relative; }
  .dash .tblwrap thead th {
    position: sticky;
    top: var(--navh, 56px);
    z-index: 5;
    background: var(--bg, #0a0a0a);
  }
}
/* Pinned first column -- the wide side-by-side comparison tables named in
   this PR's brief (award/byyear/agent/frs-recon/fin-tables/agent-stale/
   agent-year), matched by :has() on the wrapper JS already builds around
   every table (Convention: iPad Safari 15.4+ supports :has(); on an older
   engine this is a no-op progressive enhancement, not a break -- the table
   still scrolls, it just doesn't pin its first column). */
@media (min-width: 768px) {
  .dash .tblwrap:has(#award-table) thead th:first-child,
  .dash .tblwrap:has(#award-table) tbody td:first-child,
  .dash .tblwrap:has(#byyear-table) thead th:first-child,
  .dash .tblwrap:has(#byyear-table) tbody td:first-child,
  .dash .tblwrap:has(#agent-table) thead th:first-child,
  .dash .tblwrap:has(#agent-table) tbody td:first-child,
  .dash .tblwrap:has(#frs-recon-table) thead th:first-child,
  .dash .tblwrap:has(#frs-recon-table) tbody td:first-child,
  .dash .tblwrap:has(#fin-bs-history-table) thead th:first-child,
  .dash .tblwrap:has(#fin-bs-history-table) tbody td:first-child,
  .dash .tblwrap:has(#fin-pl-history-table) thead th:first-child,
  .dash .tblwrap:has(#fin-pl-history-table) tbody td:first-child,
  .dash .tblwrap:has(#fin-expense-table) thead th:first-child,
  .dash .tblwrap:has(#fin-expense-table) tbody td:first-child,
  .dash .tblwrap:has(#agent-stale) thead th:first-child,
  .dash .tblwrap:has(#agent-stale) tbody td:first-child,
  .dash .tblwrap:has(#agent-year-table) thead th:first-child,
  .dash .tblwrap:has(#agent-year-table) tbody td:first-child {
    position: sticky; left: 0; z-index: 4; background: var(--bg, #0a0a0a);
  }
  .dash .tblwrap:has(#award-table) thead th:first-child,
  .dash .tblwrap:has(#byyear-table) thead th:first-child,
  .dash .tblwrap:has(#agent-table) thead th:first-child,
  .dash .tblwrap:has(#frs-recon-table) thead th:first-child,
  .dash .tblwrap:has(#fin-bs-history-table) thead th:first-child,
  .dash .tblwrap:has(#fin-pl-history-table) thead th:first-child,
  .dash .tblwrap:has(#fin-expense-table) thead th:first-child,
  .dash .tblwrap:has(#agent-stale) thead th:first-child,
  .dash .tblwrap:has(#agent-year-table) thead th:first-child {
    z-index: 6;
  }
}
/* The five wide "drill-down" tables card-stack at the tablet tier only
   (768-1023) -- .ag-stack is layered onto their EXISTING class="rowlink
   stackable" via id selector rather than an HTML edit, since they already
   carry .stackable and this file's own §2 rule keys off
   "table.stackable.ag-stack". At 1024+ this block does not apply, so they
   fall through to the ordinary sticky-header .tblwrap treatment above,
   matching "all 16 tables sticky-header" at that tier. */
@media (min-width: 768px) and (max-width: 1023px) {
  #pipeline-table.stackable,
  #coaching-goals-table.stackable,
  #coaching-velocity-table.stackable,
  #coaching-comp-table.stackable,
  #leads-byagent-table.stackable {
    display: block; width: 100%;
  }
  #pipeline-table.stackable tbody,
  #pipeline-table.stackable tr,
  #pipeline-table.stackable td,
  #coaching-goals-table.stackable tbody,
  #coaching-goals-table.stackable tr,
  #coaching-goals-table.stackable td,
  #coaching-velocity-table.stackable tbody,
  #coaching-velocity-table.stackable tr,
  #coaching-velocity-table.stackable td,
  #coaching-comp-table.stackable tbody,
  #coaching-comp-table.stackable tr,
  #coaching-comp-table.stackable td,
  #leads-byagent-table.stackable tbody,
  #leads-byagent-table.stackable tr,
  #leads-byagent-table.stackable td {
    display: block; width: 100%;
  }
  #pipeline-table.stackable thead,
  #coaching-goals-table.stackable thead,
  #coaching-velocity-table.stackable thead,
  #coaching-comp-table.stackable thead,
  #leads-byagent-table.stackable thead { display: none; }
  #pipeline-table.stackable tr,
  #coaching-goals-table.stackable tr,
  #coaching-velocity-table.stackable tr,
  #coaching-comp-table.stackable tr,
  #leads-byagent-table.stackable tr {
    border: 1px solid var(--border, #2a2a2e); border-radius: var(--r-sm, 6px);
    padding: 10px 12px; margin-bottom: 8px; background: var(--panel, #18181b);
  }
  #pipeline-table.stackable td,
  #coaching-goals-table.stackable td,
  #coaching-velocity-table.stackable td,
  #coaching-comp-table.stackable td,
  #leads-byagent-table.stackable td { border: none; padding: 2px 0; white-space: normal; }
  #pipeline-table.stackable td::before,
  #coaching-goals-table.stackable td::before,
  #coaching-velocity-table.stackable td::before,
  #coaching-comp-table.stackable td::before,
  #leads-byagent-table.stackable td::before {
    content: attr(data-l); display: block; font-size: 11px; text-transform: uppercase;
    letter-spacing: .4px; color: var(--text-dim, #a0a0a8);
  }
  #pipeline-table.stackable td:empty::before,
  #coaching-goals-table.stackable td:empty::before,
  #coaching-velocity-table.stackable td:empty::before,
  #coaching-comp-table.stackable td:empty::before,
  #leads-byagent-table.stackable td:empty::before { content: none; }
}
/* Master Today tab: .kpi-grid (agent/dashboard.html, line ~96) is already
   `display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr))`
   and .region-grid is already `repeat(auto-fit,minmax(280px,1fr))` -- both
   verified against the real file and already genuinely multi-column at
   both tablet tiers with no override needed here. */

/* ══════════════════════════════════════════════════════════════════════
   5. Office tier (agent/office.html + js/office.js) -- LAYOUT ONLY, no
   changes to js/office.js's data logic. Of the five boards, only Ready to
   file (#ox-ready), Waiting on the cheque (#ox-blocked) and Closing
   readiness (#ox-readiness) actually render a repeated list of .ox-row
   cards (closeoutRow()/readinessRow() in js/office.js) -- Needs review
   (#ox-review) always renders exactly one summary line + a button, and
   Money path (#ox-money) renders grouped exception lists (.ox-group >
   .ox-item-row), neither of which is a repeating-card board. Gridding
   those two would just shrink a single full-width message for no benefit,
   so this PR grids the three boards that are actually card lists and
   leaves the other two full-width (this is a real deviation from the
   plan's "each board's row list becomes a responsive card grid" -- verify
   the real js/office.js render functions before assuming all five match). */
@media (min-width: 768px) and (max-width: 1023px) {
  #ox-ready, #ox-blocked, #ox-readiness {
    display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; align-items: start;
  }
}
@media (min-width: 1024px) {
  #ox-ready, #ox-blocked, #ox-readiness {
    display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; align-items: start;
  }
}
@media (min-width: 768px) {
  /* Card treatment for a gridded .ox-row -- was a border-bottom-only list
     row, needs a real card outline once it's sitting beside its siblings
     instead of stacked above/below them. */
  #ox-ready .ox-row, #ox-blocked .ox-row, #ox-readiness .ox-row {
    border: 1px solid var(--border, #2a2a2e);
    border-radius: var(--r, 8px); background: var(--panel, #18181b);
    padding: 12px 14px; margin: 0;
  }
}

/* PR-8 (2026-09-17, plan Part 2 B2): the four new boards -- Intake/Drafts/FUB
   reviews/Mail review -- are ALL repeating-card lists (intakeRow()/draftRow()/
   fubRow()/mailRow() in js/office.js, all `.ox-row`), so the same 2-up/3-up
   grid + card treatment applies verbatim, no separate rule needed for each. */
@media (min-width: 768px) and (max-width: 1023px) {
  #ox-intake, #ox-drafts, #ox-fub, #ox-mail {
    display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; align-items: start;
  }
}
@media (min-width: 1024px) {
  #ox-intake, #ox-drafts, #ox-fub, #ox-mail {
    display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; align-items: start;
  }
}
@media (min-width: 768px) {
  #ox-intake .ox-row, #ox-drafts .ox-row, #ox-fub .ox-row, #ox-mail .ox-row {
    border: 1px solid var(--border, #2a2a2e);
    border-radius: var(--r, 8px); background: var(--panel, #18181b);
    padding: 12px 14px; margin: 0;
  }
}

/* ══════════════════════════════════════════════════════════════════════
   6. CMA / Registry tier
   ══════════════════════════════════════════════════════════════════════ */

/* Registry: the dynamically-built .reg-tbl tables (parcel history / survey
   / sales lists, built as raw HTML strings in agent/registry.html's own
   inline script) and the sales-search .reg-vtable-wrap both get sticky
   headers. .reg-tbl tables are deliberately NOT re-wrapped in a new
   .ag-tblwrap <div> here -- they already sit inside .reg-sheet, which
   itself never overflows sideways at this page's 920px max-width for the
   Date/Type/Price/From-To column sets these tables actually use, so a new
   wrapper would add risk (touching 5 separate string-concatenation call
   sites) for no visible benefit; the sticky-header behavior alone is
   applied directly by table selector instead. */
@media (min-width: 768px) {
  .reg-tbl thead th {
    position: sticky; top: var(--navh, 56px); z-index: 5;
    background: var(--panel, #18181b);
  }
  .reg-vtable-wrap { position: relative; }
  .reg-vtable-wrap .reg-vtable thead th {
    position: sticky; top: var(--navh, 56px); z-index: 5;
    background: var(--panel, #18181b);
  }
}

/* CMA: #cma-adj-tbl already sits inside its own .cma-adj-wrap{overflow-x:auto} */
@media (min-width: 768px) {
  .cma-adj-wrap { position: relative; }
  .cma-adj-wrap .cma-adj-tbl thead th {
    position: sticky; top: var(--navh, 56px); z-index: 5;
    background: var(--panel, #18181b);
  }
}

/* CMA wizard: single column at 768-1023 (the default -- no rule needed),
   two columns (search/comps ∣ confirm form/adjustments) at 1024+. Both
   #cma-step-subject and #cma-step-comps already contain exactly two
   sibling .cma-card blocks each (search+prior-history card, then the
   confirm-details form card; candidates grid card, then the adjustments
   card) -- gridding the step container puts them side by side with no
   markup change. The hidden card (display:none until its data is ready)
   simply leaves the other one spanning alone until then. */
@media (min-width: 1024px) {
  #cma-step-subject, #cma-step-comps {
    display: grid; grid-template-columns: 1fr 1fr; gap: 18px; align-items: start;
  }
}

/* ══════════════════════════════════════════════════════════════════════
   Deals two-pane tier (PR-6, A3 tier table: "list rail + detail").
   .dx-btn/.dx-chip tap-target sizing is already covered by the fleet-wide
   pointer:coarse rule in Section 1 above (44px, supersedes this PR's
   original narrower 40px) -- only .dx-item-assign/.dx-pf-hit are new here.
   ══════════════════════════════════════════════════════════════════════ */
@media (pointer: coarse) {
  .dx-item-assign, .dx-pf-hit { min-height: 32px; }
}

@media (min-width: 768px) {
  .dx-wrap.dx-split {
    max-width: none;
    display: grid;
    grid-template-columns: 320px 1fr;
    align-items: start;
    gap: 22px;
    padding-left: 20px;
    padding-right: 20px;
  }
  .dx-wrap.dx-split #view-list {
    position: sticky;
    top: 14px;
    max-height: calc(100vh - 28px);
    overflow-y: auto;
    padding-right: 4px;
  }
  /* the split list keeps its own toolbar/chips; the photo-card grid collapses
     to one column in the narrower rail rather than the auto-fill 300px cards
     used at full width. */
  .dx-wrap.dx-split #dx-list.dx-grid { grid-template-columns: 1fr; }
  .dx-wrap.dx-split #view-detail,
  .dx-wrap.dx-split #view-review,
  .dx-wrap.dx-split #view-person { min-width: 0; }
  /* "All deals" back-links are redundant once the list is already visible
     as the rail. */
  .dx-split #dx-back, .dx-split #dx-review-back, .dx-split #dx-person-back { display: none; }
}
@media (min-width: 1024px) {
  .dx-wrap.dx-split { grid-template-columns: 360px 1fr; }
  .dx-wrap.dx-split #view-detail,
  .dx-wrap.dx-split #view-review,
  .dx-wrap.dx-split #view-person { max-width: 900px; }
}
