/* ============================================================================
   appshell.css — ONE app bar for every Jai Roop page.
   Loaded last in <head> so it wins ties against each page's own <style>.

   The page keeps its own colours, its own logo and its own buttons. All this
   file does is give the bar the same SHAPE everywhere:

       desktop / tablet   [logo] [page name]  ............  [ the controls ]
       phone (<=760px)    [logo] [page name] .......... [ ☰ Menu ]
                          └─ the controls drop down as a full-width sheet ─┘

   Why a sheet and not a wrapped row: on order.html the bar carries eleven
   controls. Wrapped, that is four rows — 190px of app bar on a 760px screen.
   Collapsed, the bar is one 60px row on every page and every control is two
   taps away, which is what a phone app does.

   Nothing here changes a page BODY. Header and its immediate layout only.

   env()/max()/var() are used as PROGRESSIVE ENHANCEMENT: every rule that uses
   them is duplicated with a plain fallback declaration first, so a WebView
   that does not know the function simply drops that one declaration and keeps
   the fallback. env(safe-area-inset-*) stays 0 until a page carries
   viewport-fit=cover in its viewport meta — the padding is already correct
   and starts working the moment that lands.
   ============================================================================ */

/* ── 0. the safe area, in ONE place ─────────────────────────────────────────
   Every inset in this file goes through these four variables instead of
   calling env() at the point of use: one place to read, one place to change,
   and a test can set --ash-sat on <html> and see the real thing without a
   notched device.

   They are declared 0px FIRST and only re-declared inside @supports, and that
   is not decoration. A custom property is not validated when it is parsed —
   it stores whatever tokens it was given. So on a WebView that has var() but
   not env() (Chrome 49–68, i.e. an Android 5/6/7 tablet whose WebView was
   never updated — the machines this codebase is careful about) the naked form
   `--ash-sat: env(...)` would store an unusable value, and every
   `calc(12px + var(--ash-sat,0px))` using it becomes invalid AT COMPUTED-VALUE
   TIME. That does not fall back to the previous declaration the way a bad
   normal declaration does — it falls back to the property's initial value,
   which for padding is 0. The app bar would lose its padding on exactly the
   old devices we are protecting. The @supports gate means those browsers keep
   the plain 0px and therefore today's layout.

   These stay 0 until the page carries viewport-fit=cover in its viewport
   meta. All 42 pages now do — the two halves landed together.              */
:root{
  --ash-sat: 0px;
  --ash-sar: 0px;
  --ash-sab: 0px;
  --ash-sal: 0px;
}
@supports (padding-top: env(safe-area-inset-top)){
  :root{
    --ash-sat: env(safe-area-inset-top,    0px);
    --ash-sar: env(safe-area-inset-right,  0px);
    --ash-sab: env(safe-area-inset-bottom, 0px);
    --ash-sal: env(safe-area-inset-left,   0px);
  }
}

/* ── 1. the painted bar ─────────────────────────────────────────────────────
   --ash-pt / --ash-px are written inline by appshell.js from the bar's OWN
   computed padding, so each page keeps its own proportions. The status-bar
   inset is added on top of the page's padding, never instead of it.        */
.ash{
  box-sizing:border-box;
  position:relative;
  height:auto;                      /* let the safe-area inset grow the bar   */
  padding-top:var(--ash-pt,12px);
  padding-top:calc(var(--ash-pt,12px) + var(--ash-sat,0px));
  padding-bottom:var(--ash-pt,12px);
  padding-left:var(--ash-px,16px);
  padding-left:max(var(--ash-px,16px), var(--ash-sal,0px));
  padding-right:var(--ash-px,16px);
  padding-right:max(var(--ash-px,16px), var(--ash-sar,0px));
}

/* ── 2. the row ─────────────────────────────────────────────────────────── */
.ash-row{
  display:flex;
  align-items:center;
  flex-wrap:wrap;                   /* safety net: the bar can never overflow */
  gap:10px;
  min-width:0;
}

