:root{
  --bg:#0b1220; --card:#151f2e; --raised:#1d2a3b; --ink:#f4f7fb; --muted:#b8c3d1;
  --green:#22c55e; --green-ink:#052e16; --amber:#f59e0b; --yellow:#f5dd0a; --red:#fb7185; --blue:#60a5fa; --violet:#a78bfa; --pink:#f472b6; --border:#2b3b50;
  /* One shared "settle" easing for every release/pop motion in the app (tile release, confirm
     pop-ins) so they all read as the same spring rather than several unrelated tunings. */
  --spring:cubic-bezier(.34,1.56,.64,1);
}
*{box-sizing:border-box; margin:0; padding:0; -webkit-tap-highlight-color:transparent;}
body{min-height:100vh; font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif; background:radial-gradient(circle at 50% -20%,#223958 0,var(--bg) 43%); color:var(--ink);}
header{padding:18px 20px; display:flex; align-items:center; justify-content:space-between; max-width:980px; margin:0 auto; gap:12px;}
header h1{font-family:'Bebas Neue',sans-serif; font-size:24px; letter-spacing:.02em; color:var(--ink); font-weight:normal;}
#clock{font-size:14px; color:var(--muted); font-variant-numeric:tabular-nums;}
nav{display:none;}
main{padding:12px 20px 80px; max-width:980px; margin:0 auto;}
.card{background:var(--card); border:1px solid var(--border); border-radius:18px; padding:18px; margin-bottom:16px; box-shadow:0 14px 35px rgba(0,0,0,.17);}
.btn:focus-visible{outline:3px solid var(--blue); outline-offset:3px;}
body.kiosk-active main{display:none;}
body.kiosk-active{overflow:hidden;}
#tab-home{position:fixed; inset:0; z-index:40; display:flex; background:var(--bg);}
.kiosk-side{width:clamp(240px,30vw,360px); flex:0 0 auto; background:linear-gradient(160deg,#101c30,#0a1424); border-right:1px solid var(--border); display:flex; flex-direction:column; justify-content:space-between; padding:28px 26px;}
/* Three top-level children — .kiosk-top (identity + clock), the Payments/Attendance mode
   button, and .kiosk-footer (admin link) — so `justify-content:space-between` on .kiosk-side
   distributes two even gaps, pushing the mode button to the middle of the panel rather than
   crowding it next to "Admin access" at the bottom. Internal spacing within .kiosk-top is a
   real, fixed gap, not auto-margin centering — deliberate composition instead of one element
   floating in whatever space is left over. */
.kiosk-top{display:flex; flex-direction:column; gap:40px;}
.kiosk-identity{display:flex; flex-direction:column; gap:9px;}
.kiosk-mode-btn{display:flex; align-items:center; justify-content:center; gap:10px; width:100%;}
.kiosk-mode-btn svg{flex:0 0 auto;}
.kiosk-footer{display:flex; flex-direction:column; gap:6px;}
.kiosk-brand{font-family:'Bebas Neue',sans-serif; font-size:28px; letter-spacing:.02em; line-height:1; color:var(--ink);}
.kiosk-roster{display:flex; align-items:center; gap:7px; font-size:13px; font-weight:650; color:var(--muted);}
.kiosk-roster .dot{width:7px; height:7px; border-radius:50%; background:var(--green); box-shadow:0 0 8px var(--green); flex:0 0 auto;}
.kiosk-greet{font-family:ui-monospace,monospace; color:var(--blue); font-size:12px; letter-spacing:.14em; text-transform:uppercase; margin-bottom:10px;}
.kiosk-time{font-family:'Bebas Neue',sans-serif; color:var(--ink); font-size:clamp(48px,7vw,72px); letter-spacing:.03em; line-height:1; font-variant-numeric:tabular-nums;}
.kiosk-date{color:var(--ink); font-weight:650; font-size:16px; margin-top:8px;}
.kiosk-admin-link{align-self:flex-start; color:var(--muted); font-size:13px; text-decoration:underline; background:none; border:0; padding:8px 0; cursor:pointer;}
.sync-status{display:none; font-size:12px; font-weight:700; margin-bottom:4px;}
.sync-status.pending{display:block; color:var(--amber);}
.sync-status.stuck{display:block; color:var(--red);}
/* Purely informational — which deploy is actually running on this tablet (see js/version.js /
   js/ui/appVersion.js). Deliberately quiet: smaller and dimmer than .muted, never interactive. */
.app-version{font-size:10px; opacity:.55; margin-top:2px;}
/* flex-direction:column so the new .payments-banner can stack above .kiosk-badges instead of
   squeezing beside it in a row — align-items/justify-content:center still centers a single
   child both ways when the banner is hidden (Attendance mode), so this doesn't change today's
   one-child layout. */
.kiosk-main{flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:28px; padding:32px; overflow:auto;}
.kiosk-badges{display:grid; grid-template-columns:repeat(auto-fit,minmax(188px,224px)); justify-content:center; gap:clamp(16px,2.2vw,26px); width:100%; max-width:980px;}
/* --lift is each tile's own resting transform (plain tiles: none; in/lunch/missed: a small
   raise) — kept as a variable, not a literal `transform` on .in/.lunch/.missed, specifically so
   :active can compose var(--lift) + the press scale into ONE transform instead of two rules of
   equal specificity fighting over the same property. Before this, .badge-tile.in (etc.), being
   declared later in the file, silently won that tie every time — any already-clocked-in/lunch/
   missed tile showed no press feedback at all, only ever-plain tiles (like the Payments grid's,
   which never gets these state classes) did. */
.badge-tile{position:relative; background:var(--card); border:1.5px solid var(--border); border-radius:16px; padding:24px 16px 20px; text-align:center; cursor:pointer; box-shadow:0 10px 24px rgba(0,0,0,.28); --lift:translateY(0); transform:var(--lift); transition:transform .22s var(--spring),background .14s,border-color .14s,box-shadow .14s;}
/* Press-down uses its own fast, non-springy transition (scoped to :active, so it only wins
   while pressed) so the tap itself feels instant; releasing falls through to the base rule's
   --spring easing above for a slight settle-bounce back to rest. Same transform property, two
   different feels depending on direction — cheaper than a JS-driven animation. */
.badge-tile:active{transform:var(--lift) scale(.96); background:var(--raised); transition:transform .08s ease-out,background .08s ease-out;}
.badge-tile:focus-visible{outline:3px solid var(--blue); outline-offset:3px;}
.badge-tile .avatar{display:block; width:clamp(64px,7vw,88px); height:clamp(64px,7vw,88px); margin:0 auto 14px; border:2.5px solid #293b53; border-radius:14px; object-fit:cover; background:#293b53;}
.badge-tile .name{font-weight:700; font-size:17px; margin-bottom:7px;}
.badge-tile .status{font-size:13px; color:var(--muted); font-weight:600; line-height:1.35;}
.badge-tile.in{border-color:var(--green); background:linear-gradient(160deg,#123524,var(--card)); box-shadow:0 10px 26px rgba(34,197,94,.32); --lift:translateY(-3px);}
.badge-tile.in .avatar{border-color:var(--green);}
.badge-tile.in .status{color:#a7f3c0;}
.badge-tile .state-badge{position:absolute; top:-10px; right:-10px; width:28px; height:28px; border-radius:50%; display:grid; place-items:center; font-size:12px; font-weight:800; background:var(--raised); color:var(--muted); border:2px solid var(--bg);}
.badge-tile.in .state-badge{background:var(--green); color:var(--green-ink);}
.badge-tile.lunch{border-color:var(--amber); background:linear-gradient(160deg,#3a2a0f,var(--card)); box-shadow:0 10px 26px rgba(245,158,11,.28); --lift:translateY(-3px);}
.badge-tile.lunch .avatar{border-color:var(--amber);}
.badge-tile.lunch .status{color:#fcd34d;}
.badge-tile.lunch .state-badge{background:var(--amber); color:#3a2a0f;}
.badge-tile.missed{border-color:var(--red); background:linear-gradient(160deg,#3a1420,var(--card)); box-shadow:0 10px 26px rgba(251,113,133,.28); --lift:translateY(-3px);}
.badge-tile.missed .avatar{border-color:var(--red);}
.badge-tile.missed .status{color:#fca5a5;}
.badge-tile.missed .state-badge{background:var(--red); color:#500716;}
@media (max-width:760px), (orientation:portrait){
  #tab-home{flex-direction:column;}
  .kiosk-side{width:auto; flex-direction:row; align-items:center; justify-content:space-between; padding:16px 18px; border-right:0; border-bottom:1px solid var(--border); position:relative;}
  /* .kiosk-top/.kiosk-footer exist only to control spacing on the tall desktop panel — on the
     compact mobile bar there's no "top vs bottom of a tall column" to manage, so unwrap them
     back to plain flex children of .kiosk-side, exactly like before .kiosk-top/.kiosk-footer
     existed. .kiosk-admin-link keeps working via its own absolute position below regardless
     of which element is its DOM parent. */
  .kiosk-top, .kiosk-footer{display:contents;}
  .kiosk-identity{gap:3px;}
  .kiosk-brand{font-size:19px;}
  .kiosk-roster{font-size:12px;}
  .kiosk-hero{text-align:right;}
  .kiosk-time{font-size:28px;}
  .kiosk-date{font-size:13px; margin-top:3px;}
  .kiosk-admin-link{position:absolute; bottom:-6px; left:18px; padding:4px 0;}
  .app-version{position:absolute; bottom:-6px; right:18px; margin-top:0;}
}
/* Same fade-in idiom as .modal-overlay (opacity/visibility/pointer-events, not a display:none/
   flex hard cut) — this is the single most-repeated screen in the app (every punch, every
   employee), so it shouldn't be the one overlay that pops in with zero transition while every
   other overlay in the app fades. */
#punchConfirm{position:fixed; inset:0; background:rgba(4,9,17,.97); display:flex; flex-direction:column; align-items:center; justify-content:center; z-index:140; padding:20px; text-align:center; cursor:pointer; opacity:0; visibility:hidden; pointer-events:none; transition:opacity .2s ease;}
#punchConfirm.open{opacity:1; visibility:visible; pointer-events:auto;}
#pcPhoto{width:150px; height:150px; border-radius:50%; object-fit:cover; border:4px solid var(--green); margin-bottom:18px;}
#punchConfirm.out #pcPhoto{border-color:var(--blue);}
/* Staggered pop-in (photo, then the check a beat later) is tied to the .open selector itself —
   removing .open removes the animation outright, so re-adding it on the next punch always
   starts fresh with no JS replay logic needed. */
#punchConfirm.open #pcPhoto{animation:popIn .3s var(--spring) both;}
#pcCheck{width:56px; height:56px; border-radius:50%; background:var(--green); color:var(--green-ink); display:grid; place-items:center; margin-bottom:14px;}
#punchConfirm.open #pcCheck{animation:popIn .3s .1s var(--spring) both;}
#punchConfirm.out #pcCheck{background:var(--blue); color:#07111d;}
#pcCheck svg{display:block;}
/* pathLength="1" on the <path> (index.html) lets this draw-on animate as a plain 0→1 dash
   offset regardless of the path's real geometry — no hand-measured stroke length to keep in
   sync if the checkmark shape ever changes. */
#pcCheck svg path{stroke-dasharray:1; stroke-dashoffset:1;}
#punchConfirm.open #pcCheck svg path{animation:checkDraw .35s .3s cubic-bezier(.65,0,.35,1) forwards;}
#pcAction{font-size:28px; font-weight:800; margin-bottom:4px;}
#pcName{font-size:20px; color:var(--muted); margin-bottom:10px;}
#pcDetail{font-size:15px; color:var(--muted);}
/* Payment save confirmation — same full-screen overlay language as #punchConfirm, minus the
   photo (there's no camera step in this flow). Kept as its own element rather than overloading
   #punchConfirm's photo-specific markup/classes. */
#paymentConfirm{position:fixed; inset:0; background:rgba(4,9,17,.97); display:flex; flex-direction:column; align-items:center; justify-content:center; z-index:140; padding:20px; text-align:center; cursor:pointer; opacity:0; visibility:hidden; pointer-events:none; transition:opacity .2s ease;}
#paymentConfirm.open{opacity:1; visibility:visible; pointer-events:auto;}
#pymCheck{width:56px; height:56px; border-radius:50%; background:var(--green); color:var(--green-ink); display:grid; place-items:center; margin-bottom:14px;}
#paymentConfirm.open #pymCheck{animation:popIn .3s var(--spring) both;}
#pymCheck svg{display:block;}
#pymCheck svg path{stroke-dasharray:1; stroke-dashoffset:1;}
#paymentConfirm.open #pymCheck svg path{animation:checkDraw .35s .2s cubic-bezier(.65,0,.35,1) forwards;}
#pymAction{font-size:28px; font-weight:800; margin-bottom:4px;}
#pymName{font-size:20px; color:var(--muted); margin-bottom:10px;}
#pymDetail{font-size:15px; color:var(--muted);}
/* Same instant-down/spring-up language as .badge-tile and the two keypads above — filter:
   brightness() rather than a per-variant background swap, so one rule darkens .btn's press
   state correctly across blue/green/red/ghost without listing each color separately. */
.btn{display:inline-flex; align-items:center; justify-content:center; min-height:52px; border:none; border-radius:13px; padding:13px 20px; font-size:16px; font-weight:750; cursor:pointer; color:#07111d; background:var(--blue);}
/* Shared with the other simple (non-tile) tappable controls below — .month-arrow, the admin
   tab pills, and the payments resolve-toggle all get the exact same instant-down/spring-up
   scale + brightness dim from this one pair of rules, so the whole app tunes together instead
   of drifting across several near-identical copies. (.badge-tile and the two number keypads
   keep their own versions — a --lift composition and a literal background swap respectively —
   since neither fits this simpler scale+filter shape.) */
.btn, .month-arrow, .admin-panel button, .resolve-toggle{transition:transform .18s var(--spring),filter .1s;}
.btn:active, .month-arrow:active, .admin-panel button:active, .resolve-toggle:active{transform:scale(.93); filter:brightness(.88); transition:transform .07s ease-out,filter .07s ease-out;}
.btn.green{background:var(--green); color:var(--green-ink);} .btn.red{background:var(--red); color:#500716;}
.btn.ghost{background:transparent; color:var(--ink); border:1px solid var(--border);}
.btn.small{min-height:38px; padding:8px 12px; font-size:13px; border-radius:10px;}
.btn:disabled{opacity:.5;}
.modal-overlay{position:fixed; inset:0; background:rgba(4,9,17,.96); display:flex; flex-direction:column; align-items:center; justify-content:center; z-index:100; padding:20px; opacity:0; visibility:hidden; pointer-events:none; transition:opacity .18s ease;}
.modal-overlay.open{opacity:1; visibility:visible; pointer-events:auto;}
#camModal h2{color:#fff; margin-bottom:8px; font-size:24px; text-align:center;}
.camera-help{color:var(--muted); margin-bottom:18px; text-align:center; font-size:15px;}
.video-wrap{position:relative; width:100%; max-width:440px;}
#video{display:block; width:100%; border:2px solid var(--border); border-radius:20px; background:#000; transform:scaleX(-1);}
/* Shutter flash — the universal "a photo was just taken" cue, missing before this: a brief
   white flash over the live feed, timed to the tap itself rather than the async blob encode
   that follows it. */
#camFlash{position:absolute; inset:0; background:#fff; border-radius:20px; opacity:0; pointer-events:none;}
#camFlash.flash{animation:shutterFlash .28s ease-out;}
#camBtns{width:100%; max-width:440px; margin-top:18px; display:flex; gap:12px;}
#camBtns .btn{flex:1;}
.modal-err{color:#ffb3b3; margin-top:10px; text-align:center; font-size:14px; max-width:340px;}
.auth-card{background:var(--card); border:1px solid var(--border); border-radius:20px; padding:24px; width:100%; max-width:390px; transform:scale(.96); transition:transform .18s ease;}
.modal-overlay.open .auth-card{transform:scale(1);}
.auth-card h2{font-size:20px; letter-spacing:-.02em; margin-bottom:14px;}
.auth-card input{margin-bottom:10px;}
.auth-card .modal-err{color:var(--red);}
.modal-field-label{display:block; color:var(--muted); font-size:13px; font-weight:650; margin:0 0 6px;}
.modal-field-label ~ .modal-field-label{margin-top:14px;}
/* infoModal()'s content for "which exact dates" (js/ui/report.js's showAbsenceDetail) — scrolls
   internally past a couple of screenfuls of dates rather than growing the modal past the
   viewport on a month with a lot of absences. */
.absence-modal-body{max-height:52vh; overflow-y:auto; padding-right:4px;}
.absence-section + .absence-section{margin-top:16px;}
.absence-heading{font-size:13px; font-weight:700; margin-bottom:8px;}
.absence-heading.full{color:var(--red);}
.absence-heading.half{color:var(--yellow);}
.absence-empty{color:var(--muted); font-size:13px;}
.absence-list{list-style:none; display:flex; flex-direction:column; gap:6px;}
.absence-list li{background:var(--raised); border-radius:9px; padding:8px 12px; font-size:14px; font-weight:650;}
input:focus-visible{outline:2px solid var(--blue); outline-offset:1px; border-color:var(--blue);}
.photo-thumb{width:44px; height:44px; object-fit:cover; border-radius:8px; cursor:pointer; background:#ddd;}
input[type=text], input[type=email], input[type=password], input[type=month], input[type=date], input[type=time], input[type=number], select{min-height:48px; padding:10px 12px; border:1px solid var(--border); border-radius:10px; background:#0e1725; color:var(--ink); font-size:16px; width:100%;}
input[type=time]::-webkit-calendar-picker-indicator, input[type=date]::-webkit-calendar-picker-indicator, input[type=month]::-webkit-calendar-picker-indicator{filter:invert(1) brightness(1.6);}
.row{display:flex; gap:10px; align-items:center; flex-wrap:wrap;}
.row > *{flex:0 0 auto;}
.grow{flex:1 1 auto !important;}
.muted{color:var(--muted); font-size:13px;}
.open-session{color:var(--green); font-weight:600;}
.lunch-flag{color:#fbbf24; font-weight:600;}
#photoView{position:fixed; inset:0; background:rgba(0,0,0,.9); display:none; align-items:center; justify-content:center; z-index:110; cursor:pointer;}
#photoView.open{display:flex;}
#photoView img{max-width:92%; max-height:92%; border-radius:12px;}
/* Monthly report — detailed calendar. A day is a status pill, not a number (a day can now
   have more than one session, and a single cell can't spell that out) — Employee/Days/Total
   hrs stay pinned via position:sticky while the day columns scroll underneath them. */
.grid-scroll{overflow-x:auto;}
#reportTable{border-collapse:separate; border-spacing:0; font-size:13px; width:max-content;}
#reportTable th, #reportTable td{padding:0; height:52px; border-bottom:1px solid var(--border); text-align:left;}
#reportTable thead th{padding:10px 8px; color:var(--muted); font-size:10.5px; font-weight:700; text-transform:uppercase; letter-spacing:.03em; background:var(--card);}
#reportTable .col-emp{position:sticky; left:0; z-index:2; background:var(--card); padding:0 14px; min-width:150px; border-right:1px solid var(--border);}
#reportTable .col-days, #reportTable .col-absent, #reportTable .col-total{position:sticky; z-index:2; background:var(--card); text-align:center;}
#reportTable .col-days{right:168px; min-width:70px; border-left:1px solid var(--border);}
/* Absent = full absences + 0.5 per half day (see renderDetailCalendar()) — red like .daypill.off,
   so a glance at this column and a glance at the calendar's red pills agree on what "absent"
   means here. */
#reportTable .col-absent{right:92px; min-width:76px; color:var(--red);}
#reportTable .col-absent.clickable{cursor:pointer;}
#reportTable .col-absent.clickable:hover{text-decoration:underline;}
#reportTable .col-total{right:0; min-width:92px;}
#reportTable td.col-days, #reportTable td.col-absent, #reportTable td.col-total{font-weight:700; font-size:14px;}
#reportTable td.col-days span, #reportTable td.col-absent span, #reportTable td.col-total span{display:block; font-size:10px; font-weight:650; color:var(--muted); text-transform:uppercase; margin-bottom:2px;}
/* flex-start, not center: this row can now carry a days-off/review-status line under the name
   (folded in from the old standalone Employee summary card), so the avatar aligns with the name
   at the top rather than the vertical midpoint of a now-taller, multi-line block. */
.emp-name{display:flex; align-items:flex-start; gap:9px; font-weight:700;}
.emp-avatar-img{width:26px; height:26px; border-radius:8px; object-fit:cover; background:var(--raised); flex:0 0 auto;}
#reportTable td.day-cell{padding:9px 3px; text-align:center; width:46px;}
.daypill{
  width:36px; height:32px; margin:0 auto; border-radius:9px; border:1.5px solid var(--border);
  display:flex; align-items:center; justify-content:center; font-size:11px; font-weight:700;
  color:var(--muted); position:relative; transition:transform .1s; font-variant-numeric:tabular-nums;
}
/* Showing hours worked (e.g. "3:55") instead of the bare day-of-month the pill used to carry —
   the column header above already has the day number, so repeating it in every pill was
   redundant once there was something more useful to show there (the owner's ask, 2026-09-12:
   see the day's hours without clicking in). Smaller/tighter than the single-character day-number
   size it replaces, since up to 5 characters ("10:30") need to fit the same pill width. */
.daypill.has-hours{font-size:9px; letter-spacing:-.02em;}
.daypill.full{background:rgba(34,197,94,.16); border-color:var(--green); color:#a7f3c0; cursor:pointer;}
.daypill.review{background:rgba(245,158,11,.20); border-color:var(--amber); color:#fde3a7; cursor:pointer;}
/* A single-session day with notably fewer hours than a full day (see isHalfDay() in
   reportMath.js) — yellow per the shop owner's explicit ask (2026-09-12, live review), so it
   reads at a glance as "partial attendance" distinct from both a full day (green) and an
   absence (red, see .off below). --yellow sits at hue 54° specifically, ~16° from --amber's 38°
   (the "needs review" color) and visibly more lemon/green than amber's orange — an initial
   #eab308 pick (only 8° from amber) blended into it exactly the way --teal-vs-green and
   --violet-vs-blue already taught this file to watch for once each. */
.daypill.half{background:rgba(245,221,10,.20); border-color:var(--yellow); color:#fef9a7; cursor:pointer;}
.daypill.full:hover, .daypill.half:hover, .daypill.review:hover, .daypill.holiday:hover{transform:translateY(-2px);}
.daypill.auto::after{content:""; position:absolute; top:-3px; right:-3px; width:7px; height:7px; border-radius:50%; background:var(--blue); border:1.5px solid var(--card);}
.daypill.full.flagged, .daypill.half.flagged{border-color:var(--amber);}
.daypill.full.flagged::after, .daypill.half.flagged::after{content:""; position:absolute; top:-3px; right:-3px; width:7px; height:7px; border-radius:50%; background:var(--amber); border:1.5px solid var(--card);}
/* A single full-day session with no recorded lunch gap (see isPossibleMissedLunch() in
   reportMath.js) — a quiet corner-dot nudge, same visual weight as .auto (informational) rather
   than .flagged (amber, "needs review"): this isn't a data problem, punch data genuinely can't
   tell a missed lunch punch apart from a real no-break shift, so it's "worth a glance" only.
   --pink, not --violet (tried first, reverted 2026-09-12): violet sits only ~40° from --blue on
   the color wheel, hard to tell apart from .auto's dot at 7px — the exact same "too close to an
   already-used color at a glance" issue .half's fill already hit once with teal-vs-green. Pink
   sits far from --blue, --amber, and (now that .half is yellow, not pink) --yellow too, so it
   stays a safe, unambiguous choice here even though .half's own fill moved off pink. */
.daypill.full.unbroken::after{content:""; position:absolute; top:-3px; right:-3px; width:7px; height:7px; border-radius:50%; background:var(--pink); border:1.5px solid var(--card);}
/* Friday's standing paid holiday — filled and lettered like .full/.review, since it's a
   frequent, expected state worth reading at a glance rather than a quiet footnote. Clickable
   (cursor + hover-lift, see .daypill.holiday:hover above) now that it opens the docked-holiday
   toggle in the day-detail panel — .off below stays non-interactive, so it doesn't get either. */
.daypill.holiday{background:rgba(167,139,250,.20); border-color:var(--violet); color:#ddd6fe; cursor:pointer;}
/* An inferred day off / absence (no explicit record backs this — see dayOffStatus() in
   reportMath.js) — red per the shop owner's explicit ask (2026-09-12, live review), superseding
   an earlier deliberately-muted treatment (this pill used to read as a quiet dashed neutral, with
   the calendar row's own "● N days off" line under the employee's name carrying the emphasis
   instead). Still dashed rather than a solid fill, so it stays visually distinct from a real
   worked full/half day at a glance, not just by color. */
/* Clickable (2026-09-12): an absence is sometimes actually a missed punch, so this pill opens
   the same "add a missed punch" flow as any other admin correction — cursor + the same hover
   lift every other actionable pill gets (see the .full/.half/.review/.holiday hover rule above). */
.daypill.off{background:rgba(251,113,133,.14); border-style:dashed; border-color:var(--red); color:#fecdd3; cursor:pointer;}
.daypill.off:hover{transform:translateY(-2px);}
/* A paid holiday the owner has explicitly excluded from an employee's pay this month (js/ui/
   report.js's day-detail panel on the 'F' pill) — --red, already this app's "something's being
   taken away" colour (the missed-clock-in tile, delete buttons), reused here as a dot since this
   is the one daypill state that's a deliberate pay deduction rather than an informational nudge
   (.auto/.unbroken) or a needs-review flag (.flagged, amber). */
.daypill.holiday.docked::after{content:""; position:absolute; top:-3px; right:-3px; width:7px; height:7px; border-radius:50%; background:var(--red); border:1.5px solid var(--card);}
.detail-row{display:none;}
.detail-row.open{display:table-row;}
.detail-row td{background:var(--raised); padding:0;}
/* Capped well under `main`'s own 980px max-width (not just 90vw) — this row lives inside a
   wide, horizontally-scrolling table, so its own visible box is narrower than the viewport;
   wrapping here (rather than at 90vw) keeps every chip on-screen instead of getting clipped
   past the table's scrollport edge. The "paid" annotation chips are what made this bite in
   practice — long enough that a 2-session day used to render wider than that visible box.
   A column of rows, not one long flex-wrap line: each session (and the lunch/break gap before
   it) is its own `.detail-row-line` — grouping per row means a narrow viewport only ever wraps a
   whole row at once, instead of any chip mid-session, which used to produce two misaligned lines
   with no visual relationship to which chips belonged to which session. */
.detail-inner{position:sticky; left:0; display:flex; flex-direction:column; align-items:flex-start; gap:9px; padding:14px 18px; width:max-content; max-width:min(90vw, 820px);}
.detail-row-line{display:flex; align-items:center; gap:10px; flex-wrap:wrap;}
/* Edit/Delete/Split as one non-wrapping unit — a narrow row wraps this whole cluster onto its
   own line rather than splitting a single button off it (which used to strand a lone Delete). */
.detail-actions{display:flex; align-items:center; gap:8px; flex-wrap:nowrap; flex:0 0 auto;}
.detail-date{font-weight:750; font-size:13px; color:var(--ink); white-space:nowrap;}
.chip{background:var(--card); border:1px solid var(--border); border-radius:9px; padding:6px 11px; font-size:12.5px; display:inline-flex; align-items:center; gap:7px; white-space:nowrap;}
.chip .lbl{color:var(--muted); font-size:10.5px; text-transform:uppercase; letter-spacing:.03em;}
.chip.lunch{color:#93c5fd; border-color:#2c4870;}
.chip.review{color:#fde3a7; border-color:#7a5914;}
/* The one row that isn't a session — a divider (border-top) sets it apart as a summary/exit
   row rather than another correction to make, and `justify-content:space-between` pins the jump
   button to the far edge so it can't end up trailing wherever the last chip happens to end. */
.detail-footer{display:flex; align-items:center; justify-content:space-between; gap:16px; width:100%; margin-top:2px; padding-top:11px; border-top:1px solid var(--border);}
.detail-total{font-size:13px; color:var(--muted); white-space:nowrap;}
/* A real label + accent color (the same blue used for lunch chips elsewhere), not the icon-only
   ghost square this used to be — that read as a quiet, easy-to-miss affordance right when it
   needed to be the one clearly-findable way out of this panel to the punch photos. */
.btn.small.detail-jump{background:rgba(96,165,250,.12); color:#93c5fd; border:1px solid #2c4870; white-space:nowrap;}
.btn.small.detail-jump:hover{background:rgba(96,165,250,.22);}
.detail-total b{color:var(--ink); font-size:15px;}

/* Key for the calendar's status pills — sits below the scrollable table itself, not above
   it, since it explains something the reader has already seen. */
.calendar-legend{display:flex; flex-wrap:wrap; gap:10px 22px; padding:16px 4px 4px; margin-top:14px; border-top:1px solid var(--border);}
.legend-item{display:flex; align-items:center; gap:9px; font-size:12.5px; color:var(--muted);}
.legend-item .daypill{width:20px; height:20px; margin:0; font-size:9px; flex:0 0 auto;}
.legend-item .daypill, .legend-item .daypill:hover{cursor:default; transform:none;}
.toast{position:fixed; bottom:28px; left:50%; transform:translateX(-50%) translateY(10px); background:var(--green); color:var(--green-ink); padding:16px 24px; border-radius:14px; font-size:16px; font-weight:750; z-index:120; opacity:0; transition:opacity .25s,transform .25s var(--spring); pointer-events:none; max-width:90%; text-align:center; box-shadow:0 12px 30px rgba(0,0,0,.35);}
.toast.show{opacity:1; transform:translateX(-50%) translateY(0);}
h3{font-size:16px; margin-bottom:10px;}
#busy{position:fixed; top:0; left:0; right:0; height:3px; background:var(--blue); display:none; z-index:130; animation:busy 1s linear infinite;}
@keyframes busy{0%{transform:scaleX(.1); transform-origin:left}50%{transform:scaleX(1)}100%{transform:scaleX(.1); transform-origin:right}}
@keyframes popIn{from{opacity:0; transform:scale(.55);} to{opacity:1; transform:scale(1);}}
@keyframes checkDraw{to{stroke-dashoffset:0;}}
@keyframes shutterFlash{0%{opacity:.85;} 100%{opacity:0;}}
@keyframes shake{
  10%,90%{transform:translateX(-1px);}
  20%,80%{transform:translateX(2px);}
  30%,50%,70%{transform:translateX(-4px);}
  40%,60%{transform:translateX(4px);}
}
/* Respect the OS-level motion preference: keep every state still readable (checkmarks land
   fully drawn, tiles/confirms just appear) but drop the bounce/pop/draw/flash/shake motion. */
@media (prefers-reduced-motion: reduce){
  .badge-tile, .badge-tile:active, .pin-keypad button, .pay-keypad button, .pin-keypad button:active, .pay-keypad button:active{transition:background .01ms,border-color .01ms,box-shadow .01ms;}
  .btn, .btn:active, .month-arrow, .month-arrow:active, .admin-panel button, .admin-panel button:active, .resolve-toggle, .resolve-toggle:active{transition:background .01ms,filter .01ms;}
  .toast{transition:opacity .25s;}
  #punchConfirm.open #pcPhoto, #punchConfirm.open #pcCheck, #paymentConfirm.open #pymCheck,
  #pcCheck svg path, #pymCheck svg path{animation:none;}
  #pcCheck svg path, #pymCheck svg path{stroke-dashoffset:0;}
  #camFlash.flash, .pin-dots.shake{animation:none;}
}
.admin-panel{display:flex; gap:8px; padding:8px; margin-bottom:16px; overflow:auto; background:var(--raised); border-radius:14px;}
.admin-panel button{white-space:nowrap; min-height:40px; padding:8px 12px; border:1px solid transparent; border-radius:9px; background:transparent; color:var(--muted); cursor:pointer; font-weight:700;}
.admin-panel button.active{background:var(--card); color:var(--ink); border-color:var(--border);}
.report-top{display:flex; align-items:flex-start; justify-content:space-between; gap:14px; margin-bottom:16px;}
.report-top h2{font-size:25px; letter-spacing:-.03em; margin:4px 0 5px;}
.report-period{display:flex; align-items:center; justify-content:center; gap:9px; padding:8px; margin-bottom:16px; background:var(--raised); border-radius:14px;}
.month-arrow{display:grid; place-items:center; width:42px; height:42px; border:1px solid var(--border); border-radius:10px; background:var(--card); color:var(--ink); font-size:25px; cursor:pointer;}
.report-period input[type=month]{width:200px; min-height:42px; padding:7px 9px; text-align:center; background:transparent; border:0; font-weight:750;}
.report-summary{display:grid; grid-template-columns:repeat(5,1fr); gap:12px; margin-bottom:16px;}
.metric{padding:16px; border:1px solid var(--border); border-radius:15px; background:var(--card);}
.metric-label{display:block; color:var(--muted); font-size:13px; font-weight:650;}
.metric-value{display:block; margin-top:7px; font-size:25px; letter-spacing:-.04em; font-weight:780; font-variant-numeric:tabular-nums;}
.metric-value.good{color:#86efac}.metric-value.warn{color:#fbbf24}
.metric-value.bad{color:var(--red)}.metric-value.half{color:var(--yellow)}
.review-alert{display:flex; justify-content:space-between; align-items:center; gap:14px; margin-bottom:16px; padding:14px 16px; background:#3a2c13; border:1px solid #7a5914; border-radius:15px;}
.review-alert strong{display:block; font-size:15px}.review-alert span{display:block; color:#f8d992; margin-top:3px; font-size:13px;}
.review-alert.danger{background:#3a1414; border:1px solid #7a2020;}
.review-alert.danger span{color:#fca5a5;}
.report-list{padding:0; overflow:hidden;}
.report-list-head{display:flex; align-items:baseline; justify-content:space-between; padding:17px; border-bottom:1px solid var(--border);}
.report-list-head h3{margin:0; font-size:16px}.report-list-head span{font-size:13px; color:var(--muted);}
.report-avatar{width:43px; height:43px; border:2px solid #33465f; border-radius:50%; object-fit:cover;}
.report-name{font-size:16px; font-weight:750}.report-detail{display:block; margin-top:3px; color:var(--muted); font-size:13px;}.report-state{font-size:14px; font-weight:750;}.report-state.ok{color:#86efac}.report-state.open{color:#fbbf24}
.report-daysoff{margin-top:3px; font-size:13px; font-weight:700; color:var(--muted);}
#reportDetail{margin-top:16px;}
/* Row + its (possibly open) calc-detail are one .salary-item unit — the border-bottom belongs
   here, not on .salary-person, so it always separates this employee from the next one whether
   or not their calculation panel happens to be open (see js/ui/salary.js's item wrapper). */
.salary-item{border-bottom:1px solid var(--border);}
.salary-item:last-child{border-bottom:0;}
.salary-person{display:grid; grid-template-columns:46px minmax(110px,1.2fr) 1fr auto; align-items:center; gap:12px; padding:14px 17px;}
.salary-who{min-width:0;}
.salary-amount{text-align:right; font-variant-numeric:tabular-nums;}
.salary-amount span{display:block; color:var(--muted); font-size:12px; margin-bottom:2px;}
.salary-amount strong{font-size:18px;}
.salary-actions{display:flex; gap:8px;}
/* Its own raised panel with a top border, not text floating with a negative margin right under
   the row above — reads as a distinct "receipt" attached to this employee, not loose paragraphs
   bleeding toward whoever's next in the list. */
.salary-calc-detail{background:var(--raised); padding:14px 17px; border-top:1px solid var(--border); font-size:13px; color:var(--muted);}
.salary-calc-detail p{margin:0;}
/* A real bordered table, not paragraphs — visible gridlines (not just column alignment) so a
   ledger this consequential reads unambiguously as one row per fact, easy to scan cell-by-cell
   or paste into a spreadsheet, rather than sentences that merely line up. */
.calc-table{width:100%; border-collapse:collapse; border:1px solid var(--border); border-radius:10px; overflow:hidden;}
.calc-table th, .calc-table td{border-bottom:1px solid var(--border); padding:8px 14px;}
.calc-table tr:last-child th, .calc-table tr:last-child td{border-bottom:0;}
.calc-table th{text-align:left; font-weight:700; color:var(--ink); white-space:nowrap; vertical-align:top; width:1%; background:rgba(255,255,255,.03); border-right:1px solid var(--border);}
.calc-table td{color:var(--muted); font-variant-numeric:tabular-nums;}
/* The final row is the number everything above it built up to — a filled background and
   ink-bright text (not just another muted line) so it reads as the answer, not one more fact. */
.calc-table tr.calc-total th, .calc-table tr.calc-total td{background:rgba(96,165,250,.1); color:var(--ink); font-weight:700;}
/* Employees tab — grid-list row, matching the Report/Salary pattern above */
.emp-row{display:grid; grid-template-columns:46px 1fr auto; align-items:center; gap:12px; padding:14px 17px; border-bottom:1px solid var(--border);}
.emp-row:last-child{border-bottom:0;}
.emp-status{display:flex; align-items:center; gap:6px; margin-top:3px; font-size:13px; font-weight:650; color:var(--muted);}
.emp-status .dot{width:6px; height:6px; border-radius:50%; background:var(--muted); flex:0 0 auto;}
.emp-status.active{color:#a7f3c0;}
.emp-status.active .dot{background:var(--green);}
.emp-actions{display:flex; gap:8px; flex-wrap:wrap; justify-content:flex-end;}

/* Daily records tab — grid-list row.
   Each `.rec-row` is its own independent grid (not a shared table), so column widths are
   fixed pixel values rather than `auto`/1fr-content-based — otherwise a row with a longer
   "paid" annotation sizes its own punches/hours columns wider than a plain row, and the
   columns drift out of alignment down the list. Only `who` (names vary in length anyway,
   never needs to align to a grid) is left flexible. The actions column is capped
   (`minmax(90px,180px)`, not `auto`) with `.rec-actions` set to wrap — a 3rd action ("Split
   for lunch") no longer just grows the row past the card and gets clipped by
   `.report-list`'s `overflow:hidden`; it wraps onto a second line instead. */
.rec-row{display:grid; grid-template-columns:44px minmax(110px,1fr) 300px 120px minmax(90px,180px); align-items:center; gap:14px; padding:13px 17px;}
.rec-row, .rec-group{border-bottom:1px solid var(--border);}
#recList > *:last-child{border-bottom:0;}
/* A lunch-break day's two (or more) sessions share one header — avatar, name, status, and the
   day's combined total — instead of reading as two same-weight rows with a gap in between and
   the total left as mental arithmetic. Sub-rows nest underneath, indented to align under the
   header's name rather than its avatar, still showing each session's own exact times (the
   audit trail) and its own worked/paid figure. */
.rec-group-header{display:grid; grid-template-columns:44px minmax(110px,1fr) auto; align-items:center; gap:14px; padding:13px 17px 10px;}
.rec-hours.day-total .rec-hours-stat{font-size:16px;}
.rec-hours.day-total .rec-hours-stat.paid{font-size:13px;}
.rec-group-sessions{padding:0 17px 8px 75px;}
.rec-session-row{display:grid; grid-template-columns:300px 120px 1fr auto; align-items:center; gap:14px; padding:8px 0;}
.rec-session-row .rec-actions{grid-column:4;}
.rec-punches{display:flex; gap:18px;}
.rec-punch{text-align:center;}
.rec-punch .lbl{display:block; font-size:11px; color:var(--muted); text-transform:uppercase; letter-spacing:.04em; margin-bottom:3px;}
.rec-punch .val{font-size:13.5px; font-weight:650; font-variant-numeric:tabular-nums; display:flex; align-items:center; justify-content:center; gap:6px;}
.rec-punch .photo-thumb{width:26px; height:26px; border-radius:6px; cursor:pointer;}
.paid-note{color:var(--muted); font-size:11.5px; font-style:italic;}
.rec-punch .paid-note{display:block; margin-top:2px; font-style:normal;}
.rec-hours{display:flex; flex-direction:column; align-items:flex-end; gap:2px; font-variant-numeric:tabular-nums;}
.rec-hours-stat{font-weight:700; font-size:14.5px; white-space:nowrap;}
.rec-hours-stat .lbl{color:var(--muted); font-size:10.5px; font-weight:650; text-transform:uppercase; letter-spacing:.03em; margin-right:5px;}
.rec-hours-stat.paid{font-size:12.5px; font-weight:650; color:var(--muted);}
.rec-actions{display:flex; gap:6px; flex-wrap:wrap; justify-content:flex-end; align-content:center;}
.rec-lunch-divider{display:flex; align-items:center; justify-content:space-between; gap:12px; padding:6px 17px; font-size:12px; font-weight:650; color:var(--muted); background:var(--raised); border-bottom:1px dashed var(--border);}
/* Reuses --blue (the one brand accent, already used for lunch chips elsewhere) rather than
   --green/--amber, which the design system reserves for the kiosk tile's clocked-in and
   syncing states specifically — this isn't either of those. */
.rec-lunch-divider.paid{color:#93c5fd; background:rgba(96,165,250,.1); border-bottom-color:#2c4870;}
.lunch-paid-toggle{min-height:26px; padding:4px 10px; font-size:11.5px; white-space:nowrap;}
.rec-lunch-divider.paid .lunch-paid-toggle{border-color:#2c4870; color:#93c5fd;}

/* ============ Payments ============ */
.payments-banner{display:flex; align-items:center; justify-content:center; gap:10px; padding:13px 20px; background:rgba(96,165,250,.12); border:1px solid #2c4870; border-radius:14px; color:#93c5fd; font-weight:650; font-size:14px; flex:0 0 auto;}

/* PIN pad + add-payment amount pad — one shared keypad look, big touch targets. */
#paymentFlowModal{overflow-y:auto; padding:36px 0;}
.pin-card, .pay-card{background:var(--card); border:1px solid var(--border); border-radius:20px; padding:28px; width:100%; max-width:400px; margin:0 20px; text-align:center; flex:0 0 auto;}
.pin-avatar, .pay-avatar{border-radius:12px; object-fit:cover; background:#293b53;}
.pin-avatar{width:60px; height:60px; margin:0 auto 14px;}
.pin-title{font-size:18px; font-weight:750; margin-bottom:4px;}
.pin-sub{color:var(--muted); font-size:13px; margin-bottom:22px;}
.pin-dots{display:flex; justify-content:center; gap:14px; margin-bottom:14px;}
/* Wrong-PIN shake — the globally recognized "incorrect" cue (iOS lock screen, etc.). Scoped to
   the dots row, not the whole card, so it reads as "that entry was wrong" without relocating
   the keypad the employee's thumb is about to tap again. */
.pin-dots.shake{animation:shake .4s ease;}
.pin-dot{width:16px; height:16px; border-radius:50%; border:2px solid var(--border); background:transparent;}
.pin-dot.filled{background:var(--ink); border-color:var(--ink);}
.pin-dot.error{background:var(--red); border-color:var(--red);}
.pin-error-text{color:var(--red); font-size:13px; font-weight:650; margin-bottom:14px; min-height:18px;}
.pin-locked-msg{background:rgba(251,113,133,.12); border:1px solid #7a2020; color:#fca5a5; border-radius:12px; padding:14px; font-size:13.5px; font-weight:650; margin-bottom:18px; text-align:left;}
.pin-keypad, .pay-keypad{display:grid; grid-template-columns:repeat(3,1fr); gap:10px; margin-bottom:18px;}
.pin-keypad button, .pay-keypad button{min-height:56px; border-radius:13px; background:var(--raised); border:1px solid var(--border); color:var(--ink); font-size:21px; font-weight:700; transition:transform .16s var(--spring),background .1s;}
/* Same press/release split as .badge-tile — instant down, a quick settle on release — but
   shorter (.06s vs .08s, no stagger) since digits get tapped in rapid succession and shouldn't
   feel like they're queuing behind their own animation. */
.pin-keypad button:active, .pay-keypad button:active{transform:scale(.88); background:var(--card); transition:transform .06s ease-out,background .06s ease-out;}
.pin-keypad button:disabled, .pay-keypad button:disabled{background:transparent; border:0;}
.pin-keypad.disabled{opacity:.35; pointer-events:none;}
.pin-cancel{color:var(--muted); font-size:14px; text-decoration:underline; background:none; border:0; padding:4px 0;}

.back-btn{display:inline-flex; align-items:center; gap:6px; color:var(--muted); font-size:13.5px; font-weight:650; background:none; border:0; padding:0 0 18px; cursor:pointer;}
.pay-header{display:flex; align-items:center; gap:12px; margin-bottom:8px; text-align:left;}
.pay-header .pay-avatar{width:48px; height:48px; flex:0 0 auto;}
.pay-header .pay-name{font-weight:750; font-size:17px;}
.pay-header .pay-sub{color:var(--muted); font-size:12.5px; margin-top:1px;}
.month-total{text-align:center; padding:18px; background:var(--raised); border-radius:16px; margin:18px 0 20px;}
.month-total-label{font-size:12px; font-weight:700; color:var(--muted); text-transform:uppercase; letter-spacing:.04em; margin-bottom:6px;}
.month-total-value{font-family:'Bebas Neue',sans-serif; font-size:36px; letter-spacing:.02em; font-variant-numeric:tabular-nums;}
.entries-title{font-size:12px; font-weight:700; color:var(--muted); text-transform:uppercase; letter-spacing:.04em; margin:24px 0 10px; text-align:left;}
.recent-row{display:flex; align-items:flex-start; justify-content:space-between; gap:10px; padding:11px 0; border-bottom:1px solid var(--border); text-align:left;}
.recent-row:last-child{border-bottom:0; padding-bottom:0;}
.recent-date{font-weight:700; font-size:14px;}
.recent-meta{color:var(--muted); font-size:12px; margin-top:2px;}
.pay-amount-display{text-align:center; font-family:'Bebas Neue',sans-serif; font-size:42px; letter-spacing:.02em; margin:20px 0 14px; font-variant-numeric:tabular-nums;}
.pay-amount-display span{color:var(--muted); font-size:26px; margin-right:4px;}

.status-chip{display:inline-flex; align-items:center; gap:6px; padding:5px 10px; border-radius:9px; font-size:11px; font-weight:700; white-space:nowrap; margin-top:2px;}
.status-chip.matched{background:rgba(34,197,94,.16); border:1px solid var(--green); color:#a7f3c0;}
.status-chip.awaiting{background:rgba(245,158,11,.18); border:1px solid var(--amber); color:#fde3a7;}
.status-chip.mismatch{background:rgba(251,113,133,.14); border:1px solid var(--red); color:#fecdd3;}
.status-chip.resolved{background:var(--raised); border:1px solid var(--border); color:var(--muted);}

/* Admin Payments tab — grouped by employee; expanding a row reveals that employee's own
   date-wise breakdown (.pay-emp-detail), each date independently expandable into the existing
   side-by-side owner/employee comparison (.detail-panel). */
.pay-summary{display:grid; grid-template-columns:repeat(4,1fr); gap:12px; margin-bottom:16px;}
.pay-group{border-bottom:1px solid var(--border);}
.pay-group:last-child{border-bottom:0;}
.pay-row{display:grid; grid-template-columns:40px minmax(160px,1fr) auto 20px; align-items:center; gap:14px; padding:12px 17px; cursor:pointer;}
.pay-row:hover{background:var(--raised);}
.pay-row .pay-avatar{width:40px; height:40px; border-radius:10px;}
.pay-row .pay-name{font-weight:700; font-size:15px;}
.pay-row .pay-sub{color:var(--muted); font-size:12.5px; margin-top:2px;}
.pay-amount{font-variant-numeric:tabular-nums; font-weight:700; font-size:14px; text-align:right; white-space:nowrap;}
.pay-chevron{color:var(--muted); font-size:16px; text-align:right; transition:transform .12s;}
.pay-chevron.down{transform:rotate(90deg);}
.pay-emp-detail{padding:2px 17px 8px 71px; background:var(--raised);}
.pay-date-row{display:grid; grid-template-columns:1fr auto 20px; align-items:center; gap:14px; padding:12px 0; border-top:1px solid var(--border); cursor:pointer;}
.pay-date-row:first-child{border-top:0;}
.pay-date-row .pay-name{font-weight:700; font-size:14px;}
.pay-date-row .pay-sub{color:var(--muted); font-size:12.5px; margin-top:2px;}

.detail-panel{background:var(--raised); padding:18px 17px 20px; border-top:1px dashed var(--border);}
.detail-cards{display:grid; grid-template-columns:1fr 1fr; gap:14px; margin-bottom:16px;}
.detail-card{background:var(--card); border:1px solid var(--border); border-radius:14px; padding:16px; text-align:left;}
.detail-card-label{font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.03em; color:var(--muted); margin-bottom:9px;}
.detail-card-amount{font-family:'Bebas Neue',sans-serif; font-size:28px; margin-bottom:4px;}
.detail-card-meta{color:var(--muted); font-size:12.5px; margin-bottom:2px;}
.detail-card-actions{display:flex; gap:8px; margin-top:12px;}
.resolve-row{display:flex; align-items:center; justify-content:space-between; gap:14px; padding:14px 16px; background:rgba(96,165,250,.08); border:1px solid #2c4870; border-radius:12px;}
.resolve-row-text strong{display:block; font-size:13.5px;}
.resolve-row-text span{display:block; color:#93c5fd; font-size:12px; margin-top:2px;}
.resolve-toggle{min-height:38px; padding:7px 16px; border-radius:20px; border:1px solid var(--border); background:var(--card); color:var(--muted); font-weight:700; font-size:12.5px; flex:0 0 auto; cursor:pointer;}

@media (max-width:520px){header{padding:15px 16px} main{padding:8px 16px 70px} #clock{font-size:12px}.card{padding:14px}}
@media (max-width:620px){.report-summary{grid-template-columns:1fr}.pay-summary{grid-template-columns:1fr}.report-top{align-items:stretch; flex-direction:column}.report-top .btn{width:100%}.review-alert{align-items:flex-start; flex-direction:column}.review-alert .btn{width:100%}.salary-person{grid-template-columns:43px 1fr; row-gap:8px}.salary-amount,.salary-actions{grid-column:2}.salary-amount{text-align:left}.detail-cards{grid-template-columns:1fr}.pay-emp-detail{padding-left:17px}}
@media (max-width:620px){
  .emp-row{grid-template-columns:40px 1fr; row-gap:10px;}
  .emp-actions{grid-column:1 / -1; justify-content:flex-start;}
  .rec-row{grid-template-columns:40px 1fr auto; grid-template-areas:"avatar who hours" "punches punches actions"; row-gap:10px;}
  .rec-row .rec-avatar{grid-area:avatar;}
  .rec-row .rec-who{grid-area:who;}
  .rec-row .rec-hours{grid-area:hours;}
  .rec-row .rec-punches{grid-area:punches; justify-content:flex-start;}
  .rec-row .rec-actions{grid-area:actions;}
  .rec-group-header{grid-template-columns:40px 1fr auto;}
  .rec-group-sessions{padding-left:0;}
  .rec-session-row{grid-template-columns:1fr auto; grid-template-areas:"punches punches" "hours actions"; row-gap:8px; padding:10px 0;}
  .rec-session-row .rec-punches{grid-area:punches; justify-content:flex-start;}
  .rec-session-row .rec-hours{grid-area:hours; align-items:flex-start;}
  .rec-session-row .rec-actions{grid-area:actions; grid-column:auto;}
}
