/* ═══════════════════════════════════════════════════════════════════════════
   HD Prime Lift — Apple / iOS design layer
   ---------------------------------------------------------------------------
   A stylesheet that LAYERS on top of dashboard.html's existing inline <style>.
   It never renames anything and never redefines the brand variables the inline
   block already owns (--bg --surface --ink --muted --line --accent --accent-ink
   --danger --ok --radius --shadow). The warm off-white / charcoal / brass
   identity is untouched.

   LINK IT LAST — after the inline <style> block, immediately before </head>.
   The cascade is what lets the few intentional overrides in §5 and §8 win.

   ── HOW EACH PART SWITCHES ON ────────────────────────────────────────────
   Always on          tokens, type utilities, new components (they only apply
                      to class names that do not exist yet, so nothing can
                      regress), the sheet/overlay motion rebuild, 100svh fixes,
                      reduced-motion handling.
   @media (pointer:coarse)
                      44pt touch targets and the 16px input floor. Desktop
                      pointer users keep the existing compact density — this is
                      how the layer stays invisible on a laptop.
   body:has(.tabbar)  or  html.ios-tabbar
                      Bottom tab bar takes over below 760px and the sidebar
                      spine hides. Self-activating: it only fires once the
                      orchestrator actually puts a .tabbar in the DOM.
   html.ios-chrome    Moves the safe-area insets off <body> and onto the fixed
                      chrome. ONLY add this class once a .navbar exists, or
                      content will run under the status bar in standalone.
   html.is-standalone Set by JS when display-mode is standalone. Reveals the
                      back affordance and the edge-swipe grab zone.
   html.ios-dark      Forced dark appearance.
   html.ios-dark-auto Dark appearance when the OS asks for it.
                      Dark is OPT-IN because dashboard.html still contains ~122
                      hardcoded light hexes; flipping it on before those are
                      migrated to the semantic tokens below gives a half-dark
                      screen. Turn it on after that sweep, not before.
   html.ios-flat      Removes card shadows in favour of fill + hairline (the
                      iOS grouped-list look). Opt-in; it is a visible change.
   ═══════════════════════════════════════════════════════════════════════════ */


/* ═══ 1. TOKENS ═════════════════════════════════════════════════════════ */