/* ── 3. identity — logo + page name. Never collapses, never disappears. ─── */
.ash-id{
  display:flex;
  align-items:center;
  gap:10px;
  min-width:0;
  flex:0 1 auto;
}
.ash-id > *{min-width:0}
.ash-id img,.ash-id .hlogo,.ash-id .mark{flex:none}

/* ── 4. the controls ────────────────────────────────────────────────────── */
.ash-tools{
  display:flex;
  align-items:center;
  flex-wrap:wrap;
  justify-content:flex-end;
  gap:8px;
  flex:1 1 auto;
  min-width:0;
}
.ash-burger{display:none}           /* desktop: there is nothing to collapse */
.ash-lbx{display:none}              /* desktop: the bar keeps the bare icon   */

/* order.html / sample.html "switch system" sheet hangs off the bar. */
.sysmenu{top:60px}
.sysmenu{top:calc(60px + var(--ash-sat,0px))}

/* ══════════════════════════════════════════════════════════════════════════
   PHONE
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width:760px){

  .ash{
    padding-top:8px;
    padding-top:calc(8px + var(--ash-sat,0px));
    padding-bottom:8px;
    padding-left:12px;
    padding-left:max(12px, var(--ash-sal,0px));
    padding-right:12px;
    padding-right:max(12px, var(--ash-sar,0px));
  }

  .ash-row{flex-wrap:nowrap;gap:8px;min-height:44px}

  .ash-id{flex:1 1 auto}
  /* The page name is what tells a man on the floor which system he is in, so
     it gets every pixel the burger does not need — and an ellipsis, not a
     second line and not a sideways scroll. */
  .ash-id h1,.ash-id .htitle,.ash-id .brand,.ash-id > b,.ash-id > div > b{
    font-size:15px;line-height:1.2;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  }
  .ash-id .sub,.ash-id .hsub,.ash-id small,.ash-id p{
    font-size:10.5px;line-height:1.25;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  }
  .ash-id .brand small{display:block}          /* "Order → Dispatch" stacks   */

  /* ── the ☰ button ─────────────────────────────────────────────────────
     currentColor everywhere, so it is white on the navy bars and dark on
     the light IMS bar without knowing anything about either. */
  .ash-burger{
    display:inline-flex;align-items:center;justify-content:center;gap:9px;
    flex:none;
    min-height:44px;min-width:44px;padding:0 13px;
    margin:0;
    background:transparent;
    border:1.5px solid currentColor;
    border-radius:12px;
    color:inherit;
    font-family:inherit;font-size:12.5px;font-weight:700;letter-spacing:.02em;
    cursor:pointer;
    opacity:.92;
    -webkit-tap-highlight-color:rgba(0,0,0,0);
  }
  .ash-burger:active{opacity:1;background:rgba(127,127,127,.22)}

  /* The min-width above is (0,1,0) and rule 8a below — `.ash-row > *
     {min-width:0}` — is (0,1,0) too, but later in the file, so it WINS and
     zeroes the floor this button exists to guarantee. appshell.js always
     appends #ashBurger straight into .ash-row, so `.ash-row > .ash-burger`
     is (0,2,0) and outranks 8a wherever it lands in the file. Restated here
     rather than by editing 8a: the burger is flex:none and never shrinks, so
     it was never what 8a was written to catch. */
  .ash-row > .ash-burger{min-width:44px}

  .ash-ico{
    position:relative;display:block;flex:none;
    width:17px;height:2px;border-radius:2px;background:currentColor;
  }
  .ash-ico::before,.ash-ico::after{
    content:"";position:absolute;left:0;
    width:17px;height:2px;border-radius:2px;background:currentColor;
    transition:top .16s ease,transform .16s ease;
  }
  .ash-ico::before{top:-6px}
  .ash-ico::after{top:6px}
  .ash-open .ash-ico{background:transparent}
  .ash-open .ash-ico::before{top:0;transform:rotate(45deg)}
  .ash-open .ash-ico::after{top:0;transform:rotate(-45deg)}

  /* ── the sheet ────────────────────────────────────────────────────────
     Background / text colour are copied off the bar by appshell.js, so the
     sheet is made of the same material as the header on every page. */
  .ash-tools{
    position:absolute;left:0;right:0;top:100%;
    display:none;
    flex-direction:column;align-items:stretch;justify-content:flex-start;
    flex-wrap:nowrap;
    gap:3px;
    padding:8px;
    padding-bottom:calc(8px + var(--ash-sab,0px));
    margin:0;
    max-height:78vh;
    overflow-y:auto;
    -webkit-overflow-scrolling:touch;
    border-top:1px solid rgba(127,127,127,.4);
    box-shadow:0 20px 44px rgba(0,0,0,.42);
    z-index:60;
  }
  .ash-open .ash-tools{display:flex}

  /* a spacer is a desktop idea — appshell.js tags every empty div in the bar */
  .ash-tools .ash-sp,
  .ash-tools .hsp,.ash-tools .spacer,.ash-tools .hspacer,.ash-tools .hspace{display:none}

  /* every row of the sheet is full width … */
  .ash-tools > a,.ash-tools > button,.ash-tools > select,
  .ash-tools > div,.ash-tools > span,.ash-tools > label{
    width:100%;box-sizing:border-box;margin:0 !important;
  }
  /* … and a container that came down from the bar lays its buttons out flat */
  .ash-tools > div{flex-wrap:wrap;gap:8px;justify-content:flex-start;align-items:center}

  /* … and nothing a thumb has to hit is under 46px. */
  .ash-tools a,.ash-tools button,.ash-tools select{
    min-height:46px;line-height:22px;
    padding:12px 14px;
    border-radius:10px;
    font-size:14px;
    text-align:left;justify-content:flex-start;
    box-sizing:border-box;
  }
  /* pages that shout their header buttons down with !important (order.html) */
  .ash-tools .btn,.ash-tools .hbtn,.ash-tools .homebtn,.ash-tools .out,.ash-tools .btn-out{
    padding:12px 14px !important;font-size:14px !important;
    width:auto;height:auto;
  }
  .ash-tools .sysmenu-btn{width:100%;height:auto;text-align:left}

  /* An icon-only control ("⋮" on order.html, "⚙️"/"🔊" on assistant.html) reads
     fine as a 34px square on a bar and reads as a BLANK ROW in a full-width
     sheet. appshell.js appends the control's own title here — no invented
     wording, and only where nothing else in the sheet already says it. */
  .ash-tools .ash-lbx{display:inline;font-size:14px;font-weight:600}

  /* status chips read as one calm line, not as buttons */
  .ash-tools .netbadge,.ash-tools .netpill,.ash-tools .tag,.ash-tools .hstamp{
    width:100%;box-sizing:border-box;
    text-align:center;padding:9px 12px;border-radius:10px;
    font-size:12.5px;white-space:normal;margin:0 !important;
  }

  /* order.html's hover dropdowns cannot hover on a phone: flatten them into
     the sheet, with the old trigger left standing as the section heading. */
  .ash-tools .more-wrap{width:100%;position:static}
  .ash-tools .more-trigger{
    width:100%;min-height:0;
    padding:12px 14px 4px !important;
    font-size:10.5px !important;font-weight:700;letter-spacing:.09em;
    text-transform:uppercase;opacity:.55;border:0 !important;background:transparent !important;
  }
  .ash-tools .more-menu{
    display:block;position:static;
    min-width:0;padding-top:0;box-shadow:none;
  }
  /* NOTE the .btn / button in the last position: order.html paints these white
     with `.appbar .more-menu .btn{background:#fff!important}` (0,3,0), so a
     `.ash-tools .more-menu > *` (0,2,0) loses and the sub-items come out as
     white pills inside a navy sheet. Measured, not guessed. */
  .ash-tools .more-menu > *,
  .ash-tools .more-menu > .btn,
  .ash-tools .more-menu > button{
    width:100%;white-space:normal;box-shadow:none;
    background:transparent !important;color:inherit !important;border:0 !important;
    padding:12px 14px !important;font-size:14px !important;
    border-radius:10px !important;text-align:left;min-height:46px;
  }
  .ash-tools .more-menu > .btn:active,
  .ash-tools .more-menu > button:active{background:rgba(127,127,127,.24) !important}

  /* ims.html ships a 34x18 dark-mode switch. Measured, that is a 34x18 tap
     target in the sheet — under half of 44. Re-proportioned here (and only
     here, inside the sheet) so the knob travel still matches the pill. */
  .ash-tools .toggle-dark{width:72px;height:44px;min-height:44px;flex:none;border-radius:999px}
  .ash-tools .toggle-dark .knob{width:36px;height:36px;top:4px;left:4px}
  .dark .ash-tools .toggle-dark .knob{left:32px}
}

