/* css/22b-safe-viewport.css — pass 23 (client, verbatim):

     "In the actual vehicle the full screen sometimes has a scrolling to it.
      Maybe you need to consider the native elements like top bar and bottom bar
      somehow on many screens including the inspection complete screen, that
      there is a scroller."

   TWO FAULTS, MEASURED, NOT GUESSED (Playwright, the three supported viewports
   and three reduced heights standing in for the vehicle browser's chrome):

   1. THE APP WAS SIZED TO A VIEWPORT IT DOES NOT HAVE.
      Every full-screen layer was `height:100%` / `position:fixed;inset:0`, both
      of which resolve against the initial containing block — the LARGE viewport
      on any browser that hides its toolbars on scroll. With the vehicle's top
      and bottom bars showing, the page was taller than the visible area, and
      `html,body{overflow:hidden}` meant the strip underneath them could not be
      scrolled to. That is the "scrolling" the client is seeing: the page really
      is longer than the screen, and the app refuses to let him reach the end.
      Answer: `100dvh` on the root and on every fixed layer (css/01 + §1 below),
      and env(safe-area-inset-*) — read once in css/01, composed here — so the
      brand rail, the dock and every screen gutter clear the native chrome.
      A browser reporting no insets gets 0px and today's pixels exactly.

   2. THREE SCREENS HAD NO SCROLLER AT ALL, so losing height did not compress
      them, it AMPUTATED them. Measured before/after in the pass report; the
      headline numbers:
        · Verify stage (#vStage) — 640x604 already lost the evidence plate and
          the locator (134 px, no scroller); at 640x484 it lost the Verified /
          Escalate / Add-to-visit-list row itself (254 px). The three decisions
          the whole module exists for were off the screen with no way back.
        · Inspection complete (#end) — landscape ≥901 never scrolled: the band
          was `flex:1 1 auto;min-height:0`, so at 1280x484 the merged KPI list
          was crushed to 44 px of scrollport for 395 px of rows (one row of
          eight) and the sector map was clipped 26 px.
        · #review — the list foot ("Leave n undecided" + its hint) was clipped
          by .rvw-listpanel's 26vh cap at 640x516 and below.

   THE AFFORDANCE. The codebase already has one shared "there is more" treatment
   — .scrollmore (bottom clearance + a 30 px fade toggled by scrollMoreSync()
   in index.html, styled in css/22) — and it is REUSED, not duplicated: every
   list that already carried it still does. It is deliberately NOT added to the
   two scrollers below, because both end in a PINNED action row and .scrollmore's
   mask would fade exactly the control that must never fade. Those two get the
   other half of the same idea, the one css/20 and css/21 already use on .sumfoot
   at the narrow breakpoints: the action row is `position:sticky;bottom:0` over a
   gradient, so it is always on screen and the content scrolls under it.

   CASCADE POSITION. After 22-layout-corrections (whose .scrollmore padding and
   Home-as-view compaction this must not fight) and after 20/21, because it
   corrects rules those two set at the narrow breakpoints — and before
   23-motion-policy, which stays where it is. Breakpoint-specific corrections are
   restated inside their own media query here rather than leaking to every width.
*/

/* =====================================================================
   1. EVERY FULL-SCREEN LAYER IS THE VISIBLE VIEWPORT, NOT THE TALL ONE
   `inset:0` leaves top, height and bottom all resolved, so the explicit
   height plus `bottom:auto` is what actually pins the layer to the screen
   the inspector is looking at.
   ===================================================================== */
#app,.overlay,#review,.calcveil,.dlg,.sheet,#edge{height:100dvh;bottom:auto}
/* these two start under the brand rail and run to the bottom of the screen */
#incSheet,#inboxSheet{top:var(--header-safe);height:calc(100dvh - var(--header-safe));bottom:auto}
/* the compiling veil's pulse is an inset:0 pseudo scaled to 1.06, which reported
   8 px of phantom page length on a layer that must never contribute any */
.calcveil{overflow:hidden}

/* =====================================================================
   2. THE FIXED CHROME CLEARS THE NATIVE BARS
   max() rather than calc() on the horizontal gutters: the inset replaces the
   designed gutter only when it is bigger than it, so nothing moves on a
   browser that reports none.
   ===================================================================== */
header{height:calc(var(--header-h) + var(--sa-t));padding-top:var(--sa-t);
  padding-left:max(16px,var(--sa-l));padding-right:max(16px,var(--sa-r))}
main{top:var(--header-safe);
  padding-left:max(20px,var(--sa-l));padding-right:max(20px,var(--sa-r))}
/* the floating dock lifts off the native bottom bar. layoutDockClearance() in
   index.html measures the dock's real rect, so --dock-clear — and with it
   main's padding-bottom and #start.asview's — follows this on its own. */