:root{
  /* The dashboard is a light design. Saying so stops the UA dark-rendering
     form controls, scrollbars and the caret when the OS is in dark mode.
     Flips to "light dark" via html.ios-dark-auto (see §2). */
  color-scheme: light;

  /* ── font stacks ─────────────────────────────────────────────────── */
  --sf: -apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro Display",
        "Segoe UI", Roboto, system-ui, sans-serif;
  --sf-mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, monospace;
  --sf-rounded: ui-rounded, "SF Pro Rounded", -apple-system, sans-serif;

  /* Dynamic Type scale factor. 1 until the JS probe reports the user's
     chosen iOS text size; clamped 0.9–1.35 so accessibility sizes cannot
     blow up a dense table. See the snippet in the handoff notes. */
  --dt: 1;

  /* ── iOS text styles: size / line-height / tracking / weight ─────── */
  --t-largetitle: calc(34px * var(--dt)); --lh-largetitle: calc(41px * var(--dt)); --tr-largetitle: .011em;  --w-largetitle: 700;
  --t-title1:     calc(28px * var(--dt)); --lh-title1:     calc(34px * var(--dt)); --tr-title1:     .013em;  --w-title1:     700;
  --t-title2:     calc(22px * var(--dt)); --lh-title2:     calc(28px * var(--dt)); --tr-title2:    -.012em;  --w-title2:     700;
  --t-title3:     calc(20px * var(--dt)); --lh-title3:     calc(25px * var(--dt)); --tr-title3:    -.023em;  --w-title3:     600;
  --t-headline:   calc(17px * var(--dt)); --lh-headline:   calc(22px * var(--dt)); --tr-headline:  -.025em;  --w-headline:   600;
  --t-body:       calc(17px * var(--dt)); --lh-body:       calc(22px * var(--dt)); --tr-body:      -.025em;  --w-body:       400;
  --t-callout:    calc(16px * var(--dt)); --lh-callout:    calc(21px * var(--dt)); --tr-callout:   -.019em;  --w-callout:    400;
  --t-subhead:    calc(15px * var(--dt)); --lh-subhead:    calc(20px * var(--dt)); --tr-subhead:   -.015em;  --w-subhead:    400;
  --t-footnote:   calc(13px * var(--dt)); --lh-footnote:   calc(18px * var(--dt)); --tr-footnote:  -.006em;  --w-footnote:   400;
  --t-caption1:   calc(12px * var(--dt)); --lh-caption1:   calc(16px * var(--dt)); --tr-caption1:   0;       --w-caption1:   400;
  --t-caption2:   calc(11px * var(--dt)); --lh-caption2:   calc(13px * var(--dt)); --tr-caption2:   .005em;  --w-caption2:   400;

  /* ── tint: the app's single accent, inherited from the brand ─────── */
  --tint:        var(--accent, #9C7C38);
  --tint-press:  var(--accent-ink, #7A5F27);
  --tint-fill:   rgba(156,124,56,.14);
  --tint-fill-2: rgba(156,124,56,.08);

  /* ── labels (iOS label hierarchy) ────────────────────────────────── */
  --label:     rgba(22,24,29,1);
  --label-2:   rgba(22,24,29,.60);
  --label-3:   rgba(22,24,29,.36);
  --label-4:   rgba(22,24,29,.20);
  --label-inv: #FFFFFF;

  /* ── fills: control beds, replacing the one-off warm neutrals ────── */
  --fill-1: rgba(22,24,29,.05);
  --fill-2: rgba(22,24,29,.08);
  --fill-3: rgba(22,24,29,.11);
  --fill-4: rgba(22,24,29,.15);

  /* ── separators ──────────────────────────────────────────────────── */
  --sep:        rgba(22,24,29,.14);
  --sep-opaque: #E5E2DB;

  /* ── backgrounds ─────────────────────────────────────────────────── */
  --bg-1: #FFFFFF;
  --bg-2: #F6F5F2;
  --bg-3: #EFEDE8;

  /* ── grouped backgrounds (list screens — inverted, the iOS rule) ─── */
  --grp-1: #F6F5F2;   /* page behind the cards */
  --grp-2: #FFFFFF;   /* the card itself       */
  --grp-3: #F9F8F5;   /* nested inside a card  */

  /* ── status: iOS system colours warmed to the brand ──────────────── */
  --red:    #D6382F;  --red-fill:    rgba(214,56,47,.10);
  --green:  #1B7A43;  --green-fill:  rgba(27,122,67,.10);
  --orange: #C77A17;  --orange-fill: rgba(199,122,23,.12);
  --blue:   #0E7490;  --blue-fill:   rgba(14,116,144,.10);
  --yellow: #E4A93A;  --yellow-fill: rgba(228,169,58,.14);

  /* ── 4pt spacing grid ────────────────────────────────────────────── */
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:20px;
  --sp-6:24px; --sp-8:32px; --sp-10:40px; --sp-12:48px;

  /* ── layout metrics ──────────────────────────────────────────────── */
  --margin: 16px;
  --row-min: 44px;      /* MINIMUM tappable — never smaller */
  --row-tall: 56px;
  --row-inset: 16px;    /* separator leading inset          */
  --navbar-h: 44px;
  --largetitle-h: 52px;
  --tabbar-h: 49px;
  --toolbar-h: 49px;

  /* ── safe areas, read once ───────────────────────────────────────── */
  --sa-t: env(safe-area-inset-top, 0px);
  --sa-r: env(safe-area-inset-right, 0px);
  --sa-b: env(safe-area-inset-bottom, 0px);
  --sa-l: env(safe-area-inset-left, 0px);

  /* ── corner radii ────────────────────────────────────────────────── */
  --r-xs:6px; --r-sm:10px; --r-md:13px; --r-lg:16px; --r-xl:20px; --r-full:999px;

  /* ── materials ───────────────────────────────────────────────────── */
  --mat-blur-thin:    saturate(180%) blur(20px);
  --mat-blur-regular: saturate(180%) blur(30px);
  --mat-blur-thick:   saturate(180%) blur(40px);
  --mat-blur-chrome:  saturate(180%) blur(24px);
  --mat-thin:    rgba(255,255,255,.62);
  --mat-regular: rgba(246,245,242,.78);
  --mat-thick:   rgba(246,245,242,.92);
  --mat-chrome:  rgba(246,245,242,.80);
  --mat-scrim:   rgba(22,24,29,.28);

  /* ── elevation: restrained. iOS separates with material + hairline ─ */
  --el-0: none;
  --el-1: 0 .5px 0 rgba(22,24,29,.04), 0 1px 2px rgba(22,24,29,.04);
  --el-2: 0 1px 3px rgba(22,24,29,.06), 0 4px 12px rgba(22,24,29,.07);
  --el-3: 0 2px 8px rgba(22,24,29,.08), 0 12px 32px rgba(22,24,29,.13);
  --el-4: 0 4px 16px rgba(22,24,29,.10), 0 24px 64px rgba(22,24,29,.20);

  /* ── motion: UIKit curves ────────────────────────────────────────── */
  --e-default: cubic-bezier(.25,.1,.25,1);
  --e-in:      cubic-bezier(.42,0,1,1);
  --e-out:     cubic-bezier(0,0,.58,1);
  --e-inout:   cubic-bezier(.42,0,.58,1);
  --e-sheet:   cubic-bezier(.32,.72,0,1);
  --e-sheet-x: cubic-bezier(.32,0,.67,0);

  /* damping 1.0, response 0.4 — the default for anything a finger touched */
  --spring: linear(0, .1183 6.25%, .3296 12.5%, .5271 18.75%, .6818 25%,
                   .7925 31.25%, .8677 37.5%, .9170 43.75%, .9487 50%,
                   .9686 56.25%, .9810 62.5%, .9885 68.75%, .9931 75%,
                   .9959 81.25%, .9976 87.5%, .9986 93.75%, .9992);
  --spring-dur: 600ms;

  /* damping 0.8 — ~1.5% overshoot; ONLY after a flick or throw */
  --spring-bounce: linear(0, .1088 6.25%, .3248 12.5%, .5444 18.75%, .7236 25%,
                          .8521 31.25%, .9339 37.5%, .9813 43.75%, 1.0045 50%,
                          1.0137 56.25%, 1.0150 62.5%, 1.0124 68.75%, 1.0091 75%,
                          1.0060 81.25%, 1.0035 87.5%, 1.0018 93.75%, 1.0007);
  --spring-bounce-dur: 550ms;

  --d-press:100ms; --d-micro:200ms; --d-list:250ms; --d-tab:200ms;
  --d-nav:350ms;   --d-sheet:500ms; --d-scrim:300ms;
}

@media (min-width:768px){ :root{ --margin:20px } }

/* Safari < 17.4 has no linear() — fall back to the sheet curve. */
@supports not (transition-timing-function: linear(0,1)){
  :root{ --spring: var(--e-sheet); --spring-dur: 400ms;
         --spring-bounce: var(--e-sheet); --spring-bounce-dur: 400ms }
}


/* ═══ 2. DARK APPEARANCE (opt-in — see the header) ══════════════════════ */

html.ios-dark{
  color-scheme:dark;
  --tint:#C79A47; --tint-press:#B4914A;
  --tint-fill:rgba(199,154,71,.20); --tint-fill-2:rgba(199,154,71,.10);
  --label:rgba(244,242,234,1); --label-2:rgba(244,242,234,.62);
  --label-3:rgba(244,242,234,.38); --label-4:rgba(244,242,234,.22);
  --label-inv:#16181D;
  --fill-1:rgba(244,242,234,.08); --fill-2:rgba(244,242,234,.12);
  --fill-3:rgba(244,242,234,.16); --fill-4:rgba(244,242,234,.22);
  --sep:rgba(244,242,234,.14); --sep-opaque:#2B2F38;
  --bg-1:#1D2027; --bg-2:#16181D; --bg-3:#101216;
  --grp-1:#0F1115; --grp-2:#1D2027; --grp-3:#242832;
  --red:#E2645F; --green:#3CB27A; --orange:#E0A050; --blue:#4EC0D8; --yellow:#E4C07A;
  --red-fill:rgba(226,100,95,.16);   --green-fill:rgba(60,178,122,.16);
  --orange-fill:rgba(224,160,80,.16); --blue-fill:rgba(78,192,216,.16);
  --yellow-fill:rgba(228,192,122,.16);
  --mat-thin:rgba(40,44,52,.62);  --mat-regular:rgba(29,32,39,.80);
  --mat-thick:rgba(29,32,39,.94); --mat-chrome:rgba(22,24,29,.82);
  --mat-scrim:rgba(0,0,0,.48);
  --el-1:0 .5px 0 rgba(0,0,0,.30), 0 1px 2px rgba(0,0,0,.24);
  --el-2:0 1px 3px rgba(0,0,0,.32), 0 4px 12px rgba(0,0,0,.34);
  --el-3:0 2px 8px rgba(0,0,0,.40), 0 12px 32px rgba(0,0,0,.44);
  --el-4:0 4px 16px rgba(0,0,0,.46), 0 24px 64px rgba(0,0,0,.56);
}

@media (prefers-color-scheme: dark){
  html.ios-dark-auto{
    color-scheme:dark;
    --tint:#C79A47; --tint-press:#B4914A;
    --tint-fill:rgba(199,154,71,.20); --tint-fill-2:rgba(199,154,71,.10);
    --label:rgba(244,242,234,1); --label-2:rgba(244,242,234,.62);
    --label-3:rgba(244,242,234,.38); --label-4:rgba(244,242,234,.22);
    --label-inv:#16181D;
    --fill-1:rgba(244,242,234,.08); --fill-2:rgba(244,242,234,.12);
    --fill-3:rgba(244,242,234,.16); --fill-4:rgba(244,242,234,.22);
    --sep:rgba(244,242,234,.14); --sep-opaque:#2B2F38;
    --bg-1:#1D2027; --bg-2:#16181D; --bg-3:#101216;
    --grp-1:#0F1115; --grp-2:#1D2027; --grp-3:#242832;
    --red:#E2645F; --green:#3CB27A; --orange:#E0A050; --blue:#4EC0D8; --yellow:#E4C07A;
    --red-fill:rgba(226,100,95,.16);   --green-fill:rgba(60,178,122,.16);
    --orange-fill:rgba(224,160,80,.16); --blue-fill:rgba(78,192,216,.16);
    --yellow-fill:rgba(228,192,122,.16);
    --mat-thin:rgba(40,44,52,.62);  --mat-regular:rgba(29,32,39,.80);
    --mat-thick:rgba(29,32,39,.94); --mat-chrome:rgba(22,24,29,.82);
    --mat-scrim:rgba(0,0,0,.48);
    --el-1:0 .5px 0 rgba(0,0,0,.30), 0 1px 2px rgba(0,0,0,.24);
    --el-2:0 1px 3px rgba(0,0,0,.32), 0 4px 12px rgba(0,0,0,.34);
    --el-3:0 2px 8px rgba(0,0,0,.40), 0 12px 32px rgba(0,0,0,.44);
    --el-4:0 4px 16px rgba(0,0,0,.46), 0 24px 64px rgba(0,0,0,.56);
  }
}

/* When dark is live, remap the legacy aliases so the existing 8000 lines
   follow along instead of staying light. */
html.ios-dark{
  --bg:var(--grp-1); --surface:var(--grp-2); --ink:var(--label);
  --muted:var(--label-2); --line:var(--sep-opaque);
  --accent:#C79A47; --accent-ink:#E0B565; --danger:var(--red); --ok:var(--green);
}
@media (prefers-color-scheme: dark){
  html.ios-dark-auto{
    --bg:var(--grp-1); --surface:var(--grp-2); --ink:var(--label);
    --muted:var(--label-2); --line:var(--sep-opaque);
    --accent:#C79A47; --accent-ink:#E0B565; --danger:var(--red); --ok:var(--green);
  }
}


/* ═══ 3. TYPE UTILITIES ═════════════════════════════════════════════════ */

.ty-largetitle{font-size:var(--t-largetitle);line-height:var(--lh-largetitle);letter-spacing:var(--tr-largetitle);font-weight:var(--w-largetitle)}
.ty-title1    {font-size:var(--t-title1);    line-height:var(--lh-title1);    letter-spacing:var(--tr-title1);    font-weight:var(--w-title1)}
.ty-title2    {font-size:var(--t-title2);    line-height:var(--lh-title2);    letter-spacing:var(--tr-title2);    font-weight:var(--w-title2)}
.ty-title3    {font-size:var(--t-title3);    line-height:var(--lh-title3);    letter-spacing:var(--tr-title3);    font-weight:var(--w-title3)}
.ty-headline  {font-size:var(--t-headline);  line-height:var(--lh-headline);  letter-spacing:var(--tr-headline);  font-weight:var(--w-headline)}
.ty-body      {font-size:var(--t-body);      line-height:var(--lh-body);      letter-spacing:var(--tr-body);      font-weight:var(--w-body)}
.ty-callout   {font-size:var(--t-callout);   line-height:var(--lh-callout);   letter-spacing:var(--tr-callout);   font-weight:var(--w-callout)}
.ty-subhead   {font-size:var(--t-subhead);   line-height:var(--lh-subhead);   letter-spacing:var(--tr-subhead);   font-weight:var(--w-subhead)}
.ty-footnote  {font-size:var(--t-footnote);  line-height:var(--lh-footnote);  letter-spacing:var(--tr-footnote);  font-weight:var(--w-footnote)}
.ty-caption1  {font-size:var(--t-caption1);  line-height:var(--lh-caption1);  letter-spacing:var(--tr-caption1);  font-weight:var(--w-caption1)}
.ty-caption2  {font-size:var(--t-caption2);  line-height:var(--lh-caption2);  letter-spacing:var(--tr-caption2);  font-weight:var(--w-caption2)}

/* emphasis is weight, never a size bump */
.ty-em{font-weight:600}
.ty-strong{font-weight:700}

/* money, counts, dates, tables: always tabular so columns stop dancing */
.num,.mn-sched td,.pdv-table td,.stat .n,.mn-dbv,.qh-table td.num{
  font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1}

/* the hidden Dynamic Type probe (see handoff notes) */
#dtprobe{font:-apple-system-body;position:absolute;visibility:hidden;
  pointer-events:none;left:-9999px;top:0}


/* ═══ 4. GLOBAL PRESS FEEL + TOUCH TARGETS ═════════════════════════════ */

button,[role="button"],.chip,.stchip,.dd-btn,.nav-item,.tab-item,.seg button,
.act-tile,.iseg-item,.list-row{
  touch-action:manipulation;
  -webkit-tap-highlight-color:transparent;
  -webkit-user-select:none;user-select:none;
}

/* Transparent 44x44 expander: grows the TOUCH area without growing the
   graphic. Add .tap44 to any control that must stay visually small. */
.tap44{position:relative}
.tap44::after{content:"";position:absolute;top:50%;left:50%;
  transform:translate(-50%,-50%);
  min-width:44px;min-height:44px;width:100%;height:100%}

/* ── the 13 undersized controls, TOUCH DEVICES ONLY ──────────────────
   Scoped to (pointer:coarse) on purpose: a laptop keeps the existing
   compact density, a phone gets Apple's 44pt floor. */
@media (pointer:coarse){
  .icon-btn{width:44px;height:44px}
  .icon-btn.sm{width:30px;height:30px;position:relative}
  .icon-btn.sm::after{content:"";position:absolute;top:50%;left:50%;
    transform:translate(-50%,-50%);width:44px;height:44px}

  /* the most-tapped control in the app */
  .mt-check{position:relative}
  .mt-check::after{content:"";position:absolute;top:50%;left:50%;
    transform:translate(-50%,-50%);width:44px;height:44px}

  .rc-cap button{width:44px;height:44px}
  .rc-grid{grid-template-columns:repeat(7,44px)}
  .rc-grid button,.rc-grid .oday{height:44px}

  .cart-row .qty-btn,.step-row .sic,.stchip,.mini-head button{position:relative}
  .cart-row .qty-btn::after,.step-row .sic::after,.stchip::after,
  .mini-head button::after{content:"";position:absolute;top:50%;left:50%;
    transform:translate(-50%,-50%);min-width:44px;min-height:44px;
    width:100%;height:100%}

  .cact{width:44px;height:44px}
  .chip{min-height:44px;display:inline-flex;align-items:center}
  .mt-sbtn,.mn-tdone{min-height:44px}
  .btn{min-height:44px}

  /* under 16px iOS force-zooms the viewport on focus */
  input,textarea,select,
  .field input,.field select,.field textarea{font-size:max(16px,var(--t-body))}
}

/* the right keypad, not the full QWERTY — pair with inputmode in the markup */
input[inputmode="decimal"],input[type="tel"]{font-variant-numeric:tabular-nums}


/* ═══ 5. VIEWPORT + SAFE AREAS ═════════════════════════════════════════ */

/* 100vh overflows behind the iOS toolbar; svh is the small viewport. */
body{min-height:100svh}
.app{min-height:100svh}
@media (min-width:761px){ .nav{height:100svh} }

/* Move the insets off the scroll container and onto the fixed chrome.
   OPT-IN: only add html.ios-chrome once a .navbar actually exists. */
html.ios-chrome body{padding:0;overscroll-behavior-y:none}
html.ios-chrome .navbar{padding-top:var(--sa-t)}
html.ios-chrome .tabbar{padding-bottom:var(--sa-b)}
html.ios-chrome .wrap{
  padding-left:max(var(--margin),var(--sa-l));
  padding-right:max(var(--margin),var(--sa-r));
}

/* stop nested scrollers rubber-banding the whole page */
.chipbar,.nav-items,.dd-panel,.sheet,.qtoolbar{overscroll-behavior:contain}


/* ═══ 6. MATERIALS, HAIRLINES, ELEVATION ═══════════════════════════════ */

.mat{background:var(--mat-regular);
  -webkit-backdrop-filter:var(--mat-blur-regular);backdrop-filter:var(--mat-blur-regular)}
.mat-chrome{background:var(--mat-chrome);
  -webkit-backdrop-filter:var(--mat-blur-chrome);backdrop-filter:var(--mat-blur-chrome)}
.mat-thick{background:var(--mat-thick);
  -webkit-backdrop-filter:var(--mat-blur-thick);backdrop-filter:var(--mat-blur-thick)}
.mat-thin{background:var(--mat-thin);
  -webkit-backdrop-filter:var(--mat-blur-thin);backdrop-filter:var(--mat-blur-thin)}

/* both fallbacks are required — they are different conditions */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))){
  .mat,.mat-chrome,.mat-thick,.mat-thin{background:var(--grp-2)}
}
@media (prefers-reduced-transparency: reduce){
  .mat,.mat-chrome,.mat-thick,.mat-thin{background:var(--grp-2);
    -webkit-backdrop-filter:none;backdrop-filter:none}
}
@media (prefers-contrast: more){
  :root{--sep:rgba(22,24,29,.42)}
  .mat,.mat-chrome,.mat-thick,.mat-thin{background:var(--grp-2);
    -webkit-backdrop-filter:none;backdrop-filter:none;border-color:var(--label)}
}