/* very narrow (320px): the word next to ☰ goes, the icon stays */
@media (max-width:359px){
  /* Same collision as above: the 46px has to be stated at (0,2,0) to survive
     rule 8a. Without it this button measured 19x44 on a 320px phone — the
     bare 17px icon plus its border — and ☰ is the only way to reach
     Back / Sync / Logout here. */
  .ash-burger{padding:0}
  .ash-row > .ash-burger{min-width:46px}
  .ash-lb{display:none}
}


/* ══════════════════════════════════════════════════════════════════════════
   PART TWO — THE PAGE, not just the bar.

   Everything above shapes the app bar. Everything below is the other half of
   the owner's complaint: "jab mai app ko scroll left kar raha hu to blank
   page tak scroll ho raha hai". A document that is 1032px wide on a 360px
   screen scrolls sideways into white, and everything below the content looks
   blank too. Measured at 320/360/390 before this section existed, nine pages
   pushed the document wider than the phone.

   The order here is deliberate: fix the CAUSE first (5–8), then the belt (5).
   The belt alone would only HIDE the overflow, and a table you cannot reach
   is worse than a page that scrolls.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── 5. the document does not scroll sideways, and does not rubber-band ────
   overflow-x:CLIP, not hidden. `hidden` forces the other axis to `auto`,
   which turns <body> into a scroll container and silently breaks every
   position:sticky header on these pages (accounts, help, hr, master,
   operations, reports, templates, whatsapp-engine, edit-history, field all
   have one). `clip` clips without creating a scroll container, so sticky
   keeps working. A browser too old for `clip` simply ignores it and lands on
   today's behaviour — and by then 6–8 below have already removed the cause,
   so there is nothing left to clip.

   overscroll-behavior:none is what stops the bounce that reveals blank page
   past the top/bottom/edges, and it also turns off pull-to-refresh — which
   is the single most "this is a website, not an app" gesture there is.    */
