/* PPCJ Commissary — shared design system.
   Dark gold shell (home / reports), light surface for work screens (POS / admin). */

:root {
  --gold:      #f5b722;
  --gold-dim:  #b8860b;
  --navy:      #0f1b2d;
  --navy-2:    #16243a;
  --navy-3:    #1e3050;
  --ink:       #16202e;
  --muted:     #64748b;
  --line:      #e2e8f0;
  --bg:        #f1f5f9;
  --card:      #ffffff;
  --blue:      #2563eb;
  --blue-dark: #1d4ed8;
  --green:     #16a34a;
  --red:       #dc2626;
  --amber:     #d97706;
  --violet:    #7c3aed;
  --radius:    14px;
  --shadow:    0 1px 3px rgba(15,27,45,.08), 0 8px 24px rgba(15,27,45,.06);
  --font:      'Segoe UI', system-ui, -apple-system, sans-serif;
  --display:   'Rajdhani', var(--font);
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  font-family: var(--font);
  background: var(--bg);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
}

/* ---------- dark shell ---------- */
body.dark {
  background: radial-gradient(1200px 600px at 20% -10%, #23375a 0%, var(--navy) 55%);
  color: #e6edf7;
  min-height: 100vh;
}
body.dark .card { background: rgba(255,255,255,.04); border: 1px solid rgba(255,255,255,.09); }
body.dark .muted { color: #93a4bd; }

h1, h2, h3, .display { font-family: var(--display); letter-spacing: .5px; }

/* ---------- layout ---------- */
.wrap  { max-width: 1400px; margin: 0 auto; padding: 20px; }
/* flex-wrap is a no-op wherever there is room, and the difference between a
   toolbar that reflows on a phone and one that runs off the right edge. */
.row   { display: flex; gap: 14px; align-items: center; flex-wrap: wrap; }
.between { display: flex; gap: 14px; align-items: center; justify-content: space-between;
           flex-wrap: wrap; }
.grid  { display: grid; gap: 16px; }
.g2 { grid-template-columns: repeat(auto-fit, minmax(320px,1fr)); }
.g3 { grid-template-columns: repeat(auto-fit, minmax(260px,1fr)); }
.g4 { grid-template-columns: repeat(auto-fit, minmax(200px,1fr)); }
.spacer { flex: 1; }

.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 18px;
  box-shadow: var(--shadow);
}

/* ---------- facility header ---------- */
.facility {
  display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
  padding: 20px 22px; border-radius: 18px;
  background: rgba(255,255,255,.04);
  border: 1px solid rgba(245,183,34,.28);
}
.seal {
  width: 76px; height: 76px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  background: radial-gradient(circle at 35% 30%, #ffd45e, var(--gold-dim));
  color: #3b2600; font-weight: 800; font-family: var(--display); font-size: 15px;
  box-shadow: 0 0 0 4px rgba(245,183,34,.16);
}
.facility h1 { margin: 0; color: var(--gold); font-size: 28px; }
.facility .sub { color: #b9c6da; font-size: 13px; letter-spacing: 1px; }
.facility .addr { color: #8fa1bb; font-size: 12px; margin-top: 4px; }

.clock {
  margin-left: auto; text-align: center; padding: 14px 22px; border-radius: 14px;
  border: 2px solid var(--gold); background: rgba(245,183,34,.06);
}
.clock .time { font-family: var(--display); font-size: 34px; font-weight: 700; color: var(--gold); letter-spacing: 3px; }
.clock .date { font-size: 12px; color: #b9c6da; margin-top: 2px; }
.clock .stat { font-size: 11px; color: var(--green); margin-top: 4px; letter-spacing: 1px; }

/* ---------- buttons ---------- */
.btn {
  appearance: none; border: 0; cursor: pointer; font: inherit; font-weight: 600;
  padding: 11px 18px; border-radius: 10px; background: var(--blue); color: #fff;
  display: inline-flex; align-items: center; gap: 8px; transition: filter .12s, transform .06s;
}
.btn:hover:not(:disabled) { filter: brightness(1.08); }
.btn:active:not(:disabled) { transform: translateY(1px); }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn.green  { background: var(--green); }
.btn.red    { background: var(--red); }
.btn.amber  { background: var(--amber); }
.btn.violet { background: var(--violet); }
.btn.ghost  { background: transparent; color: var(--ink); border: 1px solid var(--line); }
.btn.gold   { background: var(--gold); color: #3b2600; }
.btn.lg     { padding: 16px 24px; font-size: 17px; width: 100%; justify-content: center; }
.btn.sm     { padding: 7px 12px; font-size: 13px; }
/* .btn sets display:inline-flex above, and an AUTHOR rule beats the UA
   stylesheet's [hidden] { display: none } no matter how specific. Without this
   line `btn.hidden = true` sets the property correctly and the button still
   renders — which is exactly what happened to the POS camera-scan button on a
   device with no BarcodeDetector. Same guard, same reason, as .modal-bg[hidden]
   further down. Any future class that sets `display` needs one too. */
.btn[hidden] { display: none; }

/* ---------- forms ---------- */
label.lbl { display: block; font-size: 11px; letter-spacing: 1px; color: var(--muted);
            text-transform: uppercase; margin-bottom: 6px; font-weight: 600; }
input, select, textarea {
  width: 100%; padding: 12px 14px; font: inherit;
  border: 1.5px solid var(--line); border-radius: 10px; background: #fff; color: var(--ink);
}
input:focus, select:focus, textarea:focus { outline: 0; border-color: var(--blue); box-shadow: 0 0 0 3px rgba(37,99,235,.12); }

/* ---------- stats ---------- */
.stat-card { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 16px 18px; }
.stat-card .k { font-size: 11px; letter-spacing: 1px; color: var(--muted); text-transform: uppercase; font-weight: 600; }
.stat-card .v { font-family: var(--display); font-size: 30px; font-weight: 700; margin-top: 4px; }
.stat-card .n { font-size: 12px; color: var(--muted); }

/* ---------- misc ---------- */
.pill { display: inline-block; padding: 3px 10px; border-radius: 999px; font-size: 11px;
        font-weight: 700; letter-spacing: .5px; text-transform: uppercase; }
.pill.green { background: #dcfce7; color: #15803d; }
.pill.red   { background: #fee2e2; color: #b91c1c; }
.pill.amber { background: #fef3c7; color: #b45309; }
.pill.blue  { background: #dbeafe; color: #1d4ed8; }
.pill.gray  { background: #e2e8f0; color: #475569; }

.money { font-family: var(--display); font-weight: 700; }
.money.pos { color: var(--green); }
.money.neg { color: var(--red); }
.muted { color: var(--muted); font-size: 13px; }

table { width: 100%; border-collapse: collapse; }
th { text-align: left; font-size: 11px; letter-spacing: 1px; text-transform: uppercase;
     color: var(--muted); padding: 10px 12px; border-bottom: 2px solid var(--line); }
td { padding: 11px 12px; border-bottom: 1px solid var(--line); font-size: 14px; }
tr:hover td { background: #f8fafc; }

/* ---------- modal ---------- */
.modal-bg {
  position: fixed; inset: 0; background: rgba(15,27,45,.55); backdrop-filter: blur(2px);
  display: grid; place-items: center; z-index: 90;
  /* env() falls back to the plain 20px on anything without safe areas. */
  padding: max(20px, env(safe-area-inset-top)) max(20px, env(safe-area-inset-right))
           max(20px, env(safe-area-inset-bottom)) max(20px, env(safe-area-inset-left));
  /* Pin the single grid cell to the visible area on BOTH axes. Left to size
     itself, the cell takes the modal's max-content width and height — a wide
     table then makes the cell wider than the phone and taller than the screen,
     and the modal is centred inside that, hanging off the edges with no way to
     scroll to what is cut off. minmax(0, 1fr) caps the cell at the viewport;
     `place-items: center` still centres the modal rather than stretching it,
     and `width: min(…, 100%)` now resolves against the screen as intended. */
  grid-template: minmax(0, 1fr) / minmax(0, 1fr);
}
.modal-bg[hidden] { display: none; }
/* max-height + overflow, not just width. .modal-bg caps the GRID CELL at the
   viewport, but the modal inside it had no height limit — so on a phone with
   the on-screen keyboard up, a tall dialog simply ran past the bottom of the
   screen and its primary action could not be reached or scrolled to. This also
   lets the browser scroll a focused input back into view inside the modal. */
.modal { background: #fff; color: var(--ink); border-radius: 18px; padding: 26px;
         width: min(480px, 100%); box-shadow: 0 24px 60px rgba(0,0,0,.3);
         max-height: 100%; overflow: auto; overscroll-behavior: contain; }
.modal h3 { margin: 0 0 18px; font-size: 21px; }

/* Wide data modal — for a table to be READ, not a confirmation dialog.
   `.modal` sizes itself with `width`, so an inline `max-width` larger than
   480px never takes effect (max-width only clamps downward). This overrides
   `width` itself, which is the only thing that actually widens it.
   The modal is capped to the viewport and lays out as a column, so the
   title and the Close button stay put while only the body scrolls. */
.modal.wide {
  width: min(1180px, 100%);
  max-height: min(88vh, 100%);
  display: flex;
  flex-direction: column;
  overflow: hidden;          /* .modal-scroll below is this one's scroller */
}
.modal.wide .modal-scroll { flex: 1 1 auto; min-height: 0; overflow: auto; }

/* Laptops: keep the generous width but give the shorter screen more height. */
@media (max-height: 800px) {
  .modal.wide { max-height: 92vh; padding: 20px; }
}

/* Tablet and phone: full bleed, and the table scrolls sideways inside the
   body rather than pushing the modal off-screen. */
@media (max-width: 720px) {
  .modal-bg { padding: max(10px, env(safe-area-inset-top)) max(10px, env(safe-area-inset-right))
                      max(10px, env(safe-area-inset-bottom)) max(10px, env(safe-area-inset-left)); }
  .modal { padding: 20px; border-radius: 14px; }
  .modal.wide { padding: 18px; max-height: 94vh; border-radius: 14px; }
}

/* ---------- toast ---------- */
#toasts { position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%);
          display: grid; gap: 8px; z-index: 200; }
.toast { padding: 13px 22px; border-radius: 10px; color: #fff; font-weight: 600;
         box-shadow: 0 8px 24px rgba(0,0,0,.25); animation: pop .2s ease; }
.toast.ok  { background: var(--green); }
.toast.err { background: var(--red); }
.toast.info{ background: var(--ink); }
@keyframes pop { from { opacity: 0; transform: translateY(8px); } }

/* ---------- connection badge ---------- */
.conn { display: inline-flex; align-items: center; gap: 7px; padding: 7px 14px;
        border-radius: 999px; font-size: 12px; font-weight: 700; }
.conn.on  { background: #dcfce7; color: #15803d; }
.conn.off { background: #fee2e2; color: #b91c1c; }
.conn .dot { width: 8px; height: 8px; border-radius: 50%; background: currentColor; }

.topbar { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; padding: 14px 20px;
          background: #fff; border-bottom: 1px solid var(--line); position: sticky; top: 0; z-index: 20; }
.topbar h2 { margin: 0; font-size: 20px; }

/* ---------- PDL QR card ----------
   Shared by the on-screen preview and the printed card, so the two can
   never drift apart.

   Measured against references/QR CODE SAMPLE.png rather than guessed: the
   yellow there runs #FFDD10 at the top to #FFE935 at the foot, the lettering
   is near-black navy (#171B35 / #2A2B49), the card carries a large corner
   radius, and the QR sits on a generously padded white panel with roughly a
   2:3 portrait card around it.

   The white panel is a scanning requirement, not decoration: a QR's quiet
   zone must be the light colour, and yellow-on-black is a weaker contrast
   ratio than white-on-black for the cheap cameras used at the counter. The
   reference agrees — it uses the same white panel — so matching it costs no
   readability. Where the two ever conflict, readability wins. */
.qrcard {
  background: linear-gradient(180deg, #FFDC0D 0%, #FFE43A 100%);
  color: #171B35;
  border-radius: 28px;
  padding: 22px 20px 30px;
  text-align: center;
  box-shadow: 0 6px 18px rgba(0,0,0,.18);
}
.qrcard .fac  { font-family: var(--display); font-weight: 700; font-size: 15px;
                letter-spacing: .5px; }
.qrcard .sub  { font-size: 10px; letter-spacing: 1.5px; opacity: .72; margin-top: 2px; }
.qrcard .panel {
  background: #fff; border-radius: 22px;
  padding: 16px;                       /* the physical quiet zone */
  margin: 18px auto 20px; width: max-content;
}
/* pixelated keeps the module edges hard when the small GIF is scaled up —
   a smoothed QR is measurably harder for a camera to decode. */
.qrcard .panel img { display: block; width: 214px; height: 214px; image-rendering: pixelated; }
.qrcard .nm   { font-family: var(--display); font-weight: 700; font-size: 24px; line-height: 1.15; }
.qrcard .pdl  { font-size: 16px; font-weight: 600; color: #2A2B49;
                letter-spacing: .3px; margin-top: 6px; }

/* ---------- shared camera scanner ----------
   One block for the one scanner in app.js. The preview must NEVER stretch: a
   squashed barcode is one BarcodeDetector cannot read, so the frame keeps its
   own aspect ratio and `cover` crops instead of distorting.

   The height is capped against the viewport rather than left to the video,
   because the two controls under it are the ones an officer needs when the scan
   is going wrong — a preview that pushes Cancel and Switch camera off a phone
   in landscape is the exact moment they are unreachable. */
.scanmodal { width: min(440px, 100%); }
.scanbox { position: relative; border-radius: 12px; overflow: hidden; background: #000; }
.scanbox video { display: block; width: 100%; aspect-ratio: 4 / 3;
                 max-height: 52vh; object-fit: cover; }
/* A frame, not a mask: the middle stays completely clear, so the guide never
   sits over the code it is helping to line up. The huge spread shadow dims
   everything OUTSIDE the frame and is clipped by .scanbox's overflow. */
.scanguide { position: absolute; inset: 14% 8%; border: 3px solid rgba(255,255,255,.85);
             border-radius: 10px; box-shadow: 0 0 0 100vmax rgba(0,0,0,.3); }
#camNote { margin-top: 10px; text-align: center; }
.scanacts { display: flex; gap: 10px; margin-top: 14px; }
.scanacts .btn { flex: 1; justify-content: center; min-height: 44px; }

/* The note under a scanned field — "already exists", "not found". It sets
   `display: flex`, so it needs the same [hidden] guard .btn has: an author rule
   beats the UA stylesheet's [hidden] default, and without this the box renders
   even when the property says it should not. */
.scan-note { background: #fff7ed; color: #9a3412; border: 1px solid #fdba74;
             padding: 12px 14px; border-radius: 10px; font-size: 13px; margin-top: 14px;
             display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.scan-note[hidden] { display: none; }

/* Phone held sideways: there is barely any height, and the buttons matter more
   than a large picture. */
@media (orientation: landscape) and (max-height: 520px) {
  .scanbox video { max-height: 42vh; }
  .scanmodal { padding: 16px; }
}

/* ---------- touch targets ----------
   Counter staff work on tablets, often with a wet or gloved finger. 44px is the
   smallest reliably hittable target. Only coarse pointers are changed: a mouse
   does not need it, and widening every control on the dense admin tables would
   cost a screenful of rows. 16px inputs also stop the mobile browser zooming in
   on focus, which is what leaves the page scrolled sideways afterwards. */
@media (pointer: coarse) {
  .btn { min-height: 44px; }
  .btn.sm { min-height: 40px; padding: 9px 14px; }
  input, select, textarea { min-height: 44px; font-size: 16px; }
  label.row input[type="checkbox"] { min-height: 0; }
}

/* ---------- narrow screens ----------
   Nothing here changes the desktop layout; it only stops a fixed-width row from
   running past the right edge of a phone. */
@media (max-width: 720px) {
  .wrap { padding: 14px 12px; }
  .topbar { padding: 12px 14px; gap: 10px; }
  .topbar h2 { font-size: 18px; }
  /* A toast pinned 24px up sits under the on-screen keyboard on a phone. */
  #toasts { left: 12px; right: 12px; bottom: 14px; transform: none; }
  .toast { text-align: center; }
}

@media print {
  .noprint, .topbar, #toasts { display: none !important; }
  body { background: #fff; }
  /* Force the yellow through: browsers drop background colours when printing
     unless the page asks for them explicitly. */
  .qrcard { -webkit-print-color-adjust: exact; print-color-adjust: exact;
            box-shadow: none; }
}