/* ── hairlines ───────────────────────────────────────────────────────── */
.hair{border:1px solid var(--sep)}
.hair-t{border-top:1px solid var(--sep)}
.hair-b{border-bottom:1px solid var(--sep)}
@media (-webkit-min-device-pixel-ratio:2),(min-resolution:2dppx){
  .hair,.hair-t,.hair-b{border-width:.5px}
}
@media (-webkit-min-device-pixel-ratio:3),(min-resolution:3dppx){
  .hair,.hair-t,.hair-b{border-width:.34px}
}
/* bulletproof variant where fractional borders round up */
.hair-x{position:relative;border:0}
.hair-x::after{content:"";position:absolute;inset:0;pointer-events:none;
  border:1px solid var(--sep);border-radius:inherit;
  transform:scale(.5);transform-origin:0 0;width:200%;height:200%}

/* ── scroll edge effect: iOS fades content into a floating bar rather
      than drawing a rule under it. Drive --hdr from scroll position. ─── */
.scroll-edge{position:relative}
.scroll-edge::after{content:"";position:absolute;left:0;right:0;top:100%;
  height:12px;pointer-events:none;opacity:var(--hdr,0);
  transition:opacity .2s var(--e-out);
  background:linear-gradient(to bottom,var(--mat-chrome),transparent)}

