/* ================================================================
   Fast & Fresh — UI v4 "Fresh" design system (built from scratch)
   Theme   : clean light, teal/cyan brand
   Shells  : Manager = native-app mobile · Admin/CO = web sidebar
   Note    : component class names match the pages — logic untouched
   ================================================================ */

:root{
  /* canvas + surfaces */
  --bg:#f2f5f7;            /* page canvas — also used by the Android app */
  --surface:#ffffff;
  --surface-2:#f7f9fb;
  --line:#e3e9ef;
  --line-2:#d2dbe3;

  /* ink */
  --ink:#13202e;
  --muted:#62707f;
  --muted-2:#909caa;

  /* brand — fresh teal/cyan */
  --brand:#0f766e;
  --brand-2:#0d9488;
  --brand-grad:linear-gradient(135deg,#0d9488 0%,#0891b2 100%);
  --brand-soft:#e6f5f3;
  --brand-ring:0 0 0 3px rgba(13,148,136,.18);

  /* shell (dark) */
  --shell-1:#0b2e2c;
  --shell-2:#11403c;

  /* semantic */
  --ok:#15803d;     --ok-bg:#e5f6ea;    --ok-bd:#bce5c8;
  --warn:#b45309;   --warn-bg:#fcf2dd;  --warn-bd:#f3deab;
  --bad:#b91c1c;    --bad-bg:#fcebea;   --bad-bd:#f3c7c5;
  --inf:#0e7490;    --inf-bg:#e3f3f8;   --inf-bd:#bfe2ed;

  /* shape + depth */
  --r-xl:16px; --r-lg:14px; --r-md:11px; --r-sm:9px;
  --sh-1:0 1px 2px rgba(19,32,46,.05);
  --sh-2:0 3px 12px rgba(19,32,46,.07);
  --sh-3:0 16px 44px rgba(19,32,46,.18);

  /* shell metrics */
  --topbar-h:62px;
  --sidebar-w:248px;
  --tabbar-h:64px;

  /* Material 3 motion tokens — every transition/animation maps onto these.
     Durations: short = state changes (hover/focus), med = component and
     screen enter/exit, long = large surfaces (sheets, sidebar).
     Easing: std = standard, decel = emphasized-decelerate (entering),
     accel = standard-accelerate (exiting). */
  --m-short:150ms;
  --m-med:250ms;
  --m-long:300ms;
  --e-std:cubic-bezier(.2,0,0,1);
  --e-decel:cubic-bezier(.05,.7,.1,1);
  --e-accel:cubic-bezier(.3,0,1,1);
}

/* ---------------- base ---------------- */
*{ box-sizing:border-box; -webkit-tap-highlight-color:transparent; }
html{ background:var(--bg); }
/* Always keep the vertical scrollbar present so the centered layout NEVER
   jumps left when page height changes between pages (dashboard -> lists,
   reloads, modals). Works in every browser; on touch devices scrollbars are
   overlay and take no space, so this is a no-op there. */
html{ overflow-y:scroll; scrollbar-gutter:stable; }
html,body{ height:100%; }
body{
  margin:0;
  font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
  font-size:14px; line-height:1.5; color:var(--ink);
  background:var(--bg);
  -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility;
  overscroll-behavior-y:none;
}
a{ color:var(--brand); text-decoration:none; }
img{ border:0; max-width:100%; }
h1,h2,h3,h4{ margin:0; }
i.fa,i.fas,i.far,i.fab,i[class^="fa-"],i[class*=" fa-"]{ display:none; }

/* hover effects only where a real pointer exists (never hover-only on touch) */
@media (hover:hover){ a:hover{ text-decoration:underline; } }
@media (hover:none){ ::-webkit-scrollbar{ width:0; height:0; } }

/* Touch feel: `manipulation` exempts controls from double-tap-zoom detection
   so taps commit instantly and rapid tapping can never zoom-jitter; UI chrome
   never sprouts text-selection handles mid-press (page content stays
   selectable — copying table data still works). */
a,button,label,input,select,textarea{ touch-action:manipulation; }
.mtopbar,.topbar,.bottomnav,.sidebar nav,.btn,.page-actions{
  user-select:none; -webkit-user-select:none; }

/* screen-enter motion — opacity ONLY. The old 6px translateY made every full
   page load visibly "settle" upward (and raced the Android app's injected
   override for a few first-paint frames = a moment of trembling). A pure fade
   cannot move layout: zero cumulative layout shift on reloads, web and app. */
@keyframes screenIn{ from{ opacity:0; } to{ opacity:1; } }
.content{ animation:screenIn var(--m-med) var(--e-decel); }
@media (prefers-reduced-motion:reduce){ *{ animation:none !important; transition:none !important; } }

/* ================================================================
   WEB SHELL  (Admin / Computer Operator)
   ================================================================ */
.app{ display:flex; min-height:100vh; }

.sidebar{
  width:var(--sidebar-w); flex:0 0 var(--sidebar-w);
  position:fixed; inset:0 auto 0 0; z-index:60;
  display:flex; flex-direction:column;
  background:linear-gradient(180deg,var(--shell-1),var(--shell-2));
  color:#fff; padding:16px 13px;
  transition:transform var(--m-long) var(--e-std);
}
.sidebar .brand{
  display:flex; align-items:center; gap:11px;
  padding:6px 9px 16px; margin-bottom:8px;
  border-bottom:1px solid rgba(255,255,255,.09);
}
.sidebar .brand .logo{
  width:40px; height:40px; border-radius:12px; flex:0 0 40px;
  background:var(--brand-grad);
  display:flex; align-items:center; justify-content:center;
  font-weight:800; font-size:19px; color:#fff;
  box-shadow:0 5px 14px rgba(8,145,178,.40);
}
.sidebar .brand .bt{ font-size:14.5px; font-weight:800; letter-spacing:.2px; line-height:1.15; }
.sidebar .brand .bs{ font-size:11px; color:rgba(255,255,255,.55); }

.sidebar nav{ display:flex; flex-direction:column; gap:3px; margin-top:8px; overflow-y:auto; }
.sidebar nav .navlabel{
  font-size:10px; text-transform:uppercase; letter-spacing:.1em;
  color:rgba(255,255,255,.4); padding:12px 12px 5px; font-weight:700;
}
.sidebar nav a{
  display:flex; align-items:center; gap:11px;
  padding:11px 12px; border-radius:11px;
  color:rgba(255,255,255,.74); font-size:13.5px; font-weight:600;
  text-decoration:none; white-space:nowrap;
}
.sidebar nav a svg{ width:19px; height:19px; flex:0 0 19px; }
@media (hover:hover){
  .sidebar nav a:hover{ background:rgba(255,255,255,.09); color:#fff; text-decoration:none; }
}
.sidebar nav a:active{ background:rgba(255,255,255,.14); }
.sidebar nav a.active{
  background:var(--brand-grad); color:#fff;
  box-shadow:0 6px 16px rgba(8,145,178,.42);
}
.sidebar .side-foot{ margin-top:auto; padding-top:12px; }
.scrim{ display:none; }

.main{
  margin-left:var(--sidebar-w); flex:1 1 auto; min-width:0;
  display:flex; flex-direction:column; min-height:100vh;
}
.topbar{
  position:sticky; top:0; z-index:40;
  display:flex; align-items:center; gap:14px;
  height:var(--topbar-h); padding:0 22px;
  background:var(--surface);
  border-bottom:1px solid var(--line);
  /* own compositing layer: sticky bar over scrolling content is rastered
     once and only composited per frame, instead of repainting (R2 §5.2) */
  will-change:transform;
}
.topbar .tt{ min-width:0; }
.topbar .tt h1{ font-size:17px; font-weight:800; letter-spacing:-.01em; line-height:1.2; }
.topbar .tt .sub{ font-size:12px; color:var(--muted); margin-top:1px; }
.topbar .grow{ flex:1 1 auto; }
.topbar .tb-actions{ display:flex; gap:8px; flex-wrap:wrap; align-items:center; }
.topbar .userchip{ display:flex; align-items:center; gap:9px; }
.topbar .userchip .who{ text-align:right; line-height:1.15; }
.topbar .userchip .who .n{ font-size:12.5px; font-weight:700; }
.topbar .userchip .who .r{ font-size:11px; color:var(--muted); }
.topbar .iconbtn{
  display:inline-flex; align-items:center; justify-content:center;
  width:37px; height:37px; border-radius:10px; border:1px solid var(--line);
  background:var(--surface); color:var(--muted); cursor:pointer;
}
@media (hover:hover){
  .topbar .iconbtn:hover{ background:var(--surface-2); color:var(--ink); text-decoration:none; }
}
.topbar .iconbtn:active{ background:var(--surface-2); }
.topbar .iconbtn svg{ width:18px; height:18px; }
.hamburger{ display:none; }

.avatar{
  width:38px; height:38px; border-radius:50%; flex:0 0 38px;
  display:flex; align-items:center; justify-content:center;
  background:var(--brand-grad); color:#fff; font-weight:700; font-size:14px;
}
.side-avatar{
  border-radius:50%; display:inline-flex; align-items:center; justify-content:center;
  background:var(--brand-grad); color:#fff; font-weight:700;
}

.content{ width:100%; max-width:1180px; margin:0 auto; padding:22px; flex:1 1 auto; }

/* ================================================================
   MOBILE APP SHELL  (Manager)
   ================================================================ */
.app.mobile{ display:block; }
.app.mobile .content{
  max-width:640px;
  padding:15px 14px calc(var(--tabbar-h) + env(safe-area-inset-bottom,0px) + 22px);
}

.mtopbar{
  position:sticky; top:0; z-index:40;
  display:flex; align-items:center; gap:12px;
  min-height:60px;
  padding:calc(9px + env(safe-area-inset-top,0px)) 16px 9px;
  color:#fff;
  background:linear-gradient(120deg,#0b2e2c 0%,#0f766e 55%,#0891b2 130%);
  box-shadow:0 2px 14px rgba(11,46,44,.32);
  /* own compositing layer: the 14px blur shadow is rastered once instead of
     repainting under every scrolled frame (audit R1 §5.2) */
  will-change:transform;
}
.mtopbar .logo{
  width:36px; height:36px; border-radius:11px; flex:0 0 36px;
  background:rgba(255,255,255,.16);
  display:flex; align-items:center; justify-content:center;
  font-weight:800; font-size:17px;
}
.mtopbar .mt{ margin:0; min-width:0; flex:1 1 auto; }
.mtopbar .mt h1{ font-size:17px; font-weight:800; letter-spacing:-.01em; line-height:1.15; }
.mtopbar .mt .sub{ font-size:11.5px; color:rgba(255,255,255,.8); margin-top:1px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.mtopbar .miconbtn{
  display:inline-flex; align-items:center; justify-content:center;
  width:38px; height:38px; border-radius:11px; color:#fff;
  background:rgba(255,255,255,.14);
}
.mtopbar .miconbtn:active{ background:rgba(255,255,255,.3); }
.mtopbar .miconbtn svg{ width:19px; height:19px; }

.app.mobile .content > .page-actions{
  display:flex; gap:9px; overflow-x:auto; margin-bottom:13px; padding-bottom:2px;
  scrollbar-width:none;
}
.app.mobile .content > .page-actions::-webkit-scrollbar{ display:none; }
.app.mobile .content > .page-actions .btn{ flex:0 0 auto; }

/* bottom tab bar — active tab gets a top indicator + tint */
.bottomnav{
  position:fixed; left:0; right:0; bottom:0; z-index:50;
  height:calc(var(--tabbar-h) + env(safe-area-inset-bottom,0px));
  padding-bottom:env(safe-area-inset-bottom,0px);
  display:flex; background:var(--surface);
  border-top:1px solid var(--line);
  box-shadow:0 -4px 20px rgba(19,32,46,.08);
  /* own compositing layer: the 20px blur shadow is rastered once instead of
     repainting under every scrolled frame (audit R1 §5.2) */
  will-change:transform;
}
.bottomnav a{
  position:relative; flex:1 1 0; min-width:0;
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:3px;
  color:var(--muted-2); font-size:10.5px; font-weight:600; text-decoration:none;
  padding:8px 2px 6px;
  /* animates the optimistic tab switch (app.js) — M3 standard easing */
  transition:color var(--m-med) var(--e-std);
}
.bottomnav a::after{
  content:""; position:absolute; top:0; left:50%; transform:translateX(-50%);
  width:0; height:3px; border-radius:0 0 3px 3px; background:var(--brand-grad);
  transition:width var(--m-med) var(--e-std);
}
.bottomnav a svg{ width:22px; height:22px; transition:transform var(--m-short) var(--e-std); }
.bottomnav a span{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:100%; }
.bottomnav a.active{ color:var(--brand); font-weight:700; }
.bottomnav a.active::after{ width:34px; }
.bottomnav a:active svg{ transform:scale(.88); }

/* ================================================================
   Cards
   ================================================================ */
.card,.box{
  background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r-lg); box-shadow:var(--sh-1);
  margin-bottom:14px; overflow:hidden;
}
.card-head,.box-head{
  display:flex; align-items:center; justify-content:space-between; gap:10px;
  padding:13px 16px; border-bottom:1px solid var(--line);
}
.card-head h3,.box-head h3{ font-size:14px; font-weight:700; }
.card-body,.box-body,.card-pad{ padding:16px; }

/* ================================================================
   Stat tiles — white card, gradient top strip, big number
   ================================================================ */
.stats-grid{ display:grid; grid-template-columns:repeat(auto-fit,minmax(165px,1fr)); gap:12px; margin-bottom:14px; }
.stat{
  position:relative; background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r-md); box-shadow:var(--sh-1);
  padding:16px 16px 13px; overflow:hidden;
}
.stat::before{ content:""; position:absolute; top:0; left:0; right:0; height:3px; background:var(--brand-grad); }
.stat .ico{ display:none; }
.stat .val{ font-size:27px; font-weight:800; letter-spacing:-.02em; line-height:1.05; color:var(--ink); }
.stat .lbl{ font-size:10.5px; font-weight:700; color:var(--muted); text-transform:uppercase; letter-spacing:.06em; margin-top:6px; }
.stat a{ color:inherit; }

/* ================================================================
   Buttons — touch-first
   ================================================================ */
.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:7px;
  font-family:inherit; font-size:13px; font-weight:700; line-height:1;
  /* 44px = one control height everywhere (inputs, selects, toolbar and
     inline-form buttons are already 44) — proper thumb target + one rhythm */
  min-height:44px; padding:9px 16px; border-radius:var(--r-sm); cursor:pointer; white-space:nowrap;
  border:1px solid var(--line-2); background:var(--surface); color:var(--ink);
  text-decoration:none; user-select:none;
  /* press transform stays near-instant (state layer); the rest use tokens */
  transition:background var(--m-short) var(--e-std),
             box-shadow var(--m-short) var(--e-std), transform .06s;
}
@media (hover:hover){
  .btn:hover{ background:var(--surface-2); text-decoration:none; box-shadow:var(--sh-1); }
}
.btn:active{ transform:scale(.97); filter:brightness(.92); }

/* Press feedback for everything else. The default tap flash is removed
   globally (tap-highlight-color: transparent), so every tappable element
   needs its own visible pressed state: plain links and link-wrapped tiles
   dim while pressed; elements that already have richer dedicated states
   (.btn scale, nav backgrounds, icon-button tints) opt back out. Pressed
   states are intentionally immediate — M3 state layers apply instantly,
   transition tokens are for state *changes*, not press-and-hold. */
a:active{ opacity:.6; }
a.btn:active,.bottomnav a:active,.sidebar nav a:active,
.topbar .iconbtn:active,.mtopbar .miconbtn:active{ opacity:1; }
button:active{ filter:brightness(.92); }
.btn:focus-visible{ outline:none; box-shadow:var(--brand-ring); }
.btn svg{ width:16px; height:16px; }
.btn-primary{
  background:var(--brand-grad); border-color:transparent; color:#fff;
  box-shadow:0 4px 12px rgba(8,145,178,.32);
}
.btn-primary:active{ box-shadow:0 2px 5px rgba(8,145,178,.32); }
.btn-success{ background:linear-gradient(135deg,#22c55e,#15803d); border-color:transparent; color:#fff; box-shadow:0 4px 12px rgba(21,128,61,.28); }
.btn-danger{ background:linear-gradient(135deg,#ef4444,#b91c1c); border-color:transparent; color:#fff; }
.btn-warning{ background:linear-gradient(135deg,#f59e0b,#d97706); border-color:transparent; color:#fff; }
.btn-light{ background:var(--surface); color:var(--ink); }
.btn-sm{ min-height:34px; padding:6px 12px; font-size:12px; border-radius:8px; position:relative; }
/* invisible hit-area extension: compact row buttons keep their size but the
   TOUCH target reaches ~44px (M3 minimum) — fewer missed taps in tables */
.btn-sm::after{ content:""; position:absolute; inset:-5px; }
.btn-icon{ padding:7px; }
.btn-block{ display:flex; width:100%; }
.btn:disabled{ opacity:.55; cursor:default; box-shadow:none; }

/* Busy submit state — set by app.js the moment a form really submits:
   freezes the button (no second tap can post twice) and shows a spinner.
   The spinner OVERLAYS the centre while the label turns transparent (still
   occupying its space), so the button keeps its exact size — the old inline
   spinner pushed the label sideways, a visible jolt on every submit. */
.btn--busy{ pointer-events:none; opacity:.85; position:relative; color:transparent !important; }
.btn--busy::before{
  content:""; position:absolute; left:50%; top:50%;
  width:14px; height:14px; margin:-7px 0 0 -7px;
  border-radius:50%; border:2px solid var(--busy-spin,#42505e); border-right-color:transparent;
  animation:btnspin .8s linear infinite;
}
/* gradient variants have white labels -> white spinner */
.btn-primary.btn--busy,.btn-success.btn--busy,
.btn-danger.btn--busy,.btn-warning.btn--busy{ --busy-spin:rgba(255,255,255,.95); }
@keyframes btnspin{ to{ transform:rotate(360deg); } }

/* Same invisible hit-area extension for the compact icon buttons and the
   modal close — visually unchanged, thumb target reaches ~44-45px. */
.topbar .iconbtn,.mtopbar .miconbtn,.modal-close{ position:relative; }
.topbar .iconbtn::after,.mtopbar .miconbtn::after{ content:""; position:absolute; inset:-4px; }
.modal-close::after{ content:""; position:absolute; inset:-2px -6px; }

/* ================================================================
   Forms
   ================================================================ */
.form-grid{ display:grid; grid-template-columns:repeat(auto-fit,minmax(220px,1fr)); gap:13px; }
.field{ margin-bottom:13px; }
.field label{ display:block; font-weight:600; font-size:12.5px; color:#33424f; margin-bottom:6px; }
.field label .req{ color:var(--bad); }
.field .hint{ font-size:11.5px; color:var(--muted); margin-top:5px; }
.input,select,textarea,
input:not([type]),input[type=text],input[type=password],input[type=date],
input[type=number],input[type=tel],input[type=email],input[type=search],input[type=file]{
  font-family:inherit; font-size:14px; color:var(--ink); background:var(--surface);
  border:1px solid var(--line-2); border-radius:var(--r-sm);
  padding:10px 12px; width:100%;
  transition:border-color var(--m-short) var(--e-std),
             box-shadow var(--m-short) var(--e-std);
}
select{ appearance:none;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%2362707f' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
  background-repeat:no-repeat; background-position:right 11px center; padding-right:34px; }
textarea{ min-height:92px; resize:vertical; }
.input:focus,select:focus,textarea:focus,input:focus{ outline:none; border-color:var(--brand-2); box-shadow:var(--brand-ring); }
input[type=file]{ padding:8px 11px; background:var(--surface-2); cursor:pointer; }
.input,select,input:not([type]),input[type=text],input[type=password],input[type=date],
input[type=number],input[type=tel],input[type=email],input[type=search]{ height:44px; }
fieldset{ border:1px solid var(--line); border-radius:var(--r-md); padding:12px 14px; margin-bottom:14px; }
legend{ font-weight:700; color:var(--ink); padding:0 6px; font-size:13px; }

/* Live student-lookup result (complaint pages, filled by complaint.js ~300ms
   after typing). Reserve one text line so the answer appearing/clearing can
   never push the form fields below it up or down (layout-shift fix). */
#stuInfo{ display:block; min-height:21px; }

.inline-form{ display:flex; flex-wrap:wrap; gap:10px; align-items:flex-end; }
.inline-form .field{ margin:0; }
.inline-form input,.inline-form select{ width:100%; }
.inline-form .btn{ height:44px; }
.inline-form input[type=file]{ height:44px; }

/* ================================================================
   Tables
   ================================================================ */
/* content-visibility was tried here and deliberately REMOVED: the 480px
   intrinsic-size guess vs. a real 500-row table (~22,000px) made the
   scrollbar and surrounding content visibly jump as below-fold tables
   rendered in — the exact "UI shifts/trembles while settling" complaint.
   Typing stays fast via the cached/debounced filter in app.js; plain
   scrolling of the rendered table is compositor-bound and smooth. */
.table-wrap{ overflow-x:auto; -webkit-overflow-scrolling:touch; }
table.tbl{ width:100%; border-collapse:collapse; font-size:13px; }
.tbl thead th{
  text-align:left; background:var(--surface-2); color:var(--muted);
  font-weight:700; font-size:10.5px; text-transform:uppercase; letter-spacing:.06em;
  padding:11px 14px; border-bottom:1px solid var(--line); white-space:nowrap;
}
.tbl tbody td{ padding:12px 14px; border-bottom:1px solid var(--line); vertical-align:middle; }
.tbl tbody tr:last-child td{ border-bottom:0; }
@media (hover:hover){ .tbl tbody tr:hover{ background:var(--brand-soft); } }
.tbl tfoot td{ padding:11px 14px; border-top:1px solid var(--line); background:var(--surface-2); font-weight:700; }
.tbl .mono{ font-family:ui-monospace,"SFMono-Regular",Menlo,Consolas,monospace; font-weight:700; color:var(--brand); }
.cell-strong{ font-weight:700; }
.cell-muted{ color:var(--muted); font-size:12px; }

/* ================================================================
   Badges
   ================================================================ */
.badge{
  display:inline-flex; align-items:center; gap:5px;
  font-size:11.5px; font-weight:700; padding:3.5px 10px; border-radius:999px;
  border:1px solid transparent; line-height:1.35; white-space:nowrap;
}
.badge-success{ background:var(--ok-bg); color:var(--ok); border-color:var(--ok-bd); }
.badge-warning{ background:var(--warn-bg); color:var(--warn); border-color:var(--warn-bd); }
.badge-error,.badge-danger{ background:var(--bad-bg); color:var(--bad); border-color:var(--bad-bd); }
.badge-secondary{ background:#eef2f5; color:#5a6675; border-color:#dde4ea; }
.badge-info{ background:var(--inf-bg); color:var(--inf); border-color:var(--inf-bd); }
.badge-primary{ background:var(--brand-soft); color:var(--brand); border-color:#c8e8e4; }

/* ================================================================
   Alerts
   ================================================================ */
.alert{
  display:flex; align-items:flex-start; gap:9px;
  font-size:13px; padding:12px 14px; margin-bottom:14px;
  border:1px solid transparent; border-radius:var(--r-md); font-weight:500;
  animation:screenIn var(--m-med) var(--e-decel);
}
.alert i{ display:none; }
.alert::before{ content:""; flex:0 0 6px; align-self:stretch; border-radius:3px; }
.alert-success{ background:var(--ok-bg); color:#14532d; border-color:var(--ok-bd); }
.alert-success::before{ background:var(--ok); }
.alert-error{ background:var(--bad-bg); color:#7f1d1d; border-color:var(--bad-bd); }
.alert-error::before{ background:var(--bad); }
.alert-info{ background:var(--inf-bg); color:#155e75; border-color:var(--inf-bd); }
.alert-info::before{ background:var(--inf); }
.alert-warning{ background:var(--warn-bg); color:#7c2d12; border-color:var(--warn-bd); }
.alert-warning::before{ background:var(--warn); }

/* ================================================================
   Toolbar / filters
   ================================================================ */
.toolbar{
  display:flex; flex-wrap:wrap; gap:11px; align-items:flex-end; margin-bottom:14px;
  background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r-md); box-shadow:var(--sh-1); padding:13px 15px;
}
.toolbar .field{ margin:0; min-width:165px; flex:1 1 auto; }
.toolbar .btn{ height:44px; }
.toolbar input,.toolbar select{ width:100%; }
.toolbar input[name="search"]{ min-width:200px; }
.search{ position:relative; }
.search i{ display:none; }
.search input{ width:auto; min-width:200px; }

/* ================================================================
   Misc
   ================================================================ */
.empty{ text-align:center; padding:34px 16px; color:var(--muted); }
.empty i{ display:none; }
.empty h4{ font-size:14px; color:#42505e; margin-bottom:4px; }
.muted{ color:var(--muted); }
.grid-2{ display:grid; grid-template-columns:repeat(auto-fit,minmax(320px,1fr)); gap:14px; }
.flex{ display:flex; } .items-center{ align-items:center; } .gap{ gap:8px; } .between{ justify-content:space-between; }
.mt{ margin-top:14px; } .mb{ margin-bottom:14px; }
.drop{ border:1.5px dashed var(--line-2); border-radius:var(--r-md); background:var(--surface-2); padding:12px; display:flex; gap:10px; align-items:center; }
.drop .dico{ display:none; }
.drop input[type=file]{ width:auto; }
.req{ color:var(--bad); }
.hint{ font-size:11.5px; color:var(--muted); }

/* ================================================================
   Modal — centered on web, bottom sheet on phones
   ================================================================ */
.modal-overlay,.sheet-overlay{
  display:none; position:fixed; inset:0; z-index:120;
  background:rgba(11,30,28,.55);
  padding:20px; overflow-y:auto;
}
.modal-overlay.open,.sheet-overlay.open{ display:flex; align-items:flex-start; justify-content:center; }
.modal{
  width:560px; max-width:100%; margin:40px auto;
  background:var(--surface); border-radius:var(--r-xl); box-shadow:var(--sh-3);
  overflow:hidden; animation:modalIn var(--m-med) var(--e-decel);
}
@keyframes modalIn{ from{ transform:translateY(14px); opacity:0; } to{ transform:none; opacity:1; } }
.modal-head{
  display:flex; align-items:center; justify-content:space-between; gap:10px;
  padding:15px 18px; border-bottom:1px solid var(--line); font-weight:700;
}
.modal-head h3{ font-size:15px; font-weight:700; }
.modal-body{ padding:18px; }
.modal-foot{ padding:14px 18px; border-top:1px solid var(--line); background:var(--surface-2); display:flex; justify-content:flex-end; gap:10px; }
.modal-close{ background:none; border:0; color:var(--muted); font-size:24px; line-height:1; cursor:pointer; padding:0 6px; min-height:40px; }

@media (max-width:560px){
  .modal-overlay.open,.sheet-overlay.open{ align-items:flex-end; padding:0; }
  .modal{
    width:100%; margin:0; border-radius:18px 18px 0 0;
    animation:sheetIn var(--m-long) var(--e-decel);
    padding-bottom:env(safe-area-inset-bottom,0px);
  }
  @keyframes sheetIn{ from{ transform:translateY(38%); opacity:.6; } to{ transform:none; opacity:1; } }
}

/* ================================================================
   Toasts
   ================================================================ */
.toast-wrap{ position:fixed; top:14px; right:14px; left:14px; z-index:200; display:flex; flex-direction:column; gap:8px; align-items:flex-end; }
.toast{ background:#15242f; color:#fff; padding:11px 16px; font-size:13px; border-radius:11px; box-shadow:var(--sh-3); max-width:100%;
  animation:screenIn var(--m-med) var(--e-decel); }
.toast.ok{ background:#15803d; } .toast.err{ background:#b91c1c; }

/* ================================================================
   Responsive
   ================================================================ */
@media (max-width:1024px){
  .sidebar{ transform:translateX(-100%); box-shadow:var(--sh-3); }
  body.nav-open .sidebar{ transform:translateX(0); }
  .main{ margin-left:0; }
  .hamburger{ display:inline-flex; }
  body.nav-open .scrim{ display:block; position:fixed; inset:0; z-index:55; background:rgba(11,30,28,.45); }
}

@media (max-width:560px){
  .content{ padding:14px 13px; }
  .topbar{ padding:0 14px; gap:10px; }
  .topbar .userchip .who{ display:none; }
  .form-grid{ grid-template-columns:1fr; }
  .grid-2{ grid-template-columns:1fr; }
  .stats-grid{ grid-template-columns:repeat(2,1fr); gap:10px; }
  .stat{ padding:14px 14px 11px; }
  .stat .val{ font-size:23px; }
  .toolbar{ padding:12px 13px; }
  .toolbar .field{ min-width:calc(50% - 6px); }
  .toolbar input[name="search"]{ min-width:0; }
  .toast-wrap{ align-items:stretch; }
  .card-head{ padding:12px 14px; }
  .card-body{ padding:14px; }
  .tbl thead th{ padding:10px 12px; }
  .tbl tbody td{ padding:11px 12px; }
}

/* ================================================================
   Print
   ================================================================ */
@media print{
  body{ background:#fff; }
  .sidebar,.topbar,.mtopbar,.bottomnav,.scrim,.toolbar,.btn,.page-actions{ display:none !important; }
  .main,.app.mobile .content{ margin:0; }
  .content{ max-width:none; padding:0; animation:none; }
  .card,.stat{ box-shadow:none; border-color:#bbb; }
}