nav.dock{bottom:calc(12px + var(--sa-b))}
.toast{top:calc(var(--header-safe) + 8px)}
.sheet{padding-top:calc(var(--header-safe) + 8px)}
#incSheet .box,#inboxSheet .ilist{padding-bottom:calc(12px + var(--sa-b))}

@media (max-width:900px) and (orientation:landscape){
  header{padding-left:max(12px,var(--sa-l));padding-right:max(12px,var(--sa-r))}
  main{padding-left:max(10px,var(--sa-l));padding-right:max(10px,var(--sa-r))}
  .sheet{padding-top:calc(var(--header-safe) + 6px)}
}

/* =====================================================================
   3. HOME — the readiness card's own frame clears the chrome
   .startbody is already a .scrollmore scroller, so the task list needs
   nothing new; only the frame around it has to stop starting under the rail.
   The bottom is left alone on Home-as-view: #start.asview .startwrap
   (css/19) out-specifies this and is already measured off the dock.
   ===================================================================== */
.startwrap{padding-top:calc(22px + var(--header-safe));
  padding-left:max(22px,var(--sa-l));padding-right:max(22px,var(--sa-r));
  padding-bottom:max(22px,var(--sa-b))}
@media (max-width:900px) and (orientation:landscape){
  .startwrap{padding-top:calc(12px + var(--header-safe));
    padding-left:max(12px,var(--sa-l));padding-right:max(12px,var(--sa-r));
    padding-bottom:max(12px,var(--sa-b))}
}
@media (orientation:portrait){
  .startwrap{padding-top:calc(14px + var(--header-safe));
    padding-left:max(14px,var(--sa-l));padding-right:max(14px,var(--sa-r));
    padding-bottom:max(14px,var(--sa-b))}
}

/* =====================================================================
   4. VERIFY — the desk scrolls, the three decisions never leave the screen
   .vstage was a three-row grid inside a .panel with overflow:hidden. The
   middle row is minmax(0,1fr), so when the stage ran short it collapsed to
   zero and then the HEAD's own auto row pushed the decision row out through
   the clip: at 640x484 all three buttons were off screen with no scroller.
   It becomes a flex column scroller with a floor under the evidence/locator
   pair and the decision row stuck to the bottom edge.
   ===================================================================== */
.vstage{display:flex;flex-direction:column;gap:12px;
  overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain;
  scrollbar-width:none;-webkit-overflow-scrolling:touch;touch-action:pan-y;
  padding-bottom:0;
  /* the sticky decision row below covers the last ~70 px of the scrollport, so
     anything scrolled to the end would park UNDER it. scroll-padding is the
     property for exactly this — it tells every scroll (scrollIntoView, a
     keyboard page, focus) that the scrollport really ends 80 px higher.
     Measured: without it the evidence plate's centre landed under #vEscalate
     at both 640x604 and 640x484. */
  scroll-padding-bottom:80px}
.vstage::-webkit-scrollbar{display:none}
.vdhead{flex:0 0 auto}
/* The pair still GROWS into whatever the stage has spare (flex:1 1 auto) — it
   just may no longer be shrunk below the height its own content needs, which is
   what collapsed the evidence plate and then the locator to nothing. 230 px is
   the locator's real minimum (a 170 px map well plus its heading and its foot)
   and sits under the 246 px the row already gets at 1280x604, so the primary
   viewport neither scrolls nor moves a pixel. (An intrinsic `fit-content` floor
   was tried and rejected: the evidence plate's max-content is the photograph's
   own height, which put the floor at 271 px and started the stage scrolling at
   1280x604.) */
.vdmid{flex:1 1 auto;min-height:230px}
/* The row absorbs the 18 px css/16 used to spend on .vstage's own padding-bottom,
   so the stage's total height is unchanged and the evidence/locator pair keeps
   every pixel it had at 1280x604. The fill is the measured composite of
   --glass (.55) over --bg — neither is themed, so it is a constant — and the
   fade above it is a pseudo, not padding, for the same reason. */
/* THE EVIDENCE PLATE HAS TO SHRINK WITH THE WELL. css/16's stated intent is
   "the image is fitted whole inside a letterboxed well" — but `max-height:100%`
   on a grid item whose grid container is a flex item with an indefinite basis
   never resolves, so the <img> kept its intrinsic height and .vevidbox's
   overflow:hidden CROPPED it. Measured: a 577x284 still in a 259 px well lost
   25 px at 1280x604 and 164 px in a 122 px well at 640x604 — the shorter the
   screen, the more of the photograph the inspector was judging disappeared.
   Positioning it against the well (the same trick .vlocmap already uses for
   its canvas) makes the box definite, so object-fit:contain finally applies. */
.vevidbox{position:relative}
#vEvidImg{position:absolute;inset:0;width:100%;height:100%;max-width:none;max-height:none}

