@import url("./tokens.css");
*{margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:transparent;}
html,body{height:100%;overflow:hidden;background:var(--black);color:var(--white);font-family:var(--font-body);}

/* ─── APP SHELL ─── */
#app{height:100%;display:flex;flex-direction:column;overflow:hidden;}

/* ─── SCREENS ─── */
.screen{display:none;flex:1;flex-direction:column;overflow:hidden;}
.screen.active{display:flex;}

/* ─── LOGIN SCREEN ─── */
#screen-login{
  justify-content:center;align-items:center;
  background:radial-gradient(ellipse at 60% 40%, rgba(244,98,42,0.12) 0%, transparent 65%), var(--black);
  padding:32px 24px;
}
.login-logo{
  font-family:var(--font-display);font-size:52px;letter-spacing:4px;
  text-align:center;margin-bottom:8px;
}
.login-logo span{color:var(--orange);}
.login-tagline{font-size:13px;color:var(--muted);text-align:center;letter-spacing:2px;text-transform:uppercase;margin-bottom:48px;}
.login-card{
  background:var(--steel);border:1px solid var(--border);border-radius:12px;
  padding:32px 28px;width:100%;max-width:360px;
}
.login-tabs{display:flex;gap:4px;margin-bottom:28px;background:var(--iron);border-radius:8px;padding:4px;}
.login-tab{
  flex:1;padding:10px;border:none;background:transparent;
  color:var(--muted);font-family:var(--font-body);font-size:13px;font-weight:600;
  border-radius:6px;cursor:pointer;transition:all 0.2s;letter-spacing:0.5px;
}
.login-tab.active{background:var(--orange);color:var(--black);}
.form-group{margin-bottom:18px;}
/* [v1-12] RPT-3 report-type selector — same tap-row shape as .login-tabs/.login-tab (big touch
   targets, forms philosophy §1.1), reused here rather than introducing a second pattern. */
#report-type-selector{display:flex;gap:4px;background:var(--iron);border-radius:8px;padding:4px;margin-bottom:18px;}
.report-type-btn{
  flex:1;padding:10px;border:none;background:transparent;
  color:var(--muted);font-family:var(--font-body);font-size:13px;font-weight:600;
  border-radius:6px;cursor:pointer;transition:all 0.2s;letter-spacing:0.5px;
}
.report-type-btn.active{background:var(--orange);color:var(--black);}
/* [DISC-142] The app's ONE mic button. Tony's report: "there's no on/off indicator" and "it
   toggles itself" — a status line alone was not readable at a glance in jobsite sunlight, so the
   BUTTON carries the state: off = the existing outlined secondary treatment, listening = solid
   --orange with a pulsing ring, at full width and a 56px touch target for a gloved hand.
   Locked palette: --orange / --orange-glow / --black / --border / --muted only, no new colors. */
.mic-btn{
  display:block;width:100%;padding:16px 18px;min-height:56px;margin-bottom:4px;
  background:transparent;border:1px solid var(--border);border-radius:8px;
  color:var(--muted);font-family:var(--font-display);font-size:18px;letter-spacing:2px;
  cursor:pointer;transition:background-color 0.15s,color 0.15s,border-color 0.15s;
}
.mic-btn:focus-visible{outline:2px solid var(--orange);outline-offset:2px;}
.mic-btn--listening{
  background:var(--orange);border-color:var(--orange);color:var(--black);
  animation:mic-pulse 1.4s ease-in-out infinite;
}
@keyframes mic-pulse{
  0%,100%{box-shadow:0 0 0 0 var(--orange-glow);}
  50%{box-shadow:0 0 0 10px rgba(244,98,42,0);}
}
/* [DISC-187] The THINKING state, between "stop talking" and "here is your draft". Tony's steer was
   to keep the active treatment going through this phase rather than drop back to an idle-looking
   button, so this is the listening button's exact shape at a slower, calmer pulse and with its own
   words (TIDYING UP...). Same three tokens, no new colors, no spinner glyph — a pulse reads at arm's
   length in sunlight where a 16px spinner does not. Deliberately NOT a live transcript stream: raw
   text is what is being cleaned up, so streaming it is showing the user the mess. */
.mic-btn--working{
  background:var(--orange);border-color:var(--orange);color:var(--black);
  animation:mic-pulse 2.4s ease-in-out infinite;cursor:progress;
}
.mic-btn--working:disabled{opacity:1;} /* disabled here means "busy", not "unavailable" */
/* Respect a user who has asked the OS for less motion — the color change alone still reads. */
@media (prefers-reduced-motion: reduce){
  .mic-btn--listening,.mic-btn--working{animation:none;box-shadow:0 0 0 3px var(--orange-glow);}
}
/* [v0-29] EXT-UI-03: .form-label is the identically-styled non-<label> caption for groups of
   buttons/controls where no single labelable element exists (e.g. the 2FA method chooser). */
.form-group label,.form-group .form-label{display:block;font-size:11px;font-weight:600;letter-spacing:1.5px;text-transform:uppercase;color:var(--muted);margin-bottom:8px;}
.form-group input, .form-group select{
  width:100%;padding:12px 14px;background:var(--iron);border:1px solid var(--border);
  border-radius:8px;color:var(--white);font-family:var(--font-body);font-size:14px;
  outline:none;transition:border-color 0.2s;
}
.form-group input:focus, .form-group select:focus{border-color:var(--orange);}
.form-group select option{background:var(--iron);}
.pin-input-wrap{position:relative;display:flex;align-items:center;}
.pin-input-wrap input{padding-right:46px;}
.pin-eye-toggle{
  position:absolute;right:8px;top:50%;transform:translateY(-50%);
  width:32px;height:32px;display:inline-flex;align-items:center;justify-content:center;
  background:transparent;border:1px solid transparent;border-radius:6px;color:var(--muted);
  font-size:14px;cursor:pointer;transition:border-color 0.15s,color 0.15s,background 0.15s;
}
.pin-eye-toggle:hover{border-color:var(--orange);color:var(--orange);background:rgba(244,98,42,0.08);}
.btn-login{
  width:100%;padding:14px;background:var(--orange);border:none;border-radius:8px;
  color:var(--black);font-family:var(--font-display);font-size:20px;letter-spacing:2px;
  cursor:pointer;transition:background 0.2s;margin-top:4px;
}
.btn-login:hover{background:var(--yellow);}
.btn-biometric{
  width:100%;padding:13px;background:transparent;border:1px solid var(--border);border-radius:8px;
  color:var(--muted);font-family:var(--font-body);font-size:14px;font-weight:600;
  cursor:pointer;transition:border-color 0.2s,color 0.2s;margin-top:8px;letter-spacing:0.5px;
  display:flex;align-items:center;justify-content:center;gap:8px;
}
.btn-biometric:hover{border-color:var(--orange);color:var(--white);}
.btn-biometric:disabled{opacity:0.3;cursor:not-allowed;}
/* [DISC-108] "Not you? Switch user" — a full-size, prominent CTA (not a muted text link) so a
   worker borrowing a supervisor's phone has an obvious way in. Sized like .btn-login but
   outlined rather than solid-filled, so it never competes visually with the primary submit
   action on the same screen. */
.btn-switch-user{
  width:100%;padding:14px;background:transparent;border:2px solid var(--orange);border-radius:8px;
  color:var(--orange);font-family:var(--font-display);font-size:16px;letter-spacing:1.5px;
  cursor:pointer;transition:background 0.2s,color 0.2s;margin-top:8px;
}
.btn-switch-user:hover{background:var(--orange);color:var(--black);}
.login-hint{font-size:11px;color:var(--muted);text-align:center;margin-top:16px;line-height:1.6;}
.login-biometric-reason{font-size:12px;color:var(--muted);line-height:1.5;margin-top:10px;}

/* ─── TOP BAR ─── */
.topbar{
  display:flex;align-items:center;justify-content:space-between;
  padding:14px 20px;background:rgba(10,10,10,0.95);
  border-bottom:1px solid var(--border);flex-shrink:0;
  backdrop-filter:blur(12px);gap:12px;overflow-x:auto;-webkit-overflow-scrolling:touch;
}
.topbar-logo{font-family:var(--font-display);font-size:22px;letter-spacing:3px;}
.topbar-logo span{color:var(--orange);}
.topbar-right{display:flex;align-items:center;gap:12px;flex-shrink:0;}
.sync-badge{
  display:flex;align-items:center;gap:6px;
  font-size:11px;font-family:var(--font-mono);
  padding:5px 10px;border-radius:20px;border:1px solid var(--border);
  background:var(--iron);
}
.sync-dot{width:6px;height:6px;border-radius:50%;background:var(--muted);}
.sync-dot.online{background:var(--green);box-shadow:0 0 6px var(--green);}
.sync-dot.syncing{background:var(--yellow);animation:blink 0.8s infinite;}
@keyframes blink{0%,100%{opacity:1;}50%{opacity:0.3;}}
.btn-logout{
  min-height:32px;padding:6px 12px;background:transparent;border:1px solid var(--border);
  border-radius:6px;color:var(--muted);font-size:12px;font-weight:600;
  cursor:pointer;transition:all 0.2s;letter-spacing:0.5px;
}
.btn-logout:hover{border-color:var(--red);color:var(--red);}
@media (max-width: 400px){
  .topbar{padding:10px 12px;gap:8px;}
  .topbar-logo{font-size:18px;letter-spacing:2px;}
  .topbar-right{gap:8px;}
  .sync-badge{padding:5px 8px;}
  .btn-logout{padding:6px 9px;}
}

/* ─── EMPLOYEE SCREEN ─── */
#screen-employee{background:var(--black);}
.emp-scroll{flex:1;overflow-y:auto;padding:20px;}

.emp-header{margin-bottom:24px;}
.emp-greeting{font-size:13px;color:var(--muted);letter-spacing:1px;text-transform:uppercase;margin-bottom:4px;}
.emp-name{font-family:var(--font-display);font-size:36px;letter-spacing:2px;}

/* GEO STATUS */
.geo-status{
  border-radius:10px;padding:16px;margin-bottom:20px;
  display:flex;align-items:center;gap:14px;
  border:1px solid var(--border);background:var(--steel);
  transition:all 0.3s;
}
.geo-status.checking{border-color:var(--border);}
.geo-status.inside{border-color:rgba(46,204,113,0.4);background:rgba(46,204,113,0.06);}
.geo-status.outside{border-color:rgba(231,76,60,0.4);background:rgba(231,76,60,0.06);}
/* [DISC-26c] The primary label here is always the PUNCH status ('IN'/'ON BREAK'/'ON LUNCH'/'OUT',
   per clientCheck.js's refreshStatusBanner()) — that must read as the dominant element. .geo-icon
   only ever holds a short zone/GPS CODE WORD ('GPS'/'OFF'/'ERR'/'OUT'/'NEAR'/'OK'/'WARN'), which
   used to render at 28px — visually louder than the 11px punch-status label it sits beside, an
   inverted hierarchy. Rebalanced: .geo-icon shrinks to a small muted badge, .geo-label grows to
   the dominant size/weight. Same information present, no markup change. */