/* ── shadow discipline (opt-in) ──────────────────────────────────────── */
html.ios-flat .card,html.ios-flat .mt-card,html.ios-flat .mncard,
html.ios-flat .stat,html.ios-flat .pdv-stat,html.ios-flat .up-panel{
  box-shadow:var(--el-0);border-color:var(--sep)}
html.ios-flat .fab,html.ios-flat .syncpill,html.ios-flat .toast{box-shadow:var(--el-2)}
html.ios-flat .dd-panel{box-shadow:var(--el-3)}


/* ═══ 7. MOTION ════════════════════════════════════════════════════════ */

/* ── overlay + sheet rebuild ─────────────────────────────────────────
   The inline block toggles display:none/flex, which makes the sheet
   unable to animate in, unable to animate out, and impossible to
   interrupt or drag-dismiss. opacity+visibility is interaction-
   equivalent to display:none (visibility:hidden blocks pointer events)
   and keeps the existing .show class contract intact — no JS change
   needed for the basic animation. */
.overlay{
  display:flex;
  background:var(--mat-scrim);
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px);
  opacity:0;visibility:hidden;
  transition:opacity var(--d-scrim) var(--e-out),
             visibility 0s linear var(--d-scrim);
}
.overlay.show{opacity:1;visibility:visible;
  transition:opacity var(--d-scrim) var(--e-out)}