.vacts{flex:0 0 auto;position:sticky;bottom:0;z-index:2;margin-top:auto;
  padding:0 0 18px;background:#090D0E}
.vacts::before{content:"";position:absolute;left:0;right:0;bottom:100%;height:14px;
  pointer-events:none;background:linear-gradient(180deg,rgba(9,13,14,0),#090D0E)}
@media (max-width:900px) and (orientation:landscape){
  /* split stacks the plate over the locator, and css/20's fixed 164 px locator
     row is ~46 px short of what the 170 px map well plus its heading and foot
     actually need — it overflowed its own row and painted over the decisions.
     224 px is that real height (a 17 px heading, an 8 px gap, the 170 px map
     well, an 8 px gap and a 21 px foot); the plate keeps a 148 px floor above
     it, and 386 px (148 + 14 gap + 224) is what the pair needs before the stage
     starts scrolling instead of squeezing. */
  .verify .vdmid{grid-template-rows:minmax(148px,1fr) 224px;min-height:386px}
  .vacts{padding-bottom:14px}
}

/* =====================================================================
   5. INSPECTION COMPLETE — the screen the client named
   css/20 and css/21 already made this scroll with a sticky action at the
   narrow breakpoints; the wide landscape layout never did, so losing height
   crushed the cards instead of scrolling them. Same treatment, all widths.
   ===================================================================== */
.sumwrap{padding-top:calc(var(--header-safe) + 8px);
  padding-left:max(20px,var(--sa-l));padding-right:max(20px,var(--sa-r));
  padding-bottom:max(12px,var(--sa-b));
  overflow-y:auto;overflow-x:hidden;scrollbar-width:none;overscroll-behavior:contain;
  /* same reason as .vstage: .sumfoot is sticky at the bottom edge here too */
  scroll-padding-bottom:88px}
.sumwrap::-webkit-scrollbar{display:none}
/* css/20 and css/21 already pin .sumfoot at the narrow breakpoints, so only the
   wide landscape layout needs the treatment — and it takes it with a pseudo
   rather than the 8 px padding-top those two use, so the band keeps the exact
   height it has at 1280x604 today and the primary viewport is untouched. */
@media (min-width:901px) and (orientation:landscape){
  /* the band is flex:1 1 auto;min-height:0 in css/19 — free to be crushed to
     nothing. 236 px is under the 261 px it already takes at 1280x604, so that
     viewport is unchanged; below it the screen scrolls instead of shredding the
     merged KPI list and clipping the sector map. */
  .sumband{min-height:236px}
  .sumfoot{position:sticky;bottom:0;z-index:3;margin-top:auto}
  .sumfoot::before{content:"";position:absolute;left:0;right:0;bottom:100%;height:16px;
    pointer-events:none;background:linear-gradient(rgba(7,10,11,0),var(--bg))}
}
@media (max-width:900px) and (orientation:landscape){
  .sumwrap{padding-left:max(12px,var(--sa-l));padding-right:max(12px,var(--sa-r))}
}
@media (orientation:portrait){
  .sumwrap{padding-left:max(12px,var(--sa-l));padding-right:max(12px,var(--sa-r))}
}

/* =====================================================================
   6. THE END-OF-INSPECTION REVIEW — the escape stays reachable
   #review is inset:0 and covers the rail, so its own top padding is what
   clears the native top bar. Its list panel is capped at 26vh in split; that
   cap is smaller than the panel's own non-shrinkable foot once the vehicle's
   chrome takes height, and .panel{overflow:hidden} then ate the button and
   its hint. The cap gets a floor that the foot fits inside.
   ===================================================================== */
#review{padding-top:calc(14px + var(--sa-t));padding-bottom:calc(16px + var(--sa-b));
  padding-left:max(16px,var(--sa-l));padding-right:max(16px,var(--sa-r))}
@media (max-width:900px) and (orientation:landscape){
  #review{padding-top:calc(10px + var(--sa-t));padding-bottom:calc(12px + var(--sa-b));
    padding-left:max(12px,var(--sa-l));padding-right:max(12px,var(--sa-r))}
  /* 168 px is the panel's own measured floor — its 34 px title, its 91 px foot
     and the panel's own 4 px of border/padding, plus a row's worth of list. It
     grows the panel UPWARD (its bottom is pinned by #review's padding and the
     stage above it is a scroller), so nothing is pushed off screen. */
  .rvw-listpanel{max-height:max(26vh,168px)}
  /* 144 px was not enough on its own: the panel's children did not shrink to
     the cap, so the foot still ran 11-24 px past it at every split height. The
     list takes LEFTOVER space (basis 0) rather than its content height, so the
     title and the foot are always laid out first and the rows scroll inside
     whatever is left — which is what .rvw-list's own overflow-y:auto is for. */
  .rvw-list{flex:1 1 0}
}