.geo-icon{
  font-size:11px;font-weight:700;letter-spacing:1px;text-transform:uppercase;
  color:var(--muted);flex-shrink:0;line-height:1;
  background:var(--steel);border:1px solid var(--border);border-radius:6px;padding:4px 8px;
}
.geo-info{flex:1;}
.geo-label{font-size:22px;font-weight:700;letter-spacing:0.5px;text-transform:uppercase;margin-bottom:3px;}
.geo-detail{font-size:13px;color:var(--muted);}
.geo-status.inside .geo-label{color:var(--green);}
.geo-status.outside .geo-label{color:var(--red);}

/* [v1-07] SC-TRV-06: "Get Directions" bonus-signal button — visually secondary (never implies
   this action is load-bearing for a punch/pay outcome). */
.btn-directions{
  width:100%;padding:12px;margin-bottom:20px;
  border:1px solid var(--border);background:transparent;border-radius:8px;
  color:var(--muted);font-family:var(--font-body);font-size:13px;font-weight:600;
  letter-spacing:0.5px;cursor:pointer;transition:all 0.2s;
}
.btn-directions:hover{border-color:var(--orange);color:var(--orange);}

/* CLOCK WIDGET */
.clock-widget{
  background:var(--steel);border:1px solid var(--border);
  border-radius:12px;padding:28px 24px;margin-bottom:20px;text-align:center;
}
.live-time{
  font-family:var(--font-mono);font-size:48px;font-weight:500;
  color:var(--white);letter-spacing:2px;margin-bottom:4px;
}
.live-date{font-size:13px;color:var(--muted);letter-spacing:1px;margin-bottom:24px;}
.shift-duration{
  display:inline-flex;align-items:center;gap:8px;
  background:var(--iron);border-radius:8px;padding:10px 20px;
  font-family:var(--font-mono);font-size:22px;color:var(--orange);
  margin-bottom:28px;border:1px solid var(--border);
}
.shift-label{font-size:10px;color:var(--muted);letter-spacing:1.5px;text-transform:uppercase;margin-bottom:8px;}

/* PUNCH BUTTON */
.punch-wrap{position:relative;}
.punch-btn-main{
  width:100%;padding:22px;border:none;border-radius:10px;
  font-family:var(--font-display);font-size:28px;letter-spacing:4px;
  cursor:pointer;transition:all 0.2s;position:relative;overflow:hidden;
}
.punch-btn-main.clock-in{background:var(--orange);color:var(--black);}
.punch-btn-main.clock-out{background:var(--red);color:var(--white);}
.punch-btn-main:disabled{opacity:0.4;cursor:not-allowed;}
.punch-btn-main:not(:disabled):hover{transform:translateY(-2px);box-shadow:0 8px 24px rgba(244,98,42,0.3);}
.punch-btn-main.clock-out:not(:disabled):hover{box-shadow:0 8px 24px rgba(231,76,60,0.3);}

/* BREAK BUTTONS */
.break-row{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:12px;}
.btn-break{
  padding:14px;border:1px solid var(--border);background:var(--steel);
  border-radius:8px;color:var(--white);font-family:var(--font-body);
  font-size:13px;font-weight:600;cursor:pointer;transition:all 0.2s;
}
.btn-break:hover{border-color:var(--yellow);color:var(--yellow);}
.btn-break:disabled{opacity:0.3;cursor:not-allowed;}

/* LUNCH BUTTONS — [v1-01] D-006/SC-CLK-04: lunch is a distinct punch action from a rest break,
   so it gets its own row + a distinct hover accent (orange, vs. break's yellow) even though it
   shares .btn-break's base sizing/shape (same control, different meaning — not a new shape). */
.lunch-row{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:8px;}
.btn-lunch:hover{border-color:var(--orange);color:var(--orange);}

/* UNDO NOTE — [DISC-134] What is LEFT of D2.1's pocket-dial undo in the UI.
   The .undo-row / .btn-undo / .undo-hint block that used to live here is deleted. It rendered a
   second control that meant the same thing as END BREAK / END LUNCH — two buttons for one
   intention, one of which appeared and vanished on a timer. On a gloved hand at a job site the
   worker taps the big one, so the big one is now the only one, and it grades itself.
   What survives is a line of TEXT inside the status banner. It is not interactive, it does not
   move layout when it appears (empty = no content, so the banner keeps its height), and nothing
   is lost if the worker never reads it. */
.geo-undo-note{font-size:11px;color:var(--muted);line-height:1.3;margin-top:2px;}