.sheet{
  max-height:min(92svh,900px);
  box-shadow:var(--el-4);
  transform:translate3d(0,100%,0);
  transition:transform var(--spring-dur) var(--spring);
}
.overlay.show .sheet{transform:translate3d(0,0,0)}
/* while a finger is on the grabber, JS adds .dragging and sets --drag */
.sheet.dragging{transition:none;transform:translate3d(0,var(--drag,0px),0)}

/* grabber: the affordance that says "this is draggable".
   Add .no-grab to a sheet whose drag-to-dismiss is not wired yet. */
@media (max-width:639px){
  .sheet:not(.no-grab)::before{content:"";display:block;
    width:36px;height:5px;border-radius:2.5px;background:var(--fill-3);
    margin:0 auto 14px;flex:0 0 auto}
}

/* stacked sheets: push the parent back and dim it */
.overlay.has-child .sheet{transform:translate3d(0,-10px,0) scale(.94);
  border-radius:var(--r-xl);filter:brightness(.92);
  transition:transform var(--spring-dur) var(--spring),
             filter var(--d-scrim) var(--e-out)}

/* >= 640px it is a centered form-sheet: scale in, do not slide up */
@media (min-width:640px){
  .sheet{transform:translate3d(0,12px,0) scale(.97);opacity:0;
    transition:transform var(--d-sheet) var(--e-sheet),
               opacity var(--d-tab) var(--e-out)}
  .overlay.show .sheet{transform:none;opacity:1}
}

/* sticky sheet header so long forms keep their title + close button */
.sheet-head.sticky{position:sticky;top:0;z-index:2;
  padding-top:var(--sp-2);padding-bottom:var(--sp-3);
  background:var(--bg,var(--grp-1))}

/* ── layout-thrashing fixes ──────────────────────────────────────────── */
/* animating width forces layout every frame; scaleX is compositor-only */
.mn-poolbar>i{transform-origin:left center;
  transition:transform var(--d-list) var(--e-out),width var(--d-list) var(--e-out)}

/* ── press feedback: on pointer-down, not pointer-up ─────────────────── */
.btn,.chip,.stchip,.act-tile,.iseg-item,.list-row,.as-btn{
  transition:transform var(--d-press) var(--e-out),
             background var(--d-press) var(--e-out)}

/* ── tab / panel cross-fade ──────────────────────────────────────────── */
.tab-panel-enter{animation:ios-panel-in var(--d-tab) var(--e-out) both}
@keyframes ios-panel-in{from{opacity:0;transform:translateY(4px)}}

/* ── list row insert / remove ────────────────────────────────────────── */
.row-in{animation:ios-row-in var(--d-list) var(--e-out) both}
.row-out{animation:ios-row-out var(--d-list) var(--e-in) both}
@keyframes ios-row-in{from{opacity:0;transform:translateY(-6px)}}
@keyframes ios-row-out{to{opacity:0;transform:translateX(24px)}}

/* ── View Transitions: free cross-fade on tab switch, free FLIP on the
      Employees list when a role's tab set changes. Wrap re-renders in
      document.startViewTransition() and this is all the CSS needed. ─── */
::view-transition-old(root){animation:ios-vt-out var(--d-tab) var(--e-in) both}
::view-transition-new(root){animation:ios-vt-in  var(--d-tab) var(--e-out) both}
@keyframes ios-vt-out{to{opacity:0}}
@keyframes ios-vt-in{from{opacity:0;transform:translateY(4px)}}
.tabbar{view-transition-name:ios-tabbar}
.navbar{view-transition-name:ios-navbar}

/* ── reduced motion ──────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
    scroll-behavior:auto !important;
  }
  /* keep the comprehension-bearing cross-fade, drop the translation */
  .overlay{transition:opacity 180ms linear !important}
  .sheet{transform:none !important;opacity:0;
    transition:opacity 180ms linear !important}
  .overlay.show .sheet{opacity:1;transform:none !important}
  ::view-transition-group(*),::view-transition-old(*),::view-transition-new(*){
    animation:none !important}
  /* the ~0.5Hz infinite pulse is exactly the oscillation the HIG warns
     about — and it animates box-shadow, which is not compositable */
  .pend-tag{animation:none !important;box-shadow:0 0 0 3px var(--yellow-fill) !important}
}

/* Even with motion allowed, an infinite box-shadow loop burns compositor
   time for as long as the tab is open. Static badge, same urgency.
   Remove this rule if you decide you want the pulse back. */
.pend-tag{animation:none;box-shadow:0 0 0 3px var(--yellow-fill)}

/* used by .ptr.spinning and .syncpill .sspin */
@keyframes spin{to{transform:rotate(360deg)}}