html{
  overflow-x:clip;
  overscroll-behavior:none;
  -webkit-text-size-adjust:100%;      /* Android must not re-scale our text */
}
body{
  overflow-x:clip;
  max-width:100%;
}
/* Scrolling INSIDE the menu sheet, a table or a modal must not chain out to
   the page behind it. The menu sheet IS .ash-tools — the one this rule is named
   after — so it is already covered.

   `.sheet` USED TO BE IN THIS LIST AND IT FROZE THE REPORT PAGES. It matched
   nothing it was meant to: grepped across all 48 pages, the only `class="sheet"`
   in the platform is report-view.html's report body, which is not a scrolling
   sub-area at all — it is the page's whole content. That body carries
   `overflow:hidden` (for the rounded corners), and overflow:hidden still makes an
   element a scroll CONTAINER — one with nothing to scroll. So the wheel found a
   scroll container, could not move it, and `contain` refused to pass the gesture
   out to the page. Measured on live before removing it: pointer over the report,
   five wheel notches down, document scrollTop 1200 → 1200. The page could scroll
   (scrollHeight 4795 vs clientHeight 367) — it just was not allowed to.
   Do not add a bare `.sheet` back here; name the scroller you actually mean. */
.ash-tools,.ash-tscroll,.modal{overscroll-behavior:contain}

/* ── 6. the status-bar strip stays painted ────────────────────────────────
   Padding the bar (rule 1) stops the header sitting UNDER the clock. But on
   the pages whose header is not sticky, scrolling pushes the header away and
   white content slides under the status bar instead — which reads as a web
   page in a browser, not as an app. This strip is the app's own status-bar
   background: same colour as the header, painted behind the system icons,
   for the whole session. Height 0 when there is no inset, so on a desktop
   and in a plain browser tab it does not exist at all.
   --ash-bar-bg is written to <html> by appshell.js from the header's own
   computed background, so each page keeps its own colour.                 */