/* ZONE OVERRIDE MODAL */
#modal-zone-override{display:none;position:fixed;inset:0;background:rgba(0,0,0,0.92);z-index:1010;padding:16px;overflow-y:auto;}
.zone-override-card{background:var(--steel);border:2px solid #f59e0b;border-radius:12px;padding:24px;max-width:420px;margin:40px auto;}
.zone-override-title{font-family:var(--font-display);font-size:22px;letter-spacing:2px;color:#f59e0b;margin-bottom:6px;}
.zone-override-sub{font-size:13px;color:var(--muted);margin-bottom:20px;line-height:1.5;}
.zone-override-actions{display:flex;flex-direction:column;gap:10px;margin-bottom:0;}
.btn-zone-proceed{width:100%;padding:14px;border:2px solid #f59e0b;background:rgba(245,158,11,0.1);border-radius:8px;color:#f59e0b;font-family:var(--font-display);font-size:14px;letter-spacing:1px;cursor:pointer;transition:all 0.2s;}
.btn-zone-proceed:hover{background:rgba(245,158,11,0.2);}
.btn-zone-dismiss{width:100%;padding:13px;border:1px solid var(--border);background:transparent;border-radius:8px;color:var(--muted);font-family:var(--font-body);font-size:13px;cursor:pointer;transition:all 0.2s;}
.btn-zone-dismiss:hover{border-color:var(--white);color:var(--white);}
.zone-reason-form{display:none;margin-top:20px;border-top:1px solid var(--border);padding-top:20px;}
.zone-reason-label{font-size:12px;color:var(--muted);letter-spacing:1px;text-transform:uppercase;margin-bottom:10px;}
.zone-reason-options{display:flex;flex-direction:column;gap:8px;margin-bottom:14px;}
.zone-reason-option{display:flex;align-items:center;gap:10px;padding:10px 12px;border:1px solid var(--border);border-radius:8px;cursor:pointer;transition:border-color 0.15s;}
.zone-reason-option:has(input:checked){border-color:#f59e0b;background:rgba(245,158,11,0.06);}
.zone-reason-option input{accent-color:#f59e0b;width:16px;height:16px;flex-shrink:0;}
.zone-reason-option span{font-size:13px;color:var(--white);line-height:1.4;}
#zone-other-text{width:100%;padding:10px 12px;background:var(--iron);border:1px solid var(--border);border-radius:8px;color:var(--white);font-family:var(--font-body);font-size:13px;resize:vertical;min-height:72px;display:none;margin-bottom:12px;box-sizing:border-box;}
#zone-other-text:focus{outline:none;border-color:#f59e0b;}
.btn-zone-submit{width:100%;padding:14px;background:#f59e0b;border:none;border-radius:8px;color:#000;font-family:var(--font-display);font-size:14px;letter-spacing:1px;cursor:pointer;transition:opacity 0.2s;}
.btn-zone-submit:hover{opacity:0.88;}
.btn-zone-submit:disabled{opacity:0.4;cursor:not-allowed;}
.btn-zone-back{width:100%;padding:10px;background:transparent;border:1px solid var(--border);border-radius:8px;color:var(--muted);font-family:var(--font-body);font-size:13px;cursor:pointer;margin-top:8px;}

/* PUNCH LOG */
.punch-log-card{
  background:var(--steel);border:1px solid var(--border);
  border-radius:12px;overflow:hidden;margin-bottom:20px;
}
.card-header{
  padding:14px 18px;border-bottom:1px solid var(--border);
  display:flex;justify-content:space-between;align-items:center;
}
.card-title{font-family:var(--font-display);font-size:16px;letter-spacing:2px;color:var(--muted);}
.queue-count{
  font-size:10px;font-weight:700;letter-spacing:1px;text-transform:uppercase;
  background:rgba(244,98,42,0.15);color:var(--orange);
  padding:3px 8px;border-radius:4px;
}
.punch-row{
  display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;
  padding:12px 18px;border-bottom:1px solid rgba(42,51,71,0.5);
}
.punch-row:last-child{border-bottom:none;}
.punch-event{font-size:13px;font-weight:600;}
/* [v1-01] D-006/SC-CLK-04: lunch entries get a distinct accent color in the punch log — never
   visually identical to a rest break. */
.punch-event-lunch{color:var(--orange);}
.punch-ts{font-family:var(--font-mono);font-size:12px;color:var(--muted);}
.punch-saved{
  font-size:9px;font-weight:700;letter-spacing:1.5px;text-transform:uppercase;
  padding:3px 7px;border-radius:4px;
}
.saved-local{background:rgba(245,200,66,0.12);color:var(--yellow);}
.saved-synced{background:rgba(46,204,113,0.12);color:var(--green);}
/* [v1-09] AUTH-4/SC-CLK-08: an emergency/zone-override punch is never hard-blocked, but must be
   visibly flagged — same amber tone as the zone-override modal's own title (#f59e0b), on its
   own line so it never crowds the existing event/time/sync-status row. */
.punch-outside-zone{
  flex-basis:100%;margin-top:4px;font-size:11px;font-weight:600;letter-spacing:0.3px;
  color:#f59e0b;
}

/* ─── OFFLINE BANNER ─── */
.offline-banner{
  margin-bottom:16px;display:flex;align-items:center;gap:10px;
  background:rgba(245,200,66,0.08);border:1px solid rgba(245,200,66,0.2);
  border-radius:8px;padding:12px 14px;font-size:13px;color:var(--yellow);
}

/* ─── ADMIN SCREEN ─── */
#screen-admin{background:var(--black);}
.admin-tabs{
  display:flex;border-bottom:1px solid var(--border);flex-shrink:0;
  background:var(--steel);overflow-x:auto;
}
.admin-tab{
  padding:14px 22px;border:none;background:transparent;
  color:var(--muted);font-family:var(--font-body);font-size:12px;
  font-weight:600;letter-spacing:1px;text-transform:uppercase;
  cursor:pointer;border-bottom:2px solid transparent;white-space:nowrap;
  transition:all 0.2s;flex-shrink:0;
}
.admin-tab.active{color:var(--orange);border-bottom-color:var(--orange);}
.admin-content{flex:1;overflow-y:auto;}
.admin-panel{display:none;padding:24px 20px;}
.admin-panel.active{display:block;}

/* DASHBOARD PANEL */
.admin-punch-card{background:var(--steel);border:1px solid var(--border);border-radius:12px;padding:16px;margin-bottom:20px;}
.admin-punch-card .apc-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:14px;}
.admin-punch-card .apc-title{font-family:var(--font-display);font-size:13px;letter-spacing:2px;color:var(--muted);}
.admin-punch-card .apc-status{font-family:var(--font-display);font-size:13px;letter-spacing:1px;}
.admin-punch-card .apc-status.in{color:var(--green);}
.admin-punch-card .apc-status.out{color:var(--muted);}
.admin-punch-card .apc-status.break{color:var(--yellow);}
.admin-punch-card .apc-main-btn{width:100%;padding:13px;border:none;border-radius:8px;font-family:var(--font-display);font-size:14px;font-weight:700;letter-spacing:1px;cursor:pointer;transition:opacity 0.15s;}
.admin-punch-card .apc-main-btn.clock-in{background:var(--orange);color:var(--black);}
.admin-punch-card .apc-main-btn.clock-out{background:#d63a29;color:var(--white);} /* [v0-30] EXT-UI-07: 14px bold on #e74c3c was 3.82:1 (AA fail); #d63a29 -> 4.67:1 */
.admin-punch-card .apc-main-btn:disabled{opacity:0.35;cursor:not-allowed;}
.admin-punch-card .apc-break-row{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:8px;}
.admin-punch-card .apc-break-btn{padding:9px;background:transparent;border:1px solid var(--border);border-radius:6px;color:var(--muted);font-family:var(--font-body);font-size:12px;font-weight:600;cursor:pointer;letter-spacing:0.5px;}
.admin-punch-card .apc-break-btn:not(:disabled):hover{border-color:var(--yellow);color:var(--yellow);}
.admin-punch-card .apc-break-btn:disabled{opacity:0.3;cursor:not-allowed;}
/* [DISC-133] GAP 1 — lunch on the admin's own clock, carrying the same orange accent the
   employee widget's lunch row uses so the two surfaces read as one product. */
.admin-punch-card .apc-lunch-btn:not(:disabled):hover{border-color:var(--orange);color:var(--orange);}
.metrics-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:12px;margin-bottom:24px;}
.metric-card{
  background:var(--steel);border:1px solid var(--border);border-radius:10px;padding:20px 16px;
}
.metric-val{font-family:var(--font-display);font-size:42px;letter-spacing:1px;line-height:1;}
.metric-val.orange{color:var(--orange);}
.metric-val.green{color:var(--green);}
.metric-val.yellow{color:var(--yellow);}
.metric-val.red{color:var(--red);}
.metric-label{font-size:11px;color:var(--muted);letter-spacing:1px;text-transform:uppercase;margin-top:6px;}

.section-title{
  font-family:var(--font-display);font-size:20px;letter-spacing:2px;
  color:var(--muted);margin-bottom:14px;
}
.help-title{display:inline-flex;align-items:center;gap:6px;min-width:0;}
.info-tooltip{position:relative;display:inline-flex;align-items:center;vertical-align:middle;}
.info-tooltip-btn{
  width:18px;height:18px;border:1px solid var(--border);border-radius:50%;background:transparent;
  color:var(--muted);font-size:12px;font-weight:700;line-height:16px;text-align:center;cursor:pointer;
  font-family:var(--font-body);padding:0;
}
/* [DISC-90/TR-01] :hover alone "sticks" orange on touch devices — there is no mouseleave to
   clear it, so the icon reads as still-active after the tap that opened (then dismissed) the
   popover. Scope :hover to devices that actually have a pointer capable of hovering, and drive
   the real active/open indicator off aria-expanded (which infoTooltip.js already resets to
   "false" on close) so touch devices never get stuck. */
@media (hover:hover) and (pointer:fine){
  .info-tooltip-btn:hover{color:var(--orange);border-color:var(--orange);}
}
.info-tooltip-btn[aria-expanded="true"]{color:var(--orange);border-color:var(--orange);}
.info-tooltip-popover{
  position:absolute;z-index:50;top:24px;left:0;width:min(260px,80vw);padding:10px 12px;
  background:var(--iron);border:1px solid var(--border);border-radius:8px;color:var(--white);
  font-family:var(--font-body);font-size:12px;font-weight:400;letter-spacing:0;line-height:1.45;
  text-transform:none;box-shadow:0 12px 28px rgba(0,0,0,0.35);
}
.info-tooltip-popover[hidden]{display:none;}

/* EMPLOYEE TABLE */
.emp-table{
  background:var(--steel);border:1px solid var(--border);
  border-radius:10px;overflow:hidden;margin-bottom:24px;
}
.emp-table-row{
  display:grid;grid-template-columns:1fr auto auto auto;align-items:center;
  padding:14px 16px;border-bottom:1px solid var(--border);gap:12px;
}
.emp-table-row:last-child{border-bottom:none;}
.emp-table-header{
  font-size:10px;font-weight:700;letter-spacing:1.5px;text-transform:uppercase;
  color:var(--muted);background:var(--iron);
}
.emp-table-name{font-size:14px;font-weight:600;}
.emp-table-sub{font-size:11px;color:var(--muted);margin-top:2px;}
.status-pill{
  font-size:10px;font-weight:700;letter-spacing:1px;text-transform:uppercase;
  padding:4px 10px;border-radius:20px;white-space:nowrap;
}
.pill-in{background:rgba(46,204,113,0.12);color:var(--green);}
.pill-out{background:rgba(107,114,128,0.15);color:var(--muted);}
.pill-late{background:rgba(245,200,66,0.12);color:var(--yellow);}
.pill-break{background:rgba(244,98,42,0.12);color:var(--orange);}

/* ROSTER ROWS — used in live roster, employee roster, labor summary */
.roster-row{display:flex;align-items:center;padding:13px 16px;border-bottom:1px solid var(--border);gap:10px;}
.roster-row:last-child{border-bottom:none;}
.roster-name{flex:1;font-size:14px;font-weight:600;min-width:0;}
.roster-sub{font-size:11px;color:var(--muted);margin-top:2px;font-weight:400;}
/* [DISC-110] Replaces the silent gap where the INVITE/RE-INVITE button used to just vanish. */
.roster-invite-reason{font-size:11px;color:var(--muted);font-style:italic;align-self:center;padding:0 4px;}
.status-badge{font-size:10px;font-weight:700;letter-spacing:1px;text-transform:uppercase;padding:4px 10px;border-radius:20px;white-space:nowrap;}
.status-badge.in{background:rgba(46,204,113,0.12);color:var(--green);}
.status-badge.out{background:rgba(107,114,128,0.15);color:var(--muted);}
.status-badge.break{background:rgba(244,98,42,0.12);color:var(--orange);}
.btn-icon{
  width:32px;height:32px;display:inline-flex;align-items:center;justify-content:center;
  background:var(--iron);border:1px solid var(--border);border-radius:6px;
  cursor:pointer;font-size:15px;flex-shrink:0;transition:border-color 0.15s,background 0.15s;
}
.btn-icon:hover{border-color:var(--orange);background:rgba(244,98,42,0.08);}
.btn-icon.danger:hover{border-color:var(--red);background:rgba(231,76,60,0.08);}
/* [DISC-23f] Multi-word text buttons (ARCHIVE/RESTORE, SHOW/HIDE, etc.) were misusing .btn-icon
   — a 32px SQUARE box meant for a single glyph — squashing/clipping their own label. Same
   border/color scheme as .btn-icon, but auto width so the label actually fits. */
.btn-text-sm{
  display:inline-flex;align-items:center;justify-content:center;
  width:auto;height:auto;padding:6px 12px;
  background:var(--iron);border:1px solid var(--border);border-radius:6px;
  color:var(--white);font-family:var(--font-body);font-size:12px;font-weight:600;letter-spacing:0.5px;
  cursor:pointer;flex-shrink:0;transition:border-color 0.15s,background 0.15s;
}
.btn-text-sm:hover{border-color:var(--orange);background:rgba(244,98,42,0.08);}
.btn-text-sm.danger:hover{border-color:var(--red);background:rgba(231,76,60,0.08);}

/* PUNCH LOG TABLE */
.log-table{
  background:var(--steel);border:1px solid var(--border);
  border-radius:10px;overflow:hidden;
}
.log-row{
  display:grid;grid-template-columns:1fr 1fr 1fr auto;
  padding:12px 16px;border-bottom:1px solid var(--border);gap:8px;
  align-items:center;
}
.log-row:last-child{border-bottom:none;}
.log-row.zone-override-row{background:rgba(245,158,11,0.08);border-left:3px solid #f59e0b;}
.log-row.zone-override-row.reviewed{background:transparent;border-left:3px solid rgba(245,158,11,0.25);}
.punch-note{font-size:11px;color:var(--muted);margin-top:3px;line-height:1.4;}
.btn-review{min-height:24px;font-size:10px;padding:4px 9px;background:transparent;border:1px solid #f59e0b;border-radius:4px;color:#f59e0b;cursor:pointer;letter-spacing:0.5px;white-space:nowrap;}
.btn-review:hover{background:rgba(245,158,11,0.12);}
.btn-emergency-ack{min-height:32px;padding:7px 12px;background:#e05252;border:1px solid #ff8a8a;border-radius:6px;color:var(--white);font-size:11px;font-weight:800;letter-spacing:0.8px;text-transform:uppercase;cursor:pointer;box-shadow:0 0 0 1px rgba(224,82,82,0.22);}
.btn-emergency-ack:hover{background:#ff6b6b;color:var(--black);}
.log-row.header{
  font-size:10px;font-weight:700;letter-spacing:1.5px;
  text-transform:uppercase;color:var(--muted);background:var(--iron);
}
.log-name{font-size:13px;font-weight:600;}
.log-event{font-size:12px;color:var(--muted);}
.log-ts{font-family:var(--font-mono);font-size:11px;color:var(--muted);}

/* GEOFENCE PANEL */
.geo-config{background:var(--steel);border:1px solid var(--border);border-radius:10px;padding:24px;margin-bottom:20px;}
.geo-config h3{font-family:var(--font-display);font-size:22px;letter-spacing:2px;margin-bottom:6px;}
.geo-config p{font-size:13px;color:var(--muted);margin-bottom:20px;line-height:1.6;}
.geo-site-row{
  display:flex;flex-direction:column;
  padding:14px 0;border-bottom:1px solid var(--border);gap:10px;
}
.geo-site-row:last-child{border-bottom:none;}
.geo-site-name{font-size:14px;font-weight:600;}
.geo-site-coords{font-family:var(--font-mono);font-size:10px;color:var(--muted);margin-top:3px;word-break:break-all;}
.geo-site-coords .coords-sub{font-size:9px;color:var(--border);display:block;margin-top:2px;}
.radius-input-wrap{display:flex;align-items:center;gap:8px;flex-wrap:wrap;}
.radius-input{
  width:90px;padding:8px 10px;background:var(--iron);border:1px solid var(--border);
  border-radius:6px;color:var(--white);font-family:var(--font-mono);font-size:13px;
  outline:none;text-align:right;
}
.radius-input:focus{border-color:var(--orange);}
.radius-unit{font-size:12px;color:var(--muted);}
.btn-save-radius{
  padding:8px 16px;background:var(--orange);border:none;border-radius:6px;
  color:var(--black);font-family:var(--font-body);font-size:12px;font-weight:700;
  cursor:pointer;letter-spacing:0.5px;transition:background 0.2s;
}
.btn-save-radius:hover{background:var(--yellow);}
.btn-archive{
  padding:8px 14px;background:transparent;border:1px solid var(--border);border-radius:6px;
  color:var(--muted);font-family:var(--font-body);font-size:12px;font-weight:600;
  cursor:pointer;transition:all 0.2s;letter-spacing:0.5px;white-space:nowrap;
}
.btn-archive:hover{border-color:var(--yellow);color:var(--yellow);}
.btn-reactivate{
  padding:8px 14px;background:transparent;border:1px solid rgba(46,204,113,0.3);border-radius:6px;
  color:var(--green);font-family:var(--font-body);font-size:12px;font-weight:600;
  cursor:pointer;transition:all 0.2s;letter-spacing:0.5px;white-space:nowrap;
}
.btn-reactivate:hover{background:rgba(46,204,113,0.08);}
/* AI toggle — state managed by JS, not CSS sibling selectors */
#ai-toggle-track {
  display: block;
  position: absolute;
  inset: 0;
  border-radius: 12px;
  cursor: pointer;
  transition: background 0.2s;
  overflow: hidden;
  background: var(--border);
}
#ai-toggle-track.on { background: var(--orange); }
#ai-toggle-track .knob {
  position: absolute;
  top: 3px; left: 3px;
  width: 18px; height: 18px;
  border-radius: 50%;
  background: #fff;
  transition: transform 0.2s;
  pointer-events: none;
}
#ai-toggle-track.on .knob { transform: translateX(20px); }
/* Voice active pulse */
.voice-active { animation: voicePulse 1s infinite; }
@keyframes voicePulse { 0%,100%{opacity:1;} 50%{opacity:0.4;} }
.archived-section{margin-top:4px;}
.archived-toggle{
  display:flex;align-items:center;gap:10px;
  padding:12px 0;cursor:pointer;
  border-top:1px solid var(--border);
  user-select:none;
}
.archived-toggle-label{
  font-size:11px;font-weight:700;letter-spacing:1.5px;text-transform:uppercase;
  color:var(--muted);flex:1;
}
.archived-toggle-count{
  font-size:10px;font-weight:700;padding:3px 8px;border-radius:4px;
  background:rgba(107,114,128,0.15);color:var(--muted);
}
.archived-toggle-arrow{font-size:10px;color:var(--muted);transition:transform 0.2s;}
.archived-toggle-arrow.open{transform:rotate(180deg);}
.archived-list{display:none;}
.archived-list.open{display:block;}
.geo-site-row.archived{opacity:0.5;}
.geo-site-row.archived .geo-site-name{text-decoration:line-through;color:var(--muted);}

/* ADD EMPLOYEE */
.add-emp-form{
  background:var(--steel);border:1px solid var(--border);border-radius:10px;
  padding:24px;margin-bottom:20px;
}
.add-emp-form h3{font-family:var(--font-display);font-size:22px;letter-spacing:2px;margin-bottom:20px;}
.form-row{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin-bottom:14px;}
.btn-add-emp{
  padding:12px 24px;background:var(--orange);border:none;border-radius:6px;
  color:var(--black);font-family:var(--font-body);font-size:13px;font-weight:700;
  cursor:pointer;transition:background 0.2s;
}
.btn-add-emp:hover{background:var(--yellow);}

/* ADDRESS AUTOCOMPLETE */
.addr-suggestions{
  position:absolute;top:100%;left:0;right:0;
  background:var(--panel);border:1px solid var(--border);border-radius:0 0 8px 8px;
  z-index:200;max-height:220px;overflow-y:auto;display:none;
}
.addr-suggestions.open{display:block;}
.addr-suggestion-item{
  padding:10px 14px;font-size:13px;cursor:pointer;border-bottom:1px solid var(--border);
  line-height:1.4;
}
.addr-suggestion-item:last-child{border-bottom:none;}
.addr-suggestion-item:hover,.addr-suggestion-item.focused{background:var(--iron);color:var(--orange);}
.addr-suggestion-item small{display:block;color:var(--muted);font-size:11px;margin-top:2px;}

/* MODALS */
.modal-overlay{
  position:fixed;inset:0;background:rgba(0,0,0,0.75);
  display:flex;align-items:center;justify-content:center;
  z-index:1000;padding:24px;
}
.modal-box{
  background:var(--steel);border:1px solid var(--border);border-radius:16px;
  width:100%;max-width:400px;overflow:hidden;
}
.modal-title{
  font-family:var(--font-display);font-size:22px;letter-spacing:2px;
  padding:20px 24px 0;text-align:center;
}
.modal-body{padding:20px 24px 24px;}
.btn-modal-cancel{
  flex:1;padding:12px;background:var(--iron);border:1px solid var(--border);
  border-radius:8px;color:var(--white);font-family:var(--font-body);font-size:14px;
  font-weight:600;cursor:pointer;
}
.btn-modal-confirm{
  /* [v0-30] EXT-UI-07: white 14px text on --red #e74c3c is 3.82:1 — fails AA for normal-size
     text (needs 4.5:1). #d63a29 is the minimum darkening of the same red that passes
     (4.67:1). Applied ONLY to small-text red buttons; the 28px display-type
     .punch-btn-main.clock-out keeps --red because WCAG large-text AA is 3:1 and 3.82:1
     passes. The --red token itself is untouched (donor-verbatim). */
  flex:1;padding:12px;background:#d63a29;border:none;
  border-radius:8px;color:var(--white);font-family:var(--font-body);font-size:14px;
  font-weight:700;cursor:pointer;
}
.btn-modal-confirm.safe{background:var(--orange);}

/* PIN PAD */
.pin-dots{display:flex;gap:12px;justify-content:center;margin-bottom:24px;}
.pin-dots span{
  width:14px;height:14px;border-radius:50%;
  border:2px solid var(--border);background:transparent;
  transition:background 0.15s,border-color 0.15s;
}
.pin-dots span.filled{background:var(--orange);border-color:var(--orange);}
.pin-pad{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;}
.pin-key{
  padding:16px;background:var(--iron);border:1px solid var(--border);
  border-radius:10px;color:var(--white);font-size:22px;font-weight:700;
  cursor:pointer;transition:background 0.15s;font-family:var(--font-body);
}
.pin-key:hover{background:var(--panel);}
.pin-key:active{background:var(--orange);color:var(--black);}
.pin-key-cancel{color:var(--muted);font-size:18px;}
.pin-key-del{color:var(--muted);font-size:18px;}

/* TOAST */
/* [DISC-143] A long toast used to be unreadable, not merely ugly: `white-space:nowrap` with
   no width cap on a translateX(-50%)-centred element overflows BOTH edges symmetrically, so
   the message was clipped at the start AND the end (see the WebAuthn credential-manager error
   Tony hit — it began mid-phrase and ran off the right side). Wrapping + a viewport-relative
   cap fixes every long toast, not just that one message. Layout only — the locked colour
   scheme (platform CLAUDE.md) is untouched. */
#toast{
  position:fixed;bottom:24px;left:50%;transform:translateX(-50%) translateY(80px);
  background:var(--panel);border:1px solid var(--border);border-radius:8px;
  padding:12px 20px;font-size:13px;font-weight:600;
  transition:transform 0.3s cubic-bezier(0.34,1.56,0.64,1);
  z-index:9999;pointer-events:none;
  /* Never wider than the viewport, with a gutter so it never touches the edges. */
  max-width:min(420px, calc(100vw - 32px));
  /* `normal` explicitly replaces the old nowrap; `anywhere` breaks unbroken tokens (URLs,
     long error strings) that would otherwise force horizontal overflow anyway. */
  white-space:normal;overflow-wrap:anywhere;text-align:center;line-height:1.4;
  box-shadow:0 8px 32px rgba(0,0,0,0.4);
}
/* Keep the toast clear of the on-screen nav bar / home indicator on phones. */
@supports (padding: env(safe-area-inset-bottom)){
  #toast{bottom:calc(24px + env(safe-area-inset-bottom,0px));}
}
#toast.show{transform:translateX(-50%) translateY(0);}
#toast.success{border-color:rgba(46,204,113,0.4);color:var(--green);}
#toast.error{border-color:rgba(231,76,60,0.4);color:var(--red);}
#toast.info{border-color:rgba(244,98,42,0.4);color:var(--orange);}

/* SCROLLBAR */
::-webkit-scrollbar{width:4px;}
::-webkit-scrollbar-track{background:transparent;}
::-webkit-scrollbar-thumb{background:var(--border);border-radius:2px;}

/* EMPTY STATE */
.empty-state{text-align:center;padding:40px 20px;color:var(--muted);}
.empty-state .icon{font-size:36px;margin-bottom:12px;}
.empty-state p{font-size:14px;line-height:1.6;}

/* BOOT FALLBACK — [v0-26] moved out of index.html's inline <style> so the shipped page has
   zero <style> elements, letting the server's CSP use style-src 'self' with no
   'unsafe-inline' (see server/core/http.js). */
#boot-fallback{height:100%;display:flex;align-items:center;justify-content:center;color:var(--muted);font-family:var(--font-body);background:var(--black);}

/* ─── FOCUS VISIBILITY — [v0-29] EXT-UI-05 ───
   Global keyboard-focus ring. :focus-visible only fires for keyboard/AT navigation, so
   touch/mouse users see zero visual change (the existing :focus border-color styles on
   inputs are untouched and still apply). */
:focus-visible{outline:2px solid var(--orange);outline-offset:2px;}

/* ─── RESPONSIVE BREAKPOINTS — [v0-29] EXT-UI-02 ───
   The donor had zero @media queries: one phone-shaped layout at every width. These add the
   minimum sensible adaptations at small-phone and tablet widths WITHOUT any visual redesign —
   same components, same colors, same spacing language. */

/* Small phones (<= 400px): stop 2-column form grids from crushing inputs; scale the two
   oversized display-type elements down one step. */
@media (max-width: 400px){
  .form-row{grid-template-columns:1fr;}
  .login-logo{font-size:42px;}
  .live-time{font-size:38px;}
  .metric-val{font-size:34px;}
  .emp-scroll{padding:16px;}
  .admin-panel{padding:20px 14px;}
}

/* Tablet and up (>= 768px): cap and center the single-column flows so lines don't stretch
   edge-to-edge on wide screens; let the 2x2 metrics grid use the width it gains. */
@media (min-width: 768px){
  .emp-scroll{max-width:720px;width:100%;margin:0 auto;}
  .admin-panel.active{max-width:960px;margin:0 auto;width:100%;}
  .metrics-grid{grid-template-columns:repeat(4,1fr);}
}

/* ─── SKIP LINK — [v0-30] EXT-UI-12 ───
   Visually hidden until keyboard-focused, then presented as a floating button. */
.skip-link{
  position:absolute;left:-9999px;top:0;z-index:10000;
  background:var(--orange);color:var(--black);font-family:var(--font-body);
  font-weight:700;font-size:13px;padding:10px 16px;border-radius:0 0 8px 0;
  text-decoration:none;
}
.skip-link:focus{left:0;}

/* ─── EXPANDED HIT AREAS — [v0-30] EXT-UI-11 ───
   Invisible ::after overlays enlarge the touch target of the small controls without any
   visual change. Vertical expansion reaches >=44px everywhere; horizontal expansion on
   .btn-icon is capped at -3px because adjacent icon buttons sit 6px apart (a larger overlay
   would steal taps from the neighbor) — 38px wide x 44px tall, which clears WCAG 2.5.8 AA
   (24px) and Apple's 44pt guidance vertically. All other listed controls reach 44px both
   axes. Buttons are position:relative anchors for the overlay. */
.btn-icon,.btn-logout,.btn-review,.btn-emergency-ack,.login-tab{position:relative;}
.btn-icon::after{content:'';position:absolute;top:-6px;bottom:-6px;left:-3px;right:-3px;}
.btn-logout::after{content:'';position:absolute;inset:-8px -4px;}
.btn-review::after{content:'';position:absolute;inset:-11px -4px;}
.btn-emergency-ack::after{content:'';position:absolute;inset:-6px -4px;}
.login-tab::after{content:'';position:absolute;inset:-4px -1px;}

/* ─── SHARED MODAL CARD — [v0-30] EXT-UI-13 ───
   Promoted from per-module inline style helpers (boxStyle()/titleStyle() duplicated in
   admin/panels/corrections.js, admin/panels/employees.js, reports/reportForm.js). One
   source of truth; values are exactly the previously-inlined ones. */
.modal-card{background:var(--steel);border:1px solid var(--border);border-radius:12px;padding:24px;max-width:420px;margin:0 auto;}
.modal-card--wide{max-width:480px;}
.modal-card-title{font-family:var(--font-display);font-size:24px;letter-spacing:2px;margin-bottom:6px;}
.modal-card-title--spaced{margin-bottom:20px;}
/* [DISC-35] Shared full-width secondary/dismiss button for .modal-card contents (mirrors
   .btn-zone-dismiss's proportions) — promoted out of hoursView.js's one-off inline
   secondaryButtonStyle() so future modal-card content reuses one definition instead of
   re-inlining the same 8 properties. */
.btn-modal-secondary{
  width:100%;padding:13px;background:transparent;border:1px solid var(--border);border-radius:8px;
  color:var(--muted);font-family:var(--font-body);font-size:13px;font-weight:600;
  cursor:pointer;transition:border-color 0.2s,color 0.2s;margin-top:12px;letter-spacing:0.3px;
}
.btn-modal-secondary:hover{border-color:var(--white);color:var(--white);}

/* [v1-14] RPT-5/6/7 photo attachments — staged (pre-submit) and server-synced thumbnails share
   this exact markup shape (attachments.js's photoThumb()/serverAttachmentThumb()). */
.report-photo-strip{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px;}
.report-photo-item{width:110px;}
.report-photo-thumb{position:relative;width:72px;height:72px;border-radius:8px;overflow:hidden;border:1px solid var(--border);}
.report-photo-thumb img{width:100%;height:100%;object-fit:cover;cursor:pointer;display:block;}
.report-row-thumbs{display:flex;gap:6px;flex-wrap:wrap;margin-top:10px;}
.report-row-thumb{width:42px;height:42px;border-radius:6px;border:1px solid var(--border);object-fit:cover;cursor:pointer;}
.report-photo-name{position:absolute;left:0;right:0;bottom:0;background:rgba(0,0,0,0.72);font-size:9px;color:var(--white);padding:2px 4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.report-photo-caption{font-size:10px;color:var(--muted);line-height:1.3;margin-top:4px;}
.report-photo-remove{
  position:absolute;top:2px;right:2px;width:20px;height:20px;border-radius:50%;
  background:rgba(0,0,0,0.7);color:var(--white);border:none;cursor:pointer;
  font-size:14px;line-height:1;display:flex;align-items:center;justify-content:center;
}
.report-photo-caption-edit{
  position:absolute;left:2px;top:2px;min-height:24px;padding:3px 6px;background:rgba(10,10,10,0.78);
  border:1px solid rgba(244,98,42,0.55);border-radius:5px;color:var(--orange);
  font-size:8px;font-weight:800;letter-spacing:0.5px;cursor:pointer;
}
.lightbox-img{max-width:100%;max-height:100%;border-radius:8px;object-fit:contain;}
.camera-preview{width:100%;max-height:55vh;background:var(--black);border-radius:8px;object-fit:contain;border:1px solid var(--border);}
/* [DISC-193] touch-action:none stops the BROWSER'S OWN native pinch-zoom on this element — that
   was the original bug: the page visually zoomed in on pinch while the captured pixels never
   changed. Pinch is instead read explicitly (attachments.js) and driven through the same setZoom()
   path as the buttons/slider, so every input actually reaches the captured frame. */
.camera-frame{position:relative;overflow:hidden;border-radius:8px;touch-action:none;}
.camera-flash{position:absolute;inset:0;background:#fff;opacity:0;pointer-events:none;}
.camera-flash--fire{animation:cameraFlash 260ms ease-out;}
@keyframes cameraFlash{0%{opacity:0.85;}100%{opacity:0;}}

/* [DISC-193] Zoom controls — large, thumb-reachable, usable in gloves. The slider gives fine
   control; the +/- buttons are the primary gloved-thumb target (44px floor, WCAG 2.5.5-ish);
   the level readout says where you are, since a gloved pinch has no other feedback. Locked
   palette only: iron/border/orange/white/black. */
.camera-zoom-controls{display:flex;align-items:center;gap:10px;margin-top:10px;padding:8px 10px;background:var(--iron);border:1px solid var(--border);border-radius:8px;}
.camera-zoom-btn{
  flex:0 0 auto;width:44px;height:44px;border-radius:8px;border:1px solid var(--border);
  background:var(--black);color:var(--orange);font-size:22px;font-weight:800;line-height:1;
  display:flex;align-items:center;justify-content:center;cursor:pointer;
}
.camera-zoom-btn:active{background:var(--orange);color:var(--black);}
.camera-zoom-slider{flex:1 1 auto;min-width:0;height:44px;accent-color:var(--orange);}
.camera-zoom-level{
  flex:0 0 auto;min-width:44px;text-align:center;font-family:var(--font-display);
  font-size:13px;letter-spacing:0.5px;color:var(--white);
}
.photo-review{display:flex;flex-direction:column;align-items:center;gap:12px;width:100%;}
.photo-review .lightbox-img{width:min(90vw,760px);height:min(62vh,560px);background:var(--black);}
.photo-review-actions{display:flex;align-items:center;justify-content:center;gap:8px;flex-wrap:wrap;width:100%;max-width:760px;}
.photo-review-count{font-family:var(--font-mono);font-size:13px;color:var(--muted);min-width:52px;text-align:center;}
.receipt-preview-btn{width:44px;height:44px;border:1px solid var(--border);border-radius:6px;background:var(--iron);padding:0;align-items:center;justify-content:center;overflow:hidden;cursor:pointer;}
.receipt-preview-btn img{width:100%;height:100%;object-fit:cover;}
.receipt-result-row:hover{background:rgba(244,98,42,0.06) !important;}
.camera-note{font-size:12px;color:var(--muted);line-height:1.5;margin:0 0 10px;}
.settings-toggle-row{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--white);margin:10px 0;}
/* [DISC-129] D5 puts seven numeric levers on one card. .form-row's fixed two columns would
   leave a ragged trailing cell; auto-fit keeps them even at any width and collapses to one
   column on a phone through the same 1fr floor the rest of the panel uses. */
.settings-break-grid{grid-template-columns:repeat(auto-fit,minmax(190px,1fr));}
/* [DISC-135] One lever per row: its own opt-in on the left, the label (with its tooltip) in the
   middle, the control on the right. A row is either IN FORCE or it is not, and the difference has
   to be visible at a glance — --inactive dims the whole row and the control is genuinely
   `disabled`, so an admin can never mistake a stored draft for a setting that is actually
   running. Collapses to a stacked layout on a phone. */
.settings-lever-row{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:10px;padding:8px 0;border-bottom:1px solid var(--border);}
.settings-lever-row:last-of-type{border-bottom:none;}
.settings-lever-optin{display:flex;align-items:center;gap:6px;font-size:11px;color:var(--muted);white-space:nowrap;}
.settings-lever-label{display:flex;align-items:center;gap:6px;font-size:13px;color:var(--white);}
.settings-lever-row input[type=number]{max-width:110px;}
.settings-lever-row--inactive .settings-lever-label{color:var(--muted);}
.settings-lever-row--inactive input:disabled{opacity:0.45;}
@media(max-width:520px){.settings-lever-row{grid-template-columns:1fr;align-items:flex-start;}}
.settings-card{background:var(--steel);border:1px solid var(--border);border-radius:8px;padding:24px;margin-bottom:16px;}
.settings-card-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;gap:10px;}
.settings-card-title{font-family:var(--font-display);font-size:18px;letter-spacing:1px;margin:0 0 6px;}
.settings-card-copy{font-size:12px;color:var(--muted);margin-bottom:12px;line-height:1.5;}
.settings-card-note{font-size:11px;color:var(--muted);margin-top:10px;font-style:italic;}
.settings-role-list{margin-top:12px;}
.settings-list-spaced{margin-top:14px;}
.settings-field-tight{margin-bottom:0;}
.settings-week-date{font-size:12px;color:var(--muted);}
.settings-mode-label{font-family:var(--font-mono);color:var(--orange);margin-bottom:10px;}
.settings-recipient-row{display:grid;grid-template-columns:1fr auto;gap:8px;align-items:end;margin-bottom:8px;}
.settings-input{width:100%;padding:10px 12px;background:var(--iron);border:1px solid var(--border);border-radius:6px;color:var(--white);font-family:var(--font-body);font-size:14px;box-sizing:border-box;margin-bottom:8px;}
.settings-input:focus{border-color:var(--orange);outline:none;}
.settings-small-btn{min-height:32px;background:transparent;border:1px solid var(--orange);color:var(--orange);border-radius:6px;padding:6px 14px;font-size:12px;cursor:pointer;font-family:var(--font-body);}
.settings-small-btn--danger{border-color:var(--red);color:var(--red);}
.settings-save-btn{width:100%;min-height:40px;padding:12px;background:var(--orange);border:none;border-radius:8px;color:var(--black);font-family:var(--font-display);cursor:pointer;margin-top:10px;}
.settings-secondary-btn{min-height:40px;padding:12px 20px;background:transparent;border:1px solid var(--border);border-radius:8px;color:var(--muted);font-family:var(--font-body);cursor:pointer;}
.settings-role-card{background:var(--iron);border-radius:8px;padding:14px;margin-bottom:10px;border:1px solid var(--border);}
.settings-role-buttons{display:flex;justify-content:space-between;margin-top:8px;gap:8px;}
.settings-waiver-copy{font-size:13px;color:var(--muted);line-height:1.6;margin-bottom:16px;}
.settings-waiver-check{display:flex;align-items:center;gap:8px;margin:10px 0;}
.settings-actions{display:flex;gap:10px;}
.loading-indicator{display:flex;align-items:center;justify-content:center;gap:8px;min-height:56px;color:var(--muted);font-size:13px;}
.loading-indicator__dot{width:9px;height:9px;border-radius:50%;background:var(--orange);animation:blink 0.8s infinite;}
.emergency-top-btn{border-color:rgba(224,82,82,0.6)!important;color:#e05252!important;}
.admin-emergency-banner{background:rgba(224,82,82,0.16);border-bottom:1px solid rgba(224,82,82,0.55);color:var(--white);padding:10px 16px;}
.admin-emergency-banner-inner{display:flex;align-items:center;gap:10px;justify-content:space-between;flex-wrap:wrap;font-size:13px;}
.admin-emergency-banner strong{font-family:var(--font-display);color:#e05252;letter-spacing:1px;}

/* [v1-13] RPT-4 — the saved-report view's chrome. The type pill so EOD/Incident/Custom is
   obvious at a glance, and the action row.
   [DISC-181] The label/value field rules that used to live here (.report-view-meta,
   .report-view-fields, .report-view-field-label/-value) are GONE, not orphaned: the fields moved
   into the shared report document (.report-doc-* below), which renders the pre-submit review, the
   post-submit view and the print output from one implementation. Nothing referenced them any
   more, and dead selectors are how a stylesheet stops being readable. */
.report-type-pill{font-size:10px;font-weight:700;letter-spacing:1px;padding:3px 8px;border-radius:4px;background:rgba(244,98,42,0.15);color:var(--orange);}
.report-type-pill--incident{background:rgba(224,82,82,0.15);color:#e05252;}
.report-type-pill--custom{background:rgba(46,204,113,0.15);color:var(--green);}
.report-view-actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:16px;}

/* RPT-4's "PDF" requirement — a print stylesheet, not a heavy PDF library. Printing the page
   while the report-view modal is open renders JUST the report: readable, clean, structured
   HTML on a plain white background, no app chrome, no interactive controls. */
@media print{
  body > *:not(#modal-report-view){display:none !important;}
  /* [DISC-181] The app shell is `html,body{height:100%;overflow:hidden}` and the modal container
     carries `overflow-y:auto`. A scroll container does NOT paginate — it CLIPS — so a report
     longer than one page silently lost everything past the fold. A six-photo report printed as
     one page with photos 5 and 6 sliced off at the bottom edge until these three lines existed. */
  /* ...and the shell's dark background must not be painted onto the paper. `html,body` carry
     `background:var(--black)`, which with printBackground on floods every page (and every page
     BEYOND the content) solid black. A report printed on a dark page is unreadable and unusable
     as something handed to a client. */
  html,body{
    height:auto !important;overflow:visible !important;
    background:#fff !important;color:#000 !important;
  }
  #modal-report-view{
    position:static !important;inset:auto !important;background:none !important;
    padding:0 !important;display:block !important;
    overflow:visible !important;height:auto !important;max-height:none !important;
  }
  #modal-report-view .modal-card{
    box-shadow:none !important;border:none !important;max-width:none !important;
    background:#fff !important;color:#000 !important;padding:0 !important;margin:0 !important;
  }
  #modal-report-view .modal-card-title{color:#000 !important;}
  /* [DISC-181] The document's own colour overrides live in the DISC-181 print block below. */
  #modal-report-view .report-photo-remove,
  #modal-report-view .report-view-actions{display:none !important;}
}

/* ─── MY HOURS VIEW — [DISC-35] ───
   usr/hoursView.js's DOM (employee-screen "My Hours" modal + the admin shell's own "My Hours"
   tab, same renderHoursView() code path — SC-SELF-02). Previously rendered as a flat stack of
   .hv-* <div>/<span> elements with ZERO matching CSS anywhere in this file — pure browser
   defaults, i.e. "all bunched up together." Built to reuse the app's own established
   conventions rather than invent a new visual language: segmented preset control shaped like
   .login-tabs/.report-type-selector, a hero-stat total + 2-up sub-grid shaped like
   .metrics-grid/.metric-card, .form-group inputs for the custom-range fields, and a compact
   horizontally scrollable day table for scanning longer periods. */

.hv-view{display:flex;flex-direction:column;gap:18px;}

/* Segmented date-range control — same shape/behavior as .login-tabs. */
.hv-presets{display:flex;gap:4px;background:var(--iron);border-radius:8px;padding:4px;}
.hv-preset-btn{
  flex:1;padding:10px 4px;border:none;background:transparent;
  color:var(--muted);font-family:var(--font-body);font-size:12px;font-weight:600;
  border-radius:6px;cursor:pointer;transition:all 0.2s;letter-spacing:0.3px;white-space:nowrap;
}
.hv-preset-btn.active{background:var(--orange);color:var(--black);}

/* Custom range picker — same card chrome as .geo-config, same input styling as .form-group. */
.hv-custom-range{background:var(--steel);border:1px solid var(--border);border-radius:10px;padding:16px;}
.hv-custom-range-fields{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:14px;}
.hv-custom-range .form-group{margin-bottom:0;}
.hv-apply-btn{
  width:100%;padding:12px;background:var(--orange);border:none;border-radius:8px;
  color:var(--black);font-family:var(--font-body);font-size:13px;font-weight:700;
  letter-spacing:0.5px;cursor:pointer;transition:background 0.2s;
}
.hv-apply-btn:hover{background:var(--yellow);}

/* Summary — the range total is the hero stat (never equal-weighted with its own components);
   Regular/Overtime sit below as a 2-up sub-grid, same card language as .metric-card. */
.hv-summary{display:flex;flex-direction:column;gap:12px;}
.hv-summary-total{background:var(--steel);border:1px solid var(--border);border-radius:12px;padding:24px;text-align:center;}
.hv-summary-total-label{font-size:11px;font-weight:700;letter-spacing:1.5px;text-transform:uppercase;color:var(--muted);margin-bottom:8px;}
.hv-summary-total-value{font-family:var(--font-display);font-size:44px;letter-spacing:1px;color:var(--orange);line-height:1;}
.hv-summary-subgrid{display:grid;grid-template-columns:1fr 1fr;gap:12px;}
.hv-summary-stat{background:var(--steel);border:1px solid var(--border);border-radius:10px;padding:16px;text-align:center;}
.hv-summary-stat-value{font-family:var(--font-display);font-size:24px;letter-spacing:1px;color:var(--white);}
.hv-summary-stat-value.ot{color:var(--yellow);}
.hv-summary-stat-label{font-size:10px;font-weight:700;letter-spacing:1px;text-transform:uppercase;color:var(--muted);margin-top:6px;}

/* Day table - horizontally scrollable so every date exposes In/Lunch/Out/Hours/OT/Flags. */
.hv-days{display:block;}
.hv-table-scroll{
  overflow-x:auto;background:var(--steel);border:1px solid var(--border);border-radius:10px;
  -webkit-overflow-scrolling:touch;
}
.hv-table{width:100%;min-width:680px;border-collapse:collapse;font-size:13px;}
.hv-table th,.hv-table td{padding:11px 12px;text-align:left;border-bottom:1px solid var(--border);vertical-align:top;}
.hv-table th{
  color:var(--muted);font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:1px;
  background:var(--iron);white-space:nowrap;
}
.hv-day-row:last-child td,.hv-detail-row:last-child td{border-bottom:none;}
.hv-day-date{font-size:14px;font-weight:700;white-space:nowrap;}
.hv-day-hours{font-family:var(--font-mono);font-size:14px;color:var(--white);white-space:nowrap;}
.hv-detail-row td{padding-top:0;color:var(--muted);font-size:11px;line-height:1.4;background:rgba(255,255,255,0.02);}
.hv-flags-cell{display:flex;align-items:center;gap:6px;flex-wrap:wrap;min-width:92px;}
.hv-day-ot{font-size:10px;font-weight:700;letter-spacing:0.5px;padding:3px 8px;border-radius:4px;background:rgba(245,200,66,0.12);color:var(--yellow);white-space:nowrap;}
/* Same amber tone as the zone-override modal/log's "pending review" language elsewhere in the
   app (.zone-override-title, .log-row.zone-override-row) — one meaning, one color, everywhere. */
.hv-may-change{font-size:10px;font-weight:700;letter-spacing:0.5px;padding:3px 8px;border-radius:4px;background:rgba(245,158,11,0.12);color:#f59e0b;}

@media (max-width: 400px){
  .hv-summary-total-value{font-size:36px;}
  .hv-preset-btn{font-size:11px;padding:9px 3px;}
}

/* ─── ESTIMATED PAYCHECK CARD — [DISC-36] ───
   usr/paycheckEstimate.js's DISTINCT "Estimated Paycheck" card (SC-SELF-03), mounted into
   #paycheck-estimate-wrap on the employee main clock screen, just above the CLOCK IN button.
   Same root cause as DISC-35's My Hours view: the .paycheck-card* classes had ZERO matching
   rules anywhere in this file — pure browser defaults. Built to reuse the app's own established
   conventions: card chrome, an "Est. Net Pay" hero stat (never equal-weighted with its own
   Gross/Deductions components, same "hero + sub-grid" language as .hv-summary-total/-subgrid),
   and tokens.css's tonal ramp for nesting — this card sits INSIDE the already-var(--steel)
   .clock-widget, so it steps up to var(--iron) (matching .shift-duration's existing nested
   badge in the same parent), and its own inner stat chips step up again to var(--panel). */
.paycheck-card{background:var(--iron);border:1px solid var(--border);border-radius:12px;padding:16px;margin:0 0 20px;text-align:left;}
.paycheck-card-title{font-family:var(--font-display);font-size:11px;font-weight:700;letter-spacing:1.5px;text-transform:uppercase;color:var(--muted);}
.paycheck-card-hours{font-size:11px;color:var(--muted);margin-top:4px;margin-bottom:14px;}
.paycheck-card-hero{text-align:center;padding-bottom:14px;margin-bottom:14px;border-bottom:1px solid var(--border);}
.paycheck-card-hero-label{font-size:10px;font-weight:700;letter-spacing:1.5px;text-transform:uppercase;color:var(--muted);margin-bottom:6px;}
.paycheck-card-hero-value{font-family:var(--font-display);font-size:36px;letter-spacing:1px;color:var(--orange);line-height:1;}
.paycheck-card-subgrid{display:grid;grid-template-columns:1fr 1fr;gap:10px;}
.paycheck-card-subgrid.single{grid-template-columns:1fr;}
.paycheck-card-stat{background:var(--panel);border:1px solid var(--border);border-radius:8px;padding:12px;text-align:center;}
.paycheck-card-stat-value{font-family:var(--font-mono);font-size:16px;color:var(--white);}
.paycheck-card-stat-label{font-size:9px;font-weight:700;letter-spacing:1px;text-transform:uppercase;color:var(--muted);margin-top:5px;}
.paycheck-card-note{font-size:10px;color:var(--muted);line-height:1.5;margin-top:14px;padding-top:12px;border-top:1px solid var(--border);}
.pay-details{margin-top:12px;border-top:1px solid var(--border);padding-top:10px;}
.pay-details summary{cursor:pointer;font-size:11px;font-weight:700;text-transform:uppercase;color:var(--white);}
.pay-field-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin:10px 0;}
.pay-field{display:flex;flex-direction:column;gap:5px;font-size:10px;font-weight:700;text-transform:uppercase;color:var(--muted);}
.pay-field input,.pay-field select{width:100%;box-sizing:border-box;background:var(--panel);border:1px solid var(--border);border-radius:6px;color:var(--white);padding:9px 10px;font-family:var(--font-body);font-size:13px;text-transform:none;}
.pay-toggle{display:flex;align-items:center;gap:7px;min-height:38px;color:var(--muted);font-size:10px;font-weight:800;text-transform:uppercase;}
.pay-toggle input{width:16px;height:16px;accent-color:var(--accent);}
.pay-form-note{font-size:10px;color:var(--muted);line-height:1.4;margin-top:8px;}

@media (max-width: 400px){
  .paycheck-card-hero-value{font-size:30px;}
  .pay-field-grid{grid-template-columns:1fr;}
}

/* [DISC-168] The Integrations tab. Every value is an existing token — the palette is LOCKED and
   nothing here re-themes anything. */
.integrations-list{display:flex;flex-direction:column;gap:16px;}
.integration-card{background:var(--iron);border:1px solid var(--border);border-radius:10px;padding:16px;}
.integration-card.connected{border-color:var(--orange);}
.integration-head{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap;}
.integration-name{font-family:var(--font-display);letter-spacing:1px;font-size:16px;}
.integration-enable,.integration-mode{display:inline-flex;align-items:center;gap:8px;font-size:13px;color:var(--muted);}
.integration-mode{margin:12px 0;}
.integration-blurb{font-size:12px;color:var(--muted);margin-top:4px;}
.integration-section-title{font-size:11px;letter-spacing:1.2px;text-transform:uppercase;color:var(--muted);margin-top:12px;margin-bottom:6px;}
.integration-list{margin:0;padding-left:18px;font-size:13px;line-height:1.5;}
.integration-list.out li{color:var(--white);}
.integration-list.in li{color:var(--green);}
/* Deliberately legible rather than greyed to the point of invisibility: an item nobody can read
   is the same as an item that was never shown, which is the failure this list exists to avoid. */
.integration-list.pending li{color:var(--muted);}
.integration-pending-entity{color:var(--white);}
.integration-pending-reason{color:var(--muted);}
.integration-last-sync{font-size:11px;color:var(--muted);margin-top:12px;}
/* DISC-193: static planned-state panel, deliberately no fake grid/report rows. */
.job-costing-panel{background:var(--iron);border:1px solid var(--border);border-radius:8px;padding:18px;max-width:760px;}
.job-costing-status{display:inline-flex;align-items:center;border:1px solid var(--orange);color:var(--orange);font-family:var(--font-display);font-size:12px;letter-spacing:1px;padding:4px 8px;margin-bottom:12px;}
.job-costing-panel h2{font-size:22px;line-height:1.2;margin:0 0 10px;color:var(--white);}
.job-costing-lede{font-size:14px;line-height:1.55;color:var(--muted);margin:0 0 18px;}
.job-costing-details{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;}
.job-costing-detail{border:1px solid var(--border);border-radius:8px;padding:12px;background:var(--black);}
.job-costing-detail-label{font-family:var(--font-display);font-size:13px;letter-spacing:.8px;margin-bottom:6px;color:var(--white);}
.job-costing-detail-copy{font-size:12px;line-height:1.45;color:var(--muted);}
.job-costing-toolbar{display:grid;grid-template-columns:1fr 170px auto auto auto;gap:10px;align-items:end;margin-bottom:16px;}
.job-costing-date,.job-costing-burden{margin-bottom:0;}
.job-costing-metrics{margin-bottom:16px;}
.job-costing-loading{padding:16px;color:var(--muted);font-family:var(--font-mono);font-size:12px;text-transform:uppercase;}
.job-costing-config{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;margin:0 0 16px;}
.job-costing-config-form{border:1px solid var(--border);border-radius:8px;padding:12px;background:var(--iron);}
.job-costing-config-form .form-group{margin-bottom:10px;}
.job-costing-table-head,.job-costing-row{display:grid;grid-template-columns:minmax(220px,1.5fr) 110px 130px 120px 130px;gap:12px;align-items:center;}
.job-costing-table-head{font-family:var(--font-mono);font-size:11px;text-transform:uppercase;color:var(--muted);padding:0 14px 8px;}
.job-costing-row{padding:14px;}
.job-costing-num{font-family:var(--font-mono);font-size:13px;color:var(--white);white-space:nowrap;}
@media (max-width:640px){
  .integration-head{flex-direction:column;align-items:flex-start;}
  .integration-mode{align-items:flex-start;}
  .job-costing-details{grid-template-columns:1fr;}
  .job-costing-config{grid-template-columns:1fr;}
  .job-costing-toolbar{grid-template-columns:1fr;}
  .job-costing-table-head{display:none;}
  .job-costing-row{grid-template-columns:1fr;align-items:start;}
/* ─── THE REPORT AS A DOCUMENT — [DISC-181] ───
   reports/reportDocument.js renders ONE document in two modes: editable before submission, and
   read-only after it. The same DOM is what prints, so everything below has a print counterpart in
   the @media print block rather than a second, drifting layout.

   Every value is an existing token. The palette is LOCKED (see sitepunch-platform/CLAUDE.md) —
   nothing here re-themes anything; this is spacing, hierarchy and type scale only, aimed at
   "something a contractor would hand a client". */

.report-doc{display:flex;flex-direction:column;gap:16px;}

/* Heading — written entirely from what the app already knows. The user types none of it. */
.report-doc-head{border-bottom:2px solid var(--orange);padding-bottom:14px;}
.report-doc-brandline{display:flex;justify-content:space-between;align-items:baseline;gap:12px;margin-bottom:10px;}
.report-doc-company{font-family:var(--font-display);font-size:18px;letter-spacing:1.5px;color:var(--white);line-height:1.1;}
.report-doc-brandmark{font-family:var(--font-display);font-size:11px;letter-spacing:2px;color:var(--orange);flex-shrink:0;}
.report-doc-title{margin-bottom:10px;}
.report-doc-meta{display:flex;flex-wrap:wrap;align-items:center;gap:8px 18px;}
.report-doc-meta-pair{display:flex;flex-direction:column;gap:2px;}
.report-doc-meta-label{font-size:9px;letter-spacing:1.2px;text-transform:uppercase;color:var(--muted);}
.report-doc-meta-value{font-size:13px;color:var(--white);}

/* The mode notice. This is the read-only rule stated in words — a disabled input alone does not
   explain WHY, and "why can't I fix this" is how silent-edit requests start. */
.report-doc-notice{border-radius:8px;padding:10px 12px;font-size:12px;line-height:1.45;}
.report-doc-notice strong{font-family:var(--font-display);letter-spacing:1px;}
.report-doc-notice--edit{background:rgba(245,200,66,0.08);border:1px solid rgba(245,200,66,0.35);color:var(--yellow);}
.report-doc-notice--locked{background:rgba(46,204,113,0.08);border:1px solid rgba(46,204,113,0.3);color:var(--green);}
/* [DISC-187] "These are your raw words, we could not tidy them up." Muted-on-iron rather than a
   warning color: nothing is wrong, the report files perfectly well, and alarming a tech about a
   dropped provider call would be friction over a non-problem. Locked palette. */
.report-doc-notice--untidied{background:var(--iron);border:1px solid var(--border);color:var(--muted);margin-top:8px;}

.report-doc-fields{display:flex;flex-direction:column;gap:16px;}
.report-doc-field-label{display:block;font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:1px;margin-bottom:5px;}
.report-doc-field-value{font-size:15px;line-height:1.55;white-space:pre-wrap;color:var(--white);}
.report-doc-empty{color:var(--muted);font-style:italic;}
.report-doc-section-label{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:1px;margin-top:4px;}

/* Edit mode. 16px is a floor, not a preference: below it iOS Safari zooms on focus. */
.report-doc-input{
  width:100%;padding:12px;background:var(--iron);border:1px solid var(--border);border-radius:8px;
  color:var(--white);font-family:var(--font-body);font-size:16px;line-height:1.45;outline:none;
}
.report-doc-input:focus{border-color:var(--orange);}
.report-doc-input--text{min-height:112px;max-height:340px;overflow-y:auto;resize:vertical;-webkit-overflow-scrolling:touch;}

/* Photos, big enough that a blurred shot is obvious BEFORE the report is filed — the small
   72px thumbnails elsewhere in the app are a picker affordance, not a review one. */
.report-doc-photos{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px;margin-top:8px;}
/* Read mode nests attachments.js's own .report-photo-strip inside the wrapper (see
   reportForm.js's photoSlot) so that container keeps its v1-14 class list untouched — the
   document-scale grid is applied here rather than by mutating it. The WRAPPER must not also be a
   grid in that case: it has exactly one child, so it would place the strip in a single column and
   halve every photo. Proved on a real six-photo report before this modifier existed. */
.report-doc-photos--slot{display:block;}
.report-doc-photos > .report-photo-strip{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px;margin-top:0;}
.report-doc-photos .report-photo-item{width:auto;}
.report-doc-photos .report-photo-thumb{width:100%;height:auto;aspect-ratio:4/3;}
.report-doc-photos .report-photo-thumb img{width:100%;height:100%;object-fit:cover;}
.report-doc-photos-empty{font-size:12px;color:var(--muted);font-style:italic;}

/* ─── [DISC-187] PHOTOS SET ASIDE — the tray ───
   Excluding a photo from a report must be as obviously undoable as it was easy to do, so the
   excluded ones sit right under the ones the report is carrying rather than disappearing. The
   whole tile is the restore target (a gloved thumb does not hit a 20px icon), the tiles are
   deliberately smaller and dimmed so the two groups never read as one grid, and the count is in
   the label because "did that stick" is the question this tray answers at a glance.
   Locked palette: iron/border/muted/orange only. */
.report-photo-tray{margin-top:14px;border-top:1px dashed var(--border);padding-top:10px;}
.report-photo-tray-label{font-family:var(--font-display);font-size:11px;letter-spacing:1px;color:var(--muted);margin-bottom:8px;}
.report-photo-tray-strip{display:flex;flex-wrap:wrap;gap:8px;}
.report-photo-tray-item{
  position:relative;width:92px;padding:0;background:var(--iron);
  border:1px dashed var(--border);border-radius:8px;overflow:hidden;cursor:pointer;
}
.report-photo-tray-item img{display:block;width:100%;height:69px;object-fit:cover;opacity:0.45;}
.report-photo-tray-item:hover img,.report-photo-tray-item:focus-visible img{opacity:0.8;}
.report-photo-tray-item:focus-visible{outline:2px solid var(--orange);outline-offset:2px;}
.report-photo-tray-restore{
  display:block;width:100%;padding:5px 0;background:var(--orange);color:var(--black);
  font-family:var(--font-display);font-size:10px;letter-spacing:1px;
}

.report-doc-receipt{border:1px solid var(--border);border-radius:8px;padding:12px;background:var(--iron);}
.report-doc-receipt-rows{display:flex;flex-wrap:wrap;gap:10px 18px;margin-top:8px;}
.report-doc-footer{border-top:1px solid var(--border);padding-top:10px;font-size:10px;color:var(--muted);letter-spacing:0.5px;}

/* ─── PRINTED / PDF REPORT — [DISC-181] ───
   Extends the v1-13 @media print block above rather than replacing it. Two jobs here: put the
   document on white paper as something a client would accept, and size the photos so they can
   actually be SEEN on paper (you cannot tap to zoom a printout) while still fitting several to a
   page. Two columns of ~3.5in on Letter/A4 with a 3.1in height cap is the compromise: a photo
   large enough to judge, and roughly four to six per page depending on how much text precedes
   them. Every image is break-inside:avoid so none is ever sliced across a page boundary. */
@media print{
  #modal-report-view .report-doc{gap:14pt;color:#000 !important;}
  #modal-report-view .report-doc-head{border-bottom:2pt solid #000 !important;}
  #modal-report-view .report-doc-company,
  #modal-report-view .report-doc-meta-value,
  #modal-report-view .report-doc-field-value{color:#000 !important;}
  #modal-report-view .report-doc-brandmark,
  #modal-report-view .report-doc-meta-label,
  #modal-report-view .report-doc-section-label,
  #modal-report-view .report-doc-footer{color:#444 !important;}
  #modal-report-view .report-doc-footer{border-top:1pt solid #999 !important;}
  /* The mode notices are screen affordances — on paper they are noise on a legal document. */
  #modal-report-view .report-doc-notice,
  #modal-report-view .report-doc-photos-empty{display:none !important;}
  /* [DISC-187] THE SELECTION REACHES THE PAPER. A photo set aside is not on the printout, and the
     tray it is sitting in is not either — otherwise "exclude this from what goes to the PM" would
     be a screen-only gesture that the PDF quietly ignored, which is the whole point of the
     feature. The controls go too: an X and a PUT BACK button printed on a client document read as
     defects. Nothing is deleted to achieve this; the attachment is simply not in this rendering. */
  #modal-report-view .report-photo-tray,
  #modal-report-view .report-photo-remove,
  #modal-report-view .report-photo-tray-item{display:none !important;}
  #modal-report-view .report-doc-head{break-after:avoid;page-break-after:avoid;}
  #modal-report-view .report-doc-field{break-inside:avoid;page-break-inside:avoid;}

  /* NOT the --slot wrapper: it holds one child, so making it a grid would put the whole strip in
     one column and halve every photo. */
  #modal-report-view .report-doc-photos:not(.report-doc-photos--slot),
  #modal-report-view .report-doc-photos > .report-photo-strip{
    display:grid !important;grid-template-columns:1fr 1fr !important;gap:10pt !important;
  }
  #modal-report-view .report-doc-photos--slot{display:block !important;}
  #modal-report-view .report-doc-photos .report-photo-item{
    width:auto !important;break-inside:avoid;page-break-inside:avoid;
  }
  #modal-report-view .report-doc-photos .report-photo-thumb{
    width:100% !important;height:auto !important;aspect-ratio:auto !important;
    border:1pt solid #999 !important;border-radius:0 !important;
  }
  #modal-report-view .report-doc-photos .report-photo-thumb img{
    width:100% !important;height:auto !important;max-height:3.1in !important;object-fit:contain !important;
  }
  /* Pre-submit editing controls have no meaning on paper; the caption/remove overlays are the
     admin's tools, not part of the record. */
  #modal-report-view .report-photo-caption-edit{display:none !important;}
  #modal-report-view .report-photo-name{position:static !important;background:none !important;color:#444 !important;font-size:8pt !important;}
  #modal-report-view .report-photo-caption{color:#444 !important;font-size:8pt !important;}
}

/* -----------------------------------------------------------------------------------------------
   [DISC-187] UNSENT VOICE NOTES — the recovery surface (reports/transcriptRecovery.js).
   Shown when a dictated transcript has sat undelivered past a day, or has pushed the local vault
   past its bound. It is the ONLY way words leave that vault other than a server acknowledgement,
   so it is built to be read and copied, not skimmed: full text, selectable, monospace-free body at
   the same 16px the form uses (below 16px iOS zooms on tap and does not zoom back).
   Locked palette — iron/border/muted/white/orange only.
   -------------------------------------------------------------------------------------------- */
.transcript-recovery-note{font-size:13px;line-height:1.5;color:var(--muted);margin-bottom:14px;}
.transcript-recovery-list{display:flex;flex-direction:column;gap:12px;max-height:55vh;overflow-y:auto;-webkit-overflow-scrolling:touch;}
.transcript-recovery-item{background:var(--iron);border:1px solid var(--border);border-radius:8px;padding:12px;}
.transcript-recovery-when{font-family:var(--font-display);font-size:11px;letter-spacing:1px;color:var(--orange);margin-bottom:6px;}
.transcript-recovery-text{font-size:16px;line-height:1.5;color:var(--white);white-space:pre-wrap;user-select:text;-webkit-user-select:text;}

/* -----------------------------------------------------------------------------------------------
   [DISC-187] PHOTO SELECTION — the "set aside" tray.
   Tony: "if you wanna add the photo back, we need a way for it to pop back up in there. I don't
   know how that looks." This is how it looks: excluded photos do not vanish, they drop into a
   labelled strip immediately below the ones the report is carrying, at half size, and the WHOLE
   TILE is the put-back button — not a 20px icon a gloved thumb has to find. Rendered only when
   something is in it, so a report with every photo included costs no extra screen.
   Locked palette: iron / border / muted / orange / black only.
   -------------------------------------------------------------------------------------------- */
.report-photo-tray{margin-top:14px;padding:10px;background:var(--iron);border:1px dashed var(--border);border-radius:8px;}
.report-photo-tray-label{font-family:var(--font-display);font-size:11px;letter-spacing:1px;color:var(--muted);margin-bottom:8px;}
.report-photo-tray-strip{display:flex;flex-wrap:wrap;gap:8px;}
.report-photo-tray-item{
  position:relative;width:84px;padding:0;border:1px solid var(--border);border-radius:6px;
  background:transparent;cursor:pointer;overflow:hidden;display:block;
}
.report-photo-tray-item img{width:100%;height:64px;object-fit:cover;display:block;opacity:0.45;}
.report-photo-tray-item:hover img,.report-photo-tray-item:focus-visible img{opacity:0.8;}
.report-photo-tray-item:focus-visible{outline:2px solid var(--orange);outline-offset:2px;}
.report-photo-tray-restore{
  display:block;width:100%;padding:4px 0;background:var(--orange);color:var(--black);
  font-family:var(--font-display);font-size:10px;letter-spacing:1px;text-align:center;
}

/* -----------------------------------------------------------------------------------------------
   [DISC-187] PRINT — the selection is the point of the feature, so it must reach the paper.
   An excluded photo is not in the printed report at all: the tray is a working control, and a
   controller who set a photo aside before sending it to the PM must not find it on page 3.
   Extends the existing @media print blocks rather than replacing them.
   -------------------------------------------------------------------------------------------- */
@media print{
  #modal-report-view .report-photo-tray,
  .report-doc .report-photo-tray{display:none !important;}
  /* The exclude control is a control, never part of the document. */
  #modal-report-view .report-photo-remove,
  .report-doc .report-photo-remove{display:none !important;}
}