/* ═══ 8. BOTTOM TAB BAR (< 761px) ══════════════════════════════════════
   Self-activating: the sidebar only hides once a .tabbar exists in the
   DOM. html.ios-tabbar is the explicit alternative if :has() is a problem.
   iOS allows at most 5 items — build 4 primary + More, and take the
   primary set from the backend's permsForRole() tab list so a role that
   loses a tab loses it here too. */

.tabbar{
  position:fixed;left:0;right:0;bottom:0;z-index:80;display:none;
  height:calc(var(--tabbar-h) + var(--sa-b));padding-bottom:var(--sa-b);
  border-top:.5px solid var(--sep);
  background:var(--mat-chrome);
  -webkit-backdrop-filter:var(--mat-blur-chrome);backdrop-filter:var(--mat-blur-chrome);
}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .tabbar{background:var(--grp-2)}
}

.tab-item{position:relative;flex:1 1 0;min-width:0;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:2px;height:var(--tabbar-h);color:var(--label-3);
  transition:color var(--d-micro) var(--e-out)}
.tab-item .ic{font-size:24px;line-height:1;
  transition:transform var(--d-micro) var(--e-out)}
.tab-item .lbl{font-size:10px;line-height:12px;font-weight:600;letter-spacing:.005em;
  max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tab-item[aria-selected="true"]{color:var(--tint)}
.tab-item[aria-selected="true"] .ic{transform:scale(1.04)}
.tab-item:active .ic{transform:scale(.92);transition-duration:var(--d-press)}
.tab-item .bdg{position:absolute;top:2px;left:50%;margin-left:6px;
  min-width:18px;height:18px;padding:0 5px;border-radius:9px;
  background:var(--red);color:#fff;
  font-size:11px;font-weight:700;line-height:18px;text-align:center}

@media (max-width:760px){
  body:has(.tabbar) .tabbar,
  html.ios-tabbar .tabbar{display:flex}
  body:has(.tabbar) .nav,
  html.ios-tabbar .nav{display:none}

  /* nothing may hide behind the bar */
  body:has(.tabbar) .wrap,
  html.ios-tabbar .wrap{padding-bottom:calc(var(--tabbar-h) + var(--sa-b) + var(--sp-6))}
  body:has(.tabbar) .fab,
  html.ios-tabbar .fab{bottom:calc(var(--tabbar-h) + var(--sa-b) + var(--sp-4))}
  body:has(.tabbar) .syncpill,
  html.ios-tabbar .syncpill{bottom:calc(var(--tabbar-h) + var(--sa-b) + var(--sp-2))}
  body:has(.tabbar) .toast,
  html.ios-tabbar .toast{bottom:calc(var(--tabbar-h) + var(--sa-b) + var(--sp-4))}
}
@media (min-width:761px){ .tabbar{display:none} }


/* ═══ 9. LARGE-TITLE NAV BAR ═══════════════════════════════════════════
   --hdr goes 0 (expanded) -> 1 (collapsed); drive it from scrollY. */

.navbar{position:sticky;top:0;z-index:60;
  padding-top:var(--sa-t);
  padding-left:max(var(--margin),var(--sa-l));
  padding-right:max(var(--margin),var(--sa-r))}
.nav-row{position:relative;height:var(--navbar-h);
  display:flex;align-items:center;gap:var(--sp-2)}
.nav-back{display:flex;align-items:center;gap:2px;flex:0 0 auto;
  margin-left:-6px;min-height:44px;color:var(--tint);
  font-size:var(--t-body);font-weight:400;letter-spacing:var(--tr-body)}
.nav-back:active{opacity:.4;transition:opacity var(--d-press) var(--e-out)}
.nav-back[hidden]{display:none}
.nav-actions{margin-left:auto;display:flex;gap:var(--sp-2);align-items:center}

/* the small centred title fades in exactly as the large one leaves */
.nav-title-sm{position:absolute;left:50%;transform:translateX(-50%);
  font-size:var(--t-headline);font-weight:var(--w-headline);
  letter-spacing:var(--tr-headline);
  opacity:var(--hdr,0);transition:opacity 120ms var(--e-out);pointer-events:none}

.nav-title-lg{height:calc(var(--largetitle-h) * (1 - var(--hdr,0)));
  overflow:hidden;padding-bottom:var(--sp-2);
  opacity:calc(1 - var(--hdr,0) * 1.6);
  transform:translateY(calc(var(--hdr,0) * -8px));
  transform-origin:left bottom;will-change:height,opacity}

@media (min-width:761px){
  .nav-title-lg{height:auto;opacity:1;transform:none}
  .nav-title-sm{display:none}
}


/* ═══ 10. SWIPE-BACK (standalone has no browser back) ══════════════════
   In display:standalone there is no edge-swipe and no back button, so a
   deep link into a detail view is a dead end unless we provide both. */

.edge-back{display:none;position:fixed;left:0;top:0;bottom:0;width:20px;
  z-index:90;touch-action:pan-y}
html.is-standalone .edge-back{display:block}

.page{transition:transform var(--d-nav) var(--e-sheet)}
.page.dragging{transition:none;transform:translate3d(var(--px,0px),0,0)}
/* the outgoing page slides back 30% and dims, as UIKit does */
.page.behind{transform:translate3d(-30%,0,0);filter:brightness(.86)}


/* ═══ 11. CONTROLS ═════════════════════════════════════════════════════ */

/* ── switch ──────────────────────────────────────────────────────────
   Safari 17.4+ renders <input type="checkbox" switch> as the real iOS
   toggle WITH the system toggle haptic. navigator.vibrate does not exist
   on iOS, so that is the ONLY route to haptic feedback in this app.
   This is the control for the Employees tab: one per tab per role, one
   per employee override.

   ⚠️ Do NOT gate this with `@supports selector(input[switch])`. That tests
   whether the SELECTOR parses, and `input[switch]` is an ordinary attribute
   selector that every browser parses — the condition is always true, so the
   fallback would never render anywhere. Verified in Chromium: it reports
   true while `'switch' in HTMLInputElement.prototype` is false.

   So: the CSS switch below is the DEFAULT (correct everywhere, no JS
   needed), and one line of JS opts Safari into the native control:
     if ('switch' in HTMLInputElement.prototype)
       document.documentElement.classList.add('has-switch');
   Markup always carries the attribute:
     <input type="checkbox" switch class="sw"> */

/* the CSS switch is the BASE — correct everywhere, exact iOS metrics
   (51x31 track, 27 knob, 2 inset), no JS required */
input[type=checkbox].sw{
  appearance:none;-webkit-appearance:none;
  position:relative;width:51px;height:31px;flex:0 0 auto;
  border-radius:15.5px;background:var(--fill-2);cursor:pointer;border:none;
  transition:background var(--d-micro) var(--e-out)}
input[type=checkbox].sw::after{
  content:"";position:absolute;top:2px;left:2px;
  width:27px;height:27px;border-radius:13.5px;background:#fff;
  box-shadow:0 3px 8px rgba(0,0,0,.15),0 1px 1px rgba(0,0,0,.16);
  transition:transform var(--d-micro) var(--e-sheet),
             width var(--d-micro) var(--e-out)}
input[type=checkbox].sw:checked{background:var(--tint)}
input[type=checkbox].sw:checked::after{transform:translateX(20px)}
/* the knob stretches under the finger — the detail that sells it */
input[type=checkbox].sw:active::after{width:32px}
input[type=checkbox].sw:checked:active::after{transform:translateX(15px)}
input[type=checkbox].sw:focus-visible{outline:2px solid var(--tint);outline-offset:2px}
input[type=checkbox].sw:disabled{opacity:.45;pointer-events:none}

/* Safari 17.4+ hands back the real control (and its haptic) only when BOTH
   the html class and the switch attribute are present, so an input that
   forgot the attribute still gets the CSS switch above instead of nothing. */
html.has-switch input[switch].sw,
html.has-switch input[switch].sw:checked,
html.has-switch input[switch].sw:active{
  appearance:auto;-webkit-appearance:auto;accent-color:var(--tint);
  width:51px;height:31px;margin:0;
  background:none;border-radius:0;box-shadow:none}
html.has-switch input[switch].sw::after{content:none}

/* ── segmented control ───────────────────────────────────────────────
   NAMED .iseg, not .seg — dashboard.html already owns .seg. */
.iseg{position:relative;display:inline-flex;padding:2px;border-radius:9px;
  background:var(--fill-1);isolation:isolate}
.iseg::before{content:"";position:absolute;top:2px;left:2px;z-index:0;
  width:var(--seg-w,0px);height:calc(100% - 4px);border-radius:7px;
  background:var(--grp-2);
  box-shadow:0 3px 8px rgba(0,0,0,.12),0 1px 1px rgba(0,0,0,.04);
  transform:translateX(var(--seg-x,0px));
  transition:transform var(--d-micro) var(--e-sheet),
             width var(--d-micro) var(--e-sheet)}
.iseg-item{position:relative;z-index:1;flex:1 1 0;min-height:32px;
  padding:0 var(--sp-3);border:none;background:none;cursor:pointer;
  font-size:var(--t-footnote);font-weight:600;letter-spacing:var(--tr-footnote);
  color:var(--label-2);white-space:nowrap;
  transition:color var(--d-micro) var(--e-out)}
.iseg-item[aria-selected="true"]{color:var(--label)}
.iseg-item:active{transform:scale(.96)}
.iseg:has(.iseg-item:active)::before{transform:translateX(var(--seg-x,0px)) scale(.97)}
@media (pointer:coarse){ .iseg-item{min-height:40px} }

/* ── inset grouped list: the primitive for the Employees tab ─────────
   Role -> tab switches and per-employee overrides are literally an iOS
   Settings screen. Build them from this, not from cards-with-shadows. */
.list-sec{margin:0 0 var(--sp-8)}
.list-hdr{padding:0 var(--sp-4) var(--sp-2);
  font-size:var(--t-footnote);line-height:var(--lh-footnote);
  letter-spacing:.06em;text-transform:uppercase;color:var(--label-2)}
.list{background:var(--grp-2);border-radius:var(--r-lg);overflow:hidden;
  box-shadow:var(--el-0)}
.list-row{position:relative;display:flex;align-items:center;gap:var(--sp-3);
  width:100%;min-height:var(--row-min);padding:var(--sp-2) var(--sp-4);
  text-align:left;border:none;background:none;color:inherit;cursor:pointer}
.list-row:active{background:var(--fill-1)}
/* separator inset from the leading content, full-bleed right — the iOS detail */
.list-row::after{content:"";position:absolute;left:var(--row-inset);right:0;
  bottom:0;height:.5px;background:var(--sep)}
.list-row:last-child::after{display:none}
.list-row.has-icon::after{left:calc(var(--row-inset) + 29px + var(--sp-3))}
.list-row .lr-main{flex:1;min-width:0}
.list-row .lr-t{font-size:var(--t-body);line-height:var(--lh-body);
  letter-spacing:var(--tr-body)}
.list-row .lr-s{font-size:var(--t-footnote);line-height:var(--lh-footnote);
  color:var(--label-2);margin-top:1px}
.list-row .lr-v{font-size:var(--t-body);color:var(--label-2);flex:0 0 auto}
.list-row .lr-chev{flex:0 0 auto;color:var(--label-4);
  font-size:var(--t-callout);font-weight:600;
  transition:transform var(--d-micro) var(--e-sheet)}
.list-icon{flex:0 0 auto;width:29px;height:29px;border-radius:7px;
  display:grid;place-items:center;font-size:16px;color:#fff}

/* expand in place — no popups (standing rule) */
.list-detail{display:grid;grid-template-rows:0fr;
  transition:grid-template-rows var(--d-list) var(--e-sheet)}
.list-detail>div{overflow:hidden;min-height:0}
.list-row[aria-expanded="true"]+.list-detail{grid-template-rows:1fr}
.list-row[aria-expanded="true"] .lr-chev{transform:rotate(90deg)}

/* ── action sheet: for destructive choices; replaces confirm() ───────── */
.actionsheet{width:100%;max-width:min(420px,calc(100vw - 2*var(--sp-2)));
  margin:0 auto calc(var(--sp-2) + var(--sa-b));
  display:flex;flex-direction:column;gap:var(--sp-2)}
.as-group{border-radius:var(--r-md);overflow:hidden;
  background:var(--mat-thick);
  -webkit-backdrop-filter:var(--mat-blur-thick);backdrop-filter:var(--mat-blur-thick);
  box-shadow:var(--el-4)}
.as-title{padding:var(--sp-4) var(--sp-4) var(--sp-3);text-align:center;
  font-size:var(--t-footnote);line-height:var(--lh-footnote);color:var(--label-2);
  border-bottom:.5px solid var(--sep)}
.as-btn{width:100%;min-height:57px;padding:0 var(--sp-4);
  border:none;background:none;cursor:pointer;
  font-size:calc(20px * var(--dt));line-height:25px;
  letter-spacing:var(--tr-title3);font-weight:400;color:var(--tint);
  border-bottom:.5px solid var(--sep)}
.as-btn:last-child{border-bottom:none}
.as-btn:active{background:var(--fill-2)}
.as-btn.destructive{color:var(--red)}
.as-btn.cancel{font-weight:600;color:var(--label)}
.as-group.cancel-group{margin-top:var(--sp-1)}

/* ── pull to refresh ─────────────────────────────────────────────────
   Arms only at scrollTop 0; threshold 80px; rubber-band past it. */
.ptr{position:absolute;top:0;left:50%;
  transform:translate(-50%,calc(-100% + var(--ptr,0px)));
  width:28px;height:28px;pointer-events:none;
  opacity:calc(var(--ptr,0) / 80)}
.ptr .ring{width:28px;height:28px;border-radius:50%;
  border:2.5px solid var(--label-3);border-top-color:transparent;
  transform:rotate(calc(var(--ptr,0) * 3deg))}
.ptr.armed .ring{border-color:var(--tint);border-top-color:transparent}
.ptr.spinning .ring{animation:spin .8s linear infinite}


/* ═══ 12. WIDE / FULLSCREEN FORMS ══════════════════════════════════════
   Target: every entry form fits one screen at >=1024px with no scrolling,
   and reflows to a single column on a phone.
   >=1024px -> 3 columns, 640-1023 -> 2, <640 -> 1 + bottom sheet. */

.sheet.w-md{max-width:min(760px,94vw)}
.sheet.w-lg{max-width:min(1040px,94vw)}
.sheet.w-xl{max-width:min(1320px,96vw)}

.form-grid{display:grid;gap:var(--sp-4);align-items:start;
  grid-template-columns:repeat(auto-fit,minmax(280px,1fr))}
.form-sec{background:var(--grp-2);border-radius:var(--r-lg);
  padding:var(--sp-4);border:.5px solid var(--sep)}
.form-sec--wide{grid-column:1 / -1}     /* notes, line items, map */
.form-sec-t{font-size:var(--t-footnote);letter-spacing:.06em;
  text-transform:uppercase;color:var(--label-2);margin:0 0 var(--sp-3)}

/* two or three fields on one line inside a section */
.field-row{display:grid;gap:var(--sp-3);
  grid-template-columns:repeat(auto-fit,minmax(140px,1fr))}

/* sentence-case iOS field labels (the uppercase eyebrow is a Material
   convention). Opt in per form with .form-sec so nothing else moves. */
.form-sec .field>label{margin:0 0 var(--sp-1);
  font-size:var(--t-footnote);line-height:var(--lh-footnote);
  letter-spacing:0;text-transform:none;font-weight:400;color:var(--label-2)}
.form-sec .field input,.form-sec .field textarea,
.form-sec .dd-btn,.form-sec .date-btn{
  min-height:var(--row-min);padding:11px var(--sp-3);border-radius:var(--r-sm);
  border:.5px solid var(--sep);background:var(--grp-3)}
.form-sec .field input:focus,.form-sec .field textarea:focus{
  border-color:var(--tint);background:var(--grp-2);
  box-shadow:0 0 0 3px var(--tint-fill-2)}
.form-sec .field input::placeholder{color:var(--label-3)}
.form-sec textarea{resize:none;min-height:88px;line-height:1.45}

/* sticky action footer — floats over the form as a material */
.form-foot{position:sticky;bottom:0;z-index:3;
  margin:var(--sp-4) calc(-1 * var(--margin)) 0;
  padding:var(--sp-3) var(--margin) calc(var(--sp-3) + var(--sa-b));
  display:flex;gap:var(--sp-2);justify-content:flex-end;align-items:center;
  border-top:.5px solid var(--sep);
  background:var(--mat-chrome);
  -webkit-backdrop-filter:var(--mat-blur-chrome);backdrop-filter:var(--mat-blur-chrome)}
.form-foot .grow{margin-right:auto}

@media (max-width:639px){
  .form-grid{grid-template-columns:1fr}
  .form-foot{flex-direction:column-reverse;align-items:stretch}
  .form-foot .btn{width:100%;min-height:50px}
}


/* ═══ 13. STANDALONE / PWA ═════════════════════════════════════════════ */

/* nothing in the installed app should look selectable or draggable */
html.is-standalone body{-webkit-user-select:none;user-select:none;
  -webkit-touch-callout:none}
html.is-standalone input,html.is-standalone textarea,
html.is-standalone [contenteditable]{-webkit-user-select:text;user-select:text}

/* a distinct offline state for the sync pill: waiting, not failed */
.syncpill.offline{color:var(--label-2);border-color:var(--sep-opaque);
  background:var(--fill-1);opacity:1}
.syncpill.offline .sd{background:var(--label-3)}

/* install hint, if the orchestrator ever surfaces one */
.ios-install{display:none}
html:not(.is-standalone) .ios-install.show{display:flex}

/* ── print: undo the iOS sheet chrome ─────────────────────────────────────────
   printQuotation() prints while the sheet is open, and dashboard.html's own
   @media print{.overlay{background:none}} has equal specificity — ios.css is
   linked last, so without this the printed quotation carried a dark scrim and a
   backdrop blur. (2026-08-11 review defect D4.) */
@media print{
  .overlay{ background:none !important; -webkit-backdrop-filter:none !important;
            backdrop-filter:none !important; opacity:1 !important; visibility:visible !important; }
  .sheet{ max-height:none !important; box-shadow:none !important; transform:none !important; }
  .sheet::before{ display:none !important; }      /* the drag grabber */
}