body::before{
  content:"";
  position:fixed;
  top:0;left:0;right:0;
  height:var(--ash-sat,0px);
  background:var(--ash-bar-bg,#16203a);
  z-index:2147483001;                 /* above the app; the OS draws above it */
  pointer-events:none;
}

/* ── 7. a wide table gets its OWN scroller ────────────────────────────────
   The data must stay reachable. Every element that DIRECTLY contains a
   <table> becomes the table's horizontal scroller, so the table can be as
   wide as it needs while the document stays exactly one screen wide.
   `auto`, so on a desktop — where the table fits — nothing appears and
   nothing changes.
   div[id] is there because hr.html, daily-report.html and reports.html build
   their tables with innerHTML into a bare <div id="…">, which no class-based
   selector would catch.

   .ash-tscroll is a SEPARATE rule and not the first item of the :has() selector
   list below, which is where it used to sit. That is not tidiness. :has() is
   Chrome 105+ while overflow-x:clip (rule 5) is Chrome 90+, and an unknown
   pseudo-class invalidates the WHOLE rule it appears in — selector list and
   all. So on any WebView in that band the clip applied and the scroller did
   not, and the right-hand columns of a wide table were simply gone with no
   way to reach them. MEASURED at 360px, :has() disabled: hr.html's 443px
   candidate table (parent DIV#listOv) and daily-report.html's 446px table
   (parent DIV.card) both computed overflow-x:visible and could not be
   scrolled — 83px and 86px of every row unreachable. Those are exactly the
   old floor tablets rule 3 exists to protect.
   Split out, the class survives on its own, and appshell.js tags the parents
   with it when — and only when — :has() is missing. See watchTables().     */
.ash-tscroll{
  overflow-x:auto;
  overscroll-behavior-x:contain;
  -webkit-overflow-scrolling:touch;
  max-width:100%;
}
:where(main,section,article,aside,.card,.box,.panel,.wrap,.tbl,.tablewrap,.tblwrap,div[id],div[class]):has(> table){
  overflow-x:auto;
  overscroll-behavior-x:contain;
  -webkit-overflow-scrolling:touch;
  max-width:100%;
}
/* A <td> that contains a nested table is a layout, not a data grid — leave
   it alone, and never make a sticky-header card scroll on itself. */
td:has(> table),th:has(> table){overflow:visible}

/* ── 8. nothing is allowed to be wider than the phone ─────────────────────
   Three separate causes, all measured, all only on narrow screens.        */
@media (max-width:760px){

  /* (a) A grid or flex item refuses to shrink below its own content unless
         it is told it may. users.html is the proof: main is a two-column
         grid that collapses to `1fr` at 860px, but `1fr` means
         minmax(AUTO,1fr) and the auto floor is the widest cell in the user
         table — so the "collapsed" single column was 474px wide on a 320px
         phone. min-width:0 is the whole fix. */
  main > *,.wrap > *,.grid > *,.grid2 > *,.tgrid > *,.cols > *,
  .row > *,.statbar > *,.toolbar > *,.bar > *,.ash-row > *{min-width:0}
  main,.wrap{min-width:0}

  /* (a2) A flex row that is told never to wrap is a desktop idea. It cannot
         fit on a phone, so instead of wrapping it simply sticks out of the
         page — order.html's .dashleft is 401px of date pickers and status
         checkboxes on a 360px screen, and it is the last thing that was
         still dragging that document sideways.
         flex-wrap is ignored by every element that is not a flex container,
         so this reaches exactly the rows with the problem and nothing else.
         Scoped to the page BODY (main/.wrap/.card): the app bar's own
         .ash-row must stay nowrap, and it lives in <header>. */
  main *,.wrap *,.card *{flex-wrap:wrap}
  /* …except a strip that is MEANT to scroll sideways. Measured across the 20
     busiest pages, that is exactly four elements and all four are tab bars:
     hr.html NAV, master.html NAV, salary.html NAV#tabs, delegation.html
     NAV#tabs. Wrapping those would stack the tabs into a wall. */
  nav,nav *{flex-wrap:nowrap}

  /* (b) `repeat(auto-fill, minmax(300px,1fr))` cannot fit 300px into 320px,
         so the track stays 300px and the grid sticks out. On a phone one
         column is the right answer anyway. */
  .grid,.tgrid,.cards,.tiles,.cardgrid,.accgrid{grid-template-columns:1fr}
  main{grid-template-columns:minmax(0,1fr)}

  /* (c) A chip with a long label and flex:none is a 440px word. reports.html
         puts the whole reporting period in one. Let them wrap. */
  .tag,.chip,.pill,.badge,.netbadge,.netpill,.per,.rh{
    max-width:100%;
    white-space:normal;
    overflow-wrap:break-word;
    word-break:break-word;
  }

  /* (d) fixed-width form controls and long unbroken strings (an email, a
         Drive URL, a 40-character design code). */
  input,select,textarea,button{max-width:100%}
  img,video,canvas,svg,iframe{max-width:100%}
  pre,code{white-space:pre-wrap;overflow-wrap:break-word}
}

/* ── 9. the rest of the safe area ─────────────────────────────────────────
   Top is the bar (rule 1) and the strip (rule 6). These are the other three
   edges, and they only ever do anything when the inset is non-zero:

     left / right — a LANDSCAPE notch eats the left edge of the content, not
                    of the header. --ash-mainpl/pr are the page's OWN computed
                    padding, read by appshell.js before we touch anything, so
                    this ADDS to what the page already had and never replaces
                    it (purchase-form.html's body{padding:20px} survives).
     bottom       — the gesture bar eats the bottom of a fixed element.
                    field.html's tab bar is the one that matters: it is
                    position:fixed;bottom:0 and it is what the field boys tap
                    all day.

   These three are applied by appshell.js as inline style, NOT by a rule here,
   and that is a deliberate choice I got wrong the first time. The rule I had
   written was

       main,.wrap{ padding-left:calc(var(--ash-mainpl,0px) + var(--ash-sal,0px)) }

   which reads as "the page's own padding plus the inset". It is not. If the
   script has not run — or fails on one page, or is cached out of date — the
   variable is unset, the fallback 0px wins, and the rule REPLACES main's real
   26px padding with nothing. Every page's content would go edge-to-edge on a
   desktop, for a rule whose whole job is a landscape notch that is 0px on
   every device in this factory. A rule that can subtract is the wrong shape
   for the job.

   In JS the padding is read first and written back as base+inset, and it is
   only written at all when the inset is actually non-zero — so on every phone
   without a landscape notch, and on every desktop, not one property is
   touched. See ashInsets() in appshell.js.                                 */

/* The one exception: a fixed bottom bar is ours to own — .ash-bottom is set by
   appshell.js on the element it padded, so this is a marker, not a guess. */
.ash-bottom{overscroll-behavior:contain}

/* ── 10. desktop is not allowed to regress ────────────────────────────────
   Above 760px nothing in 8 applies, the insets are 0 so 1/6/9 compute to the
   page's own values, and 5 and 7 only engage when something would already
   have overflowed. The office machines at 1280px see no change — measured,
   all 42 pages, before and after. */


/* ══════════════════════════════════════════════════════════════════════════
   PART THREE — "ye app nahi, aisa lag raha hai ki website ko app me khola hai".

   PART ONE gave the bar a shape and PART TWO stopped the document scrolling
   sideways. Neither of those is what makes a page FEEL like a web page. That
   is a short, specific list of browser behaviours that no native app has:

       · the blue flash under a finger on every link and button
       · a long press that starts selecting text and pops a copy toolbar
       · double-tap zoom, and the ~300 ms click delay that comes with it
       · pull-to-refresh, and the rubber-band glow at the ends of a scroll
       · a header that slides away, so the menu is only reachable at the top

   Each one is turned off BELOW, and only where it is wrong. What is NOT
   turned off is written down just as carefully, because the man on the floor
   copies order ids and phone numbers out of these tables all day.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── 11. the browser's own gestures ───────────────────────────────────────
   -webkit-tap-highlight-color IS INHERITED, so one declaration on <html>
   takes the blue flash off every link and button on all 42 pages. (The ☰
   button already set its own; that stays, it is now simply not the only one.)

   touch-action:manipulation removes DOUBLE-TAP ZOOM — and with it the ~300 ms
   wait a browser must serve before it can know a tap was not the first half
   of a double-tap, which is exactly why every button in this system feels a
   beat late. It deliberately KEEPS PINCH ZOOM: a man reading a twelve-column
   table on a 360px phone has to be able to pinch it, and the blunt
   instruments here (touch-action:none, or user-scalable=no in the viewport
   meta) would take that away from him. The property is not inherited, but the
   browser intersects the value down the ancestor chain to the touch target,
   so declaring it on <html> covers the page — while a descendant that asks
   for LESS still wins, which is what keeps sfa.html's Leaflet map draggable
   (Leaflet puts touch-action:none on its own container).                   */
html{
  -webkit-tap-highlight-color:rgba(0,0,0,0);
  touch-action:manipulation;
}
/* Momentum. Rule 5 already killed pull-to-refresh and the page-level bounce
   with overscroll-behavior:none; this is the other half — a scroll that
   coasts instead of stopping dead the moment the finger lifts. */
body,.ash-tscroll,.modal,.sheet{-webkit-overflow-scrolling:touch}

/* ── 12. selection: OFF on the furniture, ON on the values ────────────────
   A long press on a heading, a button or a menu row selecting text — blue
   highlight, drag handles, a floating COPY bar — is the single loudest "this
   is a web page" there is, and it fires constantly because a slow tap on a
   phone IS a long press.

   It is switched off only inside the installed app (html.ash-app, set by
   appshell.js from Capacitor.isNativePlatform). In a browser these pages ARE
   a web site and behave like one — nobody's copy/paste in Chrome is touched.

   KEPT SELECTABLE, on purpose, because these are the things a man genuinely
   copies out of this system:
     td, th        every value in every table — order id, party name, design
                   number, kg, rate, amount. This is the big one: 269 .num
                   cells, every report, every ledger row.
     input,
     textarea,
     select        obviously; and a field you cannot select inside is a field
                   you cannot correct.
     .num .mono
     .big .kpi
     .val .amt     the same numbers when a page prints them outside a table
                   (dashboard tiles, totals, ids). All six are classes this
                   codebase really uses — none invented.
     a[href^=tel:]
     a[href^=mailto:]  a phone number and an e-mail address are made to be
                   copied; call-us.html is nothing but these.
     pre, code     ids, JSON, error text.
     [contenteditable]  belongs to whoever put it there.
     .ash-copy     a hook, for anything found later that should be copyable.

   -webkit-touch-callout is iOS-only and there is no iOS build today; it costs
   one line and is correct the day there is one.                            */
html.ash-app body{
  -webkit-user-select:none;
  -moz-user-select:none;
  -ms-user-select:none;
  user-select:none;
  -webkit-touch-callout:none;
}
html.ash-app input,html.ash-app textarea,html.ash-app select,
html.ash-app td,html.ash-app th,
html.ash-app pre,html.ash-app code,
html.ash-app [contenteditable],
html.ash-app a[href^="tel:"],html.ash-app a[href^="mailto:"],
html.ash-app .num,html.ash-app .mono,html.ash-app .big,
html.ash-app .kpi,html.ash-app .val,html.ash-app .amt,
/* .dval is order.html's stat-tile number — PRODUCTION (KG) 2,824,
   JOB WORK (OUT) 2,70,312, PACKING 4,92,902. Measured inside the app it was
   the one real figure on that page that had gone unselectable: everything
   else a man copies (order id, party, phone, every table cell) is a td.    */
html.ash-app .dval,
html.ash-app .ash-copy{
  -webkit-user-select:text;
  -moz-user-select:text;
  -ms-user-select:text;
  user-select:text;
  -webkit-touch-callout:default;
}

/* ── 13. the bar stays put ────────────────────────────────────────────────
   An app's top bar does not scroll away. On a phone this is not decoration:
   the ☰ button IS the whole menu, so a bar that scrolls away means the man
   has to scroll back to the top of a 4000px page to reach Logout.

   And a regression to own up to. Twelve pages position their own header —
   order, sample, accounts, operations, reports, templates, whatsapp-engine,
   master, hr, help, edit-history, field — and PART ONE took it away from all
   twelve without meaning to: `.ash{position:relative}` is (0,1,0), which
   outranks `header{…position:sticky}` at (0,0,1) outright, and ties with
   `.appbar{…position:sticky}` at (0,1,0) — where appshell.css wins because it
   is the last stylesheet in every <head>. MEASURED, not reasoned: accounts.html
   at 360px reports position:relative on a header whose own rule says sticky.
   So there are two classes here, and appshell.js decides which one:

     .ash-restick   the bar the page HAD positioned. Sticky at every width,
                    because that is what the page did before appshell.css
                    existed and desktop is not allowed to change (rule 10).
                    No z-index: the page's own survives untouched (order.html
                    keeps its 30, accounts keeps its 20).
     .ash-stick     a bar that was static/relative to begin with. New
                    behaviour, so PHONE ONLY, and it needs a z-index of its
                    own — 20, the number the twelve pages already chose.

   Then the collision nobody thinks about until it ships: a bar pinned at
   top:0 covers everything ELSE that was pinned at top:0 — the sticky <thead>
   row on every data page, and the tab strip on delegation / macprod /
   machine-maintenance / vehicle-inspection / salary. Those would slide under
   the bar and vanish. So anything that used to stop at the top now stops at
   the bar's MEASURED height (--ash-hh, written by appshell.js — measured, not
   a hard-coded 60px, because the bar grows with the safe-area inset).

   Deliberately narrow selectors:
     nav#tabs        the five tabbed pages, by id. Measured at 360px scrolled
                     900px: the strip lands at y=60 and the bar's bottom is
                     y=60, so it clears the bar exactly instead of vanishing
                     under it.
     header + nav    hr.html and master.html, where the tab strip is the very
                     next element (they hard-code top:60px today; this is the
                     same thing, measured). ADJACENT only — field.html's
                     nav is its fixed BOTTOM tab bar and sits far away in the
                     DOM; a `header ~ nav` here would have given a bottom:0
                     fixed bar a top as well and stretched it over the whole
                     screen.

   TWO SELECTORS THAT USED TO BE HERE AND ARE GONE, because the premise behind
   them was never true on these pages. An offset is only right when the sticky
   element's scroll container is the VIEWPORT — that is the only case where the
   app bar is in front of it. Both of these live inside their own scroller:

     thead th   Every data table in this codebase sits inside a wrapper that
                already scrolls (.tblwrap, .tbl-scroll, .card, #mainCard) — and
                rule 7 above makes that true for the rest. Measured across all
                42 pages at 320/360/390/1280: 92 sticky <th> samples, ZERO whose
                scroll container is the viewport. So the offset could never do
                the job it was written for, and where it applied it pushed the
                column headings 61px DOWN inside their own box — on macprod,
                salary, delegation, machine-maintenance, payment and designs the
                header row floated with a 61px band of data rows scrolling above
                it. Removing it returns each page's own `top:0`, which is right
                inside a scroller.
     .rawbar    order.html's raw-material toolbar lives in
                `.rawpanel{position:fixed;inset:0;z-index:60}` — a FULL-SCREEN
                overlay that covers the app bar (z-index 30) rather than sitting
                under it. Measured with the panel open at 360px: the toolbar was
                offset 60px from the panel's own top even at rest, i.e. a 60px
                empty blue band across the top of the Raw Inventory screen.

   The offsets are phone only: rule 10 still holds and the office machines see
   none of them. Giving the twelve pages their sticky bar back is NOT phone
   only — that is a restoration, not a change.                              */
.ash-restick{position:sticky;top:0}
@media (max-width:760px){
  .ash-stick{position:sticky;top:0;z-index:20}
  html.ash-stuck nav#tabs{top:var(--ash-hh,0px)}
  html.ash-stuck header + nav{top:var(--ash-hh,0px)}
}
