/* ===== tokens.css ======================================================== */
/* tokens.css
   Design tokens — every colour, size, radius and easing the app uses.
   Change a value here and it changes everywhere.

   The palette is built around one idea: the machine photo is the content,
   so the chrome is a dark neutral frame and the photo sits on pure white.
   The three action colours are fixed by the spec and must stay
   distinguishable at a glance on a sunlit tablet screen.
   ---------------------------------------------------------------- */

:root{
  /* ---- chrome ---------------------------------------------------- */
  --bg:#0b1220;            /* behind everything */
  --bar:#111a2b;           /* top bar */
  --bar-2:#1c2941;         /* raised surface on the bar */
  --bar-3:#243352;         /* hover on bar surfaces */
  --line:#2b3b58;          /* hairlines on dark */
  --stage:#ffffff;         /* matches the white background of the photos */

  /* ---- ink ------------------------------------------------------- */
  --ink:#0f172a;           /* primary text on light */
  --ink-2:#475569;         /* secondary */
  --ink-3:#7c8ba1;         /* tertiary / hints */
  --on-dark:#eef3fa;       /* primary text on the bar */
  --on-dark-2:#9fb0c9;     /* secondary text on the bar */

  /* ---- surfaces -------------------------------------------------- */
  --card:#ffffff;
  --card-2:#f7f9fc;        /* inset rows, table stripes */
  --card-line:#dde5ee;
  --card-line-2:#eef2f7;   /* lighter divider */

  /* ---- intent ---------------------------------------------------- */
  --accent:#1d6ff2;
  --accent-ink:#ffffff;
  --accent-soft:#e9f1fe;
  --ok:#0f9d58;
  --warn:#c77700;
  --danger:#d32f2f;
  --danger-soft:#fdecec;

  /* ---- action colours (the pin takes the colour of its action) ---- */
  --clean:#16a34a;         /* Cleaning     — green         */
  --clean-soft:#e8f7ee;
  --clean-ink:#11663a;
  --inspect:#2563eb;       /* Inspection   — blue          */
  --inspect-soft:#e8f0ff;
  --inspect-ink:#1d4ed8;
  --lube:#b8860b;          /* Lubrication  — dark yellow   */
  --lube-soft:#fdf4e0;
  --lube-ink:#7d5c07;
  --unset:#94a3b8;         /* no action chosen yet         */

  /* ---- shape ----------------------------------------------------- */
  --r-sm:8px;
  --r:12px;                /* controls */
  --radius:12px;           /* legacy alias, still referenced */
  --r-lg:16px;             /* cards, callout, modals */
  --r-pill:999px;

  /* ---- depth ----------------------------------------------------- */
  --shadow-1:0 1px 2px rgba(15,23,42,.08), 0 1px 3px rgba(15,23,42,.06);
  --shadow-2:0 4px 12px rgba(15,23,42,.10), 0 2px 4px rgba(15,23,42,.06);
  --shadow-3:0 16px 40px rgba(15,23,42,.20), 0 4px 12px rgba(15,23,42,.10);
  --shadow:var(--shadow-3);          /* legacy alias */
  --ring:0 0 0 3px rgba(29,111,242,.30);

  /* ---- touch ------------------------------------------------------
     48px is the smallest thing a gloved finger hits reliably;
     the primary actions get 56. Don't go below --tap anywhere. */
  --tap:48px;
  --tap-lg:56px;
  --tap-sm:40px;           /* icon-only, inside a dialog */

  /* ---- rhythm ---------------------------------------------------- */
  --s1:4px;  --s2:8px;  --s3:12px; --s4:16px;
  --s5:20px; --s6:24px; --s7:32px; --s8:40px;

  /* ---- type -------------------------------------------------------
     Thai needs more leading than Latin at the same size, hence 1.55. */
  --font:"Segoe UI","Leelawadee UI","Noto Sans Thai","Sarabun",Tahoma,system-ui,-apple-system,"Helvetica Neue",Arial,sans-serif;
  --fs-xs:12px;
  --fs-sm:13px;
  --fs-md:15px;
  --fs-lg:17px;
  --fs-xl:20px;
  --fs-2xl:24px;
  --lh:1.55;
  --lh-tight:1.3;

  /* ---- motion -----------------------------------------------------
     Short and flat. Anything slower feels laggy under a glove. */
  --ease:cubic-bezier(.2,.7,.3,1);
  --t-fast:120ms;
  --t:180ms;
}

/* Respect a user who has asked for less movement. */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
  }
}

/* ===== base.css ========================================================== */
/* base.css
   Resets, typography defaults and the app shell.
   ---------------------------------------------------------------- */

*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html,body{height:100%;margin:0}

body{
  font-family:var(--font);
  font-size:var(--fs-md);
  line-height:var(--lh);
  background:var(--bg);
  color:var(--ink);
  overflow:hidden;
  overscroll-behavior:none;
  -webkit-text-size-adjust:100%;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}

button,input,select,textarea{font-family:inherit;font-size:inherit;color:inherit}
button{cursor:pointer;border:0;background:none}
select{appearance:none;-webkit-appearance:none;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%239fb0c9' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 14px center;padding-right:36px;
}
h1,h2,h3{line-height:var(--lh-tight);font-weight:700}

/* Visually hidden but still read aloud. */
.sr{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;
}

/* ---------- App shell ---------- */
#app{position:fixed;inset:0;display:flex;flex-direction:column}

/* ===== layout.css ======================================================== */
/* layout.css
   Layout: top bar, stage, pin layer, legend, empty state, controls.

   Two rules govern everything here:
   1. Nothing interactive is smaller than --tap (48px). Operators use this
      with gloves on, standing next to a running machine.
   2. The chrome never competes with the photo. Dark frame, white stage,
      colour reserved for the three action categories.
   ---------------------------------------------------------------- */

/* ================================ TOP BAR ================================ */
#topbar{
  flex:0 0 auto;
  background:var(--bar);
  color:var(--on-dark);
  display:flex;align-items:center;gap:var(--s3);
  padding:var(--s2) var(--s4);
  padding-top:calc(var(--s2) + env(safe-area-inset-top));
  border-bottom:1px solid var(--line);
  box-shadow:0 1px 0 rgba(0,0,0,.25);
  flex-wrap:wrap;row-gap:var(--s2);
  position:relative;z-index:20;
}

.brand{display:flex;align-items:center;gap:var(--s3);min-width:0}
.brand .logo{
  width:40px;height:40px;border-radius:11px;flex:0 0 auto;
  background:linear-gradient(140deg,#3b82f6,#0ea5a4);
  display:grid;place-items:center;
  font-weight:800;font-size:var(--fs-sm);color:#fff;letter-spacing:.6px;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.25);
}
.brand .t1{font-weight:700;font-size:var(--fs-md);line-height:1.2;white-space:nowrap}
.brand .t2{font-size:var(--fs-xs);color:var(--on-dark-2);line-height:1.35;white-space:nowrap}
.spacer{flex:1 1 auto}

/* ---- machine picker: the most-used control on the bar ------------------- */
.machine-pick{
  display:flex;align-items:center;gap:var(--s2);
  min-width:0;flex:1 1 320px;max-width:600px;
}
.machine-pick label{
  font-size:var(--fs-xs);color:var(--on-dark-2);white-space:nowrap;
  text-transform:uppercase;letter-spacing:.6px;font-weight:600;
}
select#machineSelect{
  flex:1 1 auto;min-width:0;height:var(--tap);
  border-radius:var(--r);
  background:var(--bar-2);color:var(--on-dark);
  border:1px solid var(--line);
  padding:0 var(--s3);
  font-size:var(--fs-md);font-weight:600;
  transition:background var(--t-fast) var(--ease),border-color var(--t-fast) var(--ease);
}
select#machineSelect:hover{background:var(--bar-3)}

/* One visible focus ring for the whole app. */
select#machineSelect:focus-visible,
button:focus-visible,input:focus-visible,textarea:focus-visible,[tabindex]:focus-visible{
  outline:3px solid #6aa8ff;outline-offset:2px;
}

/* ---- bar buttons -------------------------------------------------------- */
.bar-actions{display:flex;align-items:center;gap:var(--s2);flex:0 0 auto}

.btn{
  height:var(--tap);min-width:var(--tap);padding:0 var(--s4);
  border-radius:var(--r);border:1px solid var(--line);
  background:var(--bar-2);color:var(--on-dark);
  font-weight:600;font-size:var(--fs-md);
  display:inline-flex;align-items:center;justify-content:center;gap:var(--s2);
  white-space:nowrap;
  transition:background var(--t-fast) var(--ease),transform var(--t-fast) var(--ease);
}
.btn:hover{background:var(--bar-3)}
.btn:active{transform:translateY(1px)}
.btn.primary{
  background:var(--accent);border-color:transparent;color:var(--accent-ink);
  height:var(--tap-lg);padding:0 var(--s5);
  box-shadow:0 2px 8px rgba(29,111,242,.35);
}
.btn.primary:hover{background:#155fd4}
.btn:disabled{opacity:.45;cursor:not-allowed;transform:none;box-shadow:none}
.btn .count{
  background:rgba(255,255,255,.18);border-radius:var(--r-pill);
  padding:2px 9px;font-size:var(--fs-xs);font-weight:800;
  font-variant-numeric:tabular-nums;
}

/* ================================= STAGE ================================= */
#stage{
  position:relative;flex:1 1 auto;overflow:hidden;background:var(--stage);
  touch-action:none;overscroll-behavior:contain;cursor:crosshair;
  user-select:none;-webkit-user-select:none;
  contain:layout paint;
}
#stage.can-pan{cursor:grab}
#stage.grabbing,#stage.can-pan.grabbing{cursor:grabbing}

/* `will-change:transform` is applied by script ONLY while a gesture or
   animation is running. A permanently composited layer is rasterised once at
   a fixed scale and then stretched, which measurably halves the resolution
   of the zoomed image; dropping the hint when motion stops makes the browser
   re-rasterise at the true scale and at full device resolution. */
#world{position:absolute;top:0;left:0;transform-origin:0 0;-webkit-user-drag:none}
#world.live{will-change:transform}

/* No frame or shadow: the photo's own white background merges into the stage
   so the machine appears to sit directly on the page. */
#photo{
  display:block;user-select:none;-webkit-user-drag:none;pointer-events:none;
  background:#fff;image-rendering:auto;
}
#pinLayer{position:absolute;inset:0;pointer-events:none;z-index:6}

/* While a hosted build pulls the photo over the network. */
#stage.loading::after{
  content:"";position:absolute;left:50%;top:50%;width:34px;height:34px;margin:-17px 0 0 -17px;
  border:3px solid var(--card-line);border-top-color:var(--accent);border-radius:50%;
  animation:spin .8s linear infinite;z-index:7;
}
@keyframes spin{to{transform:rotate(360deg)}}

/* ================== PINS — colour follows the action ===================== */
/* Positioned with a whole-pixel translate in screen space — no scaling, so
   the pin, its number and its check badge stay pixel-crisp at any zoom.
   These measurements are load-bearing: the zoom tests assert the pin is
   pixel-identical from 100% to 1600%. Don't "tidy" them. */
.pin{position:absolute;left:0;top:0;width:0;height:0;--c:var(--unset)}
.pin-inner{
  position:absolute;left:-17px;bottom:0;width:34px;height:41px;
  filter:drop-shadow(0 3px 4px rgba(15,23,42,.38));
}
.pin .body{
  position:absolute;left:0;top:0;width:34px;height:34px;
  border-radius:50% 50% 50% 4px;transform:rotate(-45deg);
  background:var(--c);border:2.5px solid #fff;display:grid;place-items:center;
  transition:background .16s ease;
}
.pin .num{
  transform:rotate(45deg);color:#fff;font-weight:800;font-size:14px;line-height:1;
  font-variant-numeric:tabular-nums;text-shadow:0 1px 2px rgba(0,0,0,.35);
}
.pin .check{
  display:none;position:absolute;right:-5px;top:-4px;width:16px;height:16px;border-radius:50%;
  background:#fff;border:1.5px solid var(--c);place-items:center;
}
.pin .check svg{width:9px;height:9px;stroke:var(--c);stroke-width:3.4;fill:none;stroke-linecap:round;stroke-linejoin:round}
.pin.is-done .check{display:grid}
.pin.is-draft .body{animation:pulse 1.15s ease-in-out infinite}
.pin.is-sel .body{box-shadow:0 0 0 4px rgba(15,23,42,.22)}
@keyframes pulse{0%,100%{transform:rotate(-45deg) scale(1)}50%{transform:rotate(-45deg) scale(1.13)}}
.pin-hit{position:absolute;left:-7px;top:-5px;width:48px;height:52px;border-radius:24px;cursor:pointer;pointer-events:auto}

/* ================================ LEGEND ================================= */
#legend{
  position:absolute;left:var(--s4);bottom:var(--s4);
  display:flex;gap:var(--s1);flex-wrap:wrap;align-items:center;
  background:rgba(255,255,255,.97);
  border:1px solid var(--card-line);border-radius:var(--r);
  padding:var(--s2) var(--s3);
  box-shadow:var(--shadow-2);
  pointer-events:none;
  padding-bottom:calc(var(--s2) + env(safe-area-inset-bottom));
  max-width:min(62vw,380px);
  backdrop-filter:blur(8px);
}
#legend span{
  display:inline-flex;align-items:center;gap:var(--s2);
  font-size:var(--fs-sm);font-weight:600;color:var(--ink-2);
  padding:2px var(--s2);
}
#legend i{width:11px;height:11px;border-radius:50%;flex:0 0 auto;box-shadow:0 0 0 2px rgba(255,255,255,.9)}

/* ============================= EMPTY STATE =============================== */
#emptyState{position:absolute;inset:0;display:none;place-items:center;padding:var(--s6);text-align:center}
#emptyState.show{display:grid}
.empty-card{
  background:var(--card);border:1px dashed var(--card-line);border-radius:var(--r-lg);
  padding:var(--s7) var(--s6);max-width:440px;box-shadow:var(--shadow-2);
}
.empty-card h3{margin:0 0 var(--s2);font-size:var(--fs-lg)}
.empty-card p{margin:0 0 var(--s5);color:var(--ink-2);font-size:var(--fs-md);line-height:var(--lh)}

/* =============================== CONTROLS ================================
   Zoom cluster and a directional pad, both thumb-sized. They sit on the
   right so a right-handed operator holding a tablet reaches them without
   covering the machine. */
#controls{
  position:absolute;right:var(--s4);bottom:var(--s4);
  display:flex;flex-direction:column;gap:var(--s2);align-items:center;
  padding-bottom:env(safe-area-inset-bottom);
  z-index:8;
}
.ctl{
  width:52px;height:52px;border-radius:var(--r);
  border:1px solid var(--card-line);
  background:rgba(255,255,255,.97);color:var(--ink);
  box-shadow:var(--shadow-2);
  display:grid;place-items:center;
  font-size:var(--fs-lg);font-weight:700;
  backdrop-filter:blur(8px);
  transition:background var(--t-fast) var(--ease),transform var(--t-fast) var(--ease),border-color var(--t-fast) var(--ease);
}
.ctl:hover{background:#fff;border-color:#b9c7d8}
.ctl:active{transform:scale(.94)}
.ctl svg{width:22px;height:22px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}

.pad{display:grid;grid-template-columns:repeat(3,52px);grid-template-rows:repeat(3,52px);gap:var(--s1)}
.pad .ctl{border-radius:10px}
.pad .c-up{grid-area:1/2} .pad .c-left{grid-area:2/1} .pad .c-reset{grid-area:2/2} .pad .c-right{grid-area:2/3} .pad .c-down{grid-area:3/2}
.pad .c-reset{background:var(--bar);color:var(--on-dark);border-color:transparent}
.pad .c-reset:hover{background:var(--bar-2)}

.zoom-badge{
  background:rgba(17,26,43,.9);color:var(--on-dark);border:0;
  border-radius:var(--r-pill);padding:var(--s2) var(--s4);
  font-size:var(--fs-sm);font-weight:700;font-variant-numeric:tabular-nums;
  letter-spacing:.3px;cursor:pointer;min-height:var(--tap-sm);
  box-shadow:var(--shadow-2);backdrop-filter:blur(8px);
}
.zoom-badge:hover{background:rgba(17,26,43,1)}
.zoom-badge.is-1to1{background:var(--accent)}

/* ============================== TOAST / HINT ============================= */
#hint{
  position:absolute;left:50%;top:var(--s4);transform:translateX(-50%);
  background:rgba(17,26,43,.94);color:var(--on-dark);
  border-radius:var(--r-pill);padding:var(--s3) var(--s5);
  font-size:var(--fs-md);font-weight:600;
  box-shadow:var(--shadow-3);pointer-events:none;
  max-width:90%;text-align:center;
  opacity:0;transition:opacity .25s var(--ease);z-index:30;
  backdrop-filter:blur(8px);
}
#hint.show{opacity:1}
#hint.err{background:rgba(211,47,47,.96)}
#hint.ok{background:rgba(15,157,88,.96)}

/* ============================== RESPONSIVE ===============================
   Under 860px the bar can't hold everything in one row, so the two primary
   actions drop to a fixed bottom bar where a thumb already rests. */
/* A 1024-wide tablet keeps everything on one row — vertical space is worth
   more than the labels, so the labels go first. */
@media (max-width: 1200px){
  .brand .t2{display:none}
  .machine-pick label{display:none}
}

@media (max-width: 860px){
  .machine-pick{order:3;flex:1 1 100%;max-width:none}

  .bar-actions{
    position:fixed;left:0;right:0;bottom:0;z-index:25;
    background:var(--bar);border-top:1px solid var(--line);
    padding:var(--s2) var(--s3);
    padding-bottom:calc(var(--s2) + env(safe-area-inset-bottom));
    gap:var(--s2);
    box-shadow:0 -4px 16px rgba(0,0,0,.28);
  }
  .bar-actions .btn{flex:1 1 auto}
  .bar-actions .btn.primary{flex:2 1 auto}
  #btnSettings{flex:0 0 var(--tap)}

  /* The stage gives up the bar's height rather than being covered by it,
     so the photo, the controls and the pin form all stay fully reachable
     and the viewer's own maths sees the real visible area. */
  #stage{margin-bottom:calc(var(--tap-lg) + var(--s4) + env(safe-area-inset-bottom))}
  #legend{max-width:min(70vw,300px)}
}

@media (max-width: 560px){
  .brand .t1{display:none}
  .ctl{width:var(--tap);height:var(--tap)}
  .pad{grid-template-columns:repeat(3,var(--tap));grid-template-rows:repeat(3,var(--tap))}
  #legend span{font-size:var(--fs-xs)}
}

/* A short viewport (tablet in landscape) needs the pad out of the way. */
@media (max-height: 520px){
  .pad .c-up,.pad .c-down,.pad .c-left,.pad .c-right{display:none}
  .pad{grid-template-columns:52px;grid-template-rows:52px}
  .pad .c-reset{grid-area:1/1}
}

/* ===== callout.css ======================================================= */
/* callout.css
   The pin form, anchored to the pin it belongs to, plus the form controls
   (buttons, inputs, combobox, action radios, duration) that the modals reuse.

   The callout sits above #hint (z 30) so a toast never covers its header.
   ---------------------------------------------------------------- */

/* ========================= CALLOUT SHELL ================================= */
#callout{
  position:absolute;z-index:40;
  width:360px;max-width:calc(100% - var(--s5));
  background:var(--card);border:1px solid var(--card-line);
  border-radius:var(--r-lg);
  box-shadow:var(--shadow-3);
  display:flex;flex-direction:column;
  max-height:calc(100% - var(--s5));
  animation:coIn .16s var(--ease);
  --c:var(--unset);
}
#callout[hidden]{display:none}
@keyframes coIn{from{opacity:0;transform:translateY(6px) scale(.985)}to{opacity:1;transform:none}}

.co-arrow{
  position:absolute;width:14px;height:14px;background:var(--card);
  border-left:1px solid var(--card-line);border-top:1px solid var(--card-line);
  transform:translateX(-50%) rotate(45deg);
}
#callout[data-dir="down"] .co-arrow{top:-8px}
#callout[data-dir="up"] .co-arrow{bottom:-8px;top:auto;transform:translateX(-50%) rotate(225deg)}
#callout[data-dir="right"] .co-arrow{left:-8px;transform:translateY(-50%) rotate(-45deg)}
#callout[data-dir="left"] .co-arrow{right:-8px;left:auto;transform:translateY(-50%) rotate(135deg)}
#callout[data-dir="none"] .co-arrow{display:none}

/* The 3px top edge carries the action colour — the fastest way to see
   which category a pin belongs to while the form is open. */
.co-head{
  display:flex;align-items:center;gap:var(--s3);
  padding:var(--s3) var(--s4);flex:0 0 auto;
  border-bottom:1px solid var(--card-line);
  border-top:3px solid var(--c);
  border-radius:var(--r-lg) var(--r-lg) 0 0;
  transition:border-color .16s ease;
}
.co-badge{
  width:34px;height:34px;border-radius:10px;background:var(--c);color:#fff;
  display:grid;place-items:center;font-weight:800;font-size:var(--fs-md);
  flex:0 0 auto;font-variant-numeric:tabular-nums;transition:background .16s ease;
}
.co-title{font-size:var(--fs-lg);font-weight:700;line-height:var(--lh-tight)}
.co-sub{
  font-size:var(--fs-xs);color:var(--ink-3);line-height:1.35;margin-top:2px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.co-body{padding:var(--s4);overflow:auto;flex:1 1 auto;-webkit-overflow-scrolling:touch}
.co-foot{
  padding:var(--s3) var(--s4);border-top:1px solid var(--card-line);
  display:flex;gap:var(--s2);align-items:center;flex:0 0 auto;
  background:var(--card-2);border-radius:0 0 var(--r-lg) var(--r-lg);
}

/* ============================== BUTTONS ================================== */
.x{
  width:var(--tap-sm);height:var(--tap-sm);border-radius:10px;
  border:1px solid transparent;background:transparent;color:var(--ink-2);
  font-size:22px;line-height:1;flex:0 0 auto;
  transition:background var(--t-fast) var(--ease);
}
.x:hover{background:#f1f5f9;color:var(--ink)}

.btn2{
  height:var(--tap);padding:0 var(--s4);border-radius:var(--r);
  border:1px solid var(--card-line);background:#fff;color:var(--ink);
  font-weight:600;font-size:var(--fs-md);
  display:inline-flex;align-items:center;justify-content:center;gap:var(--s2);
  transition:background var(--t-fast) var(--ease),border-color var(--t-fast) var(--ease),transform var(--t-fast) var(--ease);
}
.btn2:hover{background:var(--card-2);border-color:#c3d0e0}
.btn2:active{transform:translateY(1px)}
.btn2.primary{background:var(--accent);border-color:transparent;color:#fff;box-shadow:0 2px 8px rgba(29,111,242,.28)}
.btn2.primary:hover{background:#155fd4}
.btn2.danger{color:var(--danger);border-color:#f2c7c7}
.btn2.danger:hover{background:var(--danger-soft)}
.btn2.grow{flex:1 1 auto}
.btn2.sm{height:var(--tap-sm);padding:0 var(--s3);font-size:var(--fs-sm)}
.btn2:disabled{opacity:.5;cursor:not-allowed;transform:none;box-shadow:none}

/* =============================== FIELDS ================================== */
.field{margin-bottom:var(--s4)}
.field > label{
  display:block;font-size:var(--fs-sm);font-weight:700;
  margin-bottom:var(--s2);color:var(--ink);
}
.field .help{
  font-size:var(--fs-xs);color:var(--ink-3);font-weight:500;
  margin-top:var(--s2);line-height:var(--lh);
}
.req{color:var(--danger)}
.pill{
  display:inline-block;background:#eef2f7;color:var(--ink-2);
  border-radius:var(--r-pill);padding:2px var(--s2);
  font-size:11px;font-weight:700;margin-left:var(--s1);vertical-align:1px;
}

.input,textarea.input{
  width:100%;height:var(--tap);border-radius:var(--r);
  border:1px solid var(--card-line);padding:0 var(--s3);
  background:#fff;color:var(--ink);font-size:var(--fs-md);
  transition:border-color var(--t-fast) var(--ease),box-shadow var(--t-fast) var(--ease);
}
.input:focus{border-color:var(--accent);box-shadow:var(--ring);outline:none}
textarea.input{height:auto;min-height:64px;padding:var(--s3);line-height:var(--lh);resize:vertical}
.input::placeholder{color:#9fb0c4}
.input[aria-invalid="true"]{border-color:var(--danger);background:#fff8f8}
.err-msg{color:var(--danger);font-size:var(--fs-sm);margin-top:var(--s2);display:none;font-weight:600}
.err-msg.show{display:block}

/* ============================== AVATARS ==================================
   A face beside every operator name. The initials sit in the box and a
   photo, when there is one, covers them — so a slow or missing image
   degrades to something readable instead of a broken-image icon. */
.avatar{
  position:relative;flex:0 0 auto;
  display:inline-grid;place-items:center;
  border-radius:50%;overflow:hidden;
  color:#fff;font-weight:700;line-height:1;
  user-select:none;
  box-shadow:0 0 0 2px #fff, 0 0 0 3px rgba(15,23,42,.08);
}
.avatar img{
  position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;border-radius:50%;
}
.av-sm{width:28px;height:28px;font-size:11px}
.av-md{width:36px;height:36px;font-size:13px}
.av-lg{width:44px;height:44px;font-size:var(--fs-md)}

/* the name field, with the chosen person's face beside it */
.name-row{display:flex;gap:var(--s3);align-items:flex-start}
.name-row .combo{flex:1 1 auto;min-width:0}
.name-avatar{flex:0 0 auto;padding-top:2px}
.name-avatar[hidden]{display:none}

/* ---- combobox: the list expands inline so it can never be clipped ------- */
.combo{position:relative}
.combo-list{
  display:none;margin:var(--s2) 0 0;padding:var(--s1);list-style:none;
  background:#fff;border:1px solid var(--card-line);border-radius:var(--r);
  max-height:220px;overflow:auto;box-shadow:var(--shadow-1);
}
.combo-list.show{display:block}
.combo-list li{
  padding:var(--s3);border-radius:var(--r-sm);cursor:pointer;
  font-size:var(--fs-md);line-height:var(--lh-tight);min-height:var(--tap);
  display:flex;align-items:center;
}
.combo-list li .who{display:flex;flex-direction:column;min-width:0;margin-left:var(--s3);gap:1px}
.combo-list li .who .nm{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.combo-list li .code{color:var(--ink-3);font-size:var(--fs-sm);margin-left:0}
.combo-list li[aria-selected="true"],.combo-list li:hover{background:var(--accent-soft)}
.combo-list li.none{color:var(--ink-3);cursor:default;font-size:var(--fs-sm)}
.combo-list li.none:hover{background:transparent}

/* ========================== ACTION RADIOS ================================
   One pin carries exactly one action, so these are radios, and each one
   shows its colour as a swatch — the same colour the pin will take. */
.actions{display:grid;gap:var(--s2)}
.act{
  display:flex;align-items:center;gap:var(--s3);
  border:2px solid var(--card-line);border-radius:var(--r);
  padding:var(--s2) var(--s3);cursor:pointer;background:#fff;
  min-height:var(--tap-lg);
  transition:border-color .13s var(--ease),background .13s var(--ease);
}
.act input{width:22px;height:22px;flex:0 0 auto;margin:0;accent-color:var(--ac)}
.act .swatch{
  width:16px;height:16px;border-radius:50%;flex:0 0 auto;background:var(--ac);
  box-shadow:0 0 0 2px #fff,0 0 0 3px rgba(15,23,42,.1);
}
.act .txt{font-size:var(--fs-md);font-weight:600;line-height:var(--lh-tight)}
.act .txt small{display:block;font-weight:500;color:var(--ink-3);font-size:var(--fs-xs);margin-top:2px}
.act[data-k="cleaning"]{--ac:var(--clean);--soft:var(--clean-soft)}
.act[data-k="inspection"]{--ac:var(--inspect);--soft:var(--inspect-soft)}
.act[data-k="lubrication"]{--ac:var(--lube);--soft:var(--lube-soft)}
.act.on{border-color:var(--ac);background:var(--soft)}
.act:hover{border-color:var(--ac)}

/* ============ DURATION (appears once a category is chosen) ===============
   Tinted with the chosen action colour so it reads as part of that choice. */
#durField{
  border:2px solid var(--c);border-radius:var(--r);
  padding:var(--s3);
  background:color-mix(in srgb, var(--c) 6%, #fff);
  transition:border-color .16s ease;
}
#durField[hidden]{display:none}
#durField > label{margin-bottom:var(--s2)}
.dur-row{display:flex;gap:var(--s2);align-items:center;flex-wrap:wrap}
.chips{display:flex;gap:var(--s2);flex-wrap:wrap;flex:1 1 auto}
.chip{
  height:44px;min-width:52px;padding:0 var(--s3);border-radius:10px;
  border:2px solid var(--card-line);background:#fff;
  font-size:var(--fs-md);font-weight:700;color:var(--ink-2);
  font-variant-numeric:tabular-nums;
  transition:background var(--t-fast) var(--ease),border-color var(--t-fast) var(--ease),color var(--t-fast) var(--ease);
}
.chip:hover{border-color:var(--c);color:var(--ink)}
.chip.on{background:var(--c);border-color:var(--c);color:#fff}
.dur-input{display:flex;align-items:center;gap:var(--s2);flex:0 0 auto}
.dur-input .input{width:92px;height:44px;text-align:center;font-weight:700;padding:0 var(--s2)}
.dur-input .unit{font-size:var(--fs-sm);color:var(--ink-3);font-weight:700;white-space:nowrap}
.dur-sum{font-size:var(--fs-sm);font-weight:700;color:var(--c)}

/* duration badge in the summary table */
.durtag{
  display:inline-flex;align-items:center;gap:var(--s1);margin-left:var(--s2);
  border-radius:var(--r-sm);padding:2px var(--s2);
  font-size:var(--fs-xs);font-weight:700;background:#f1f5f9;color:var(--ink-2);
  font-variant-numeric:tabular-nums;white-space:nowrap;
}

/* On a phone the callout spans the width and docks to the bottom, which is
   easier to fill in one-handed than a floating box. */
@media (max-width: 560px){
  #callout{width:calc(100% - var(--s4))}
  .act .txt small{font-size:11px}
}

/* ===== modals.css ======================================================== */
/* modals.css
   Overlays: saved-entries list, settings, confirm dialog, summary table.

   Layout breakpoints live in layout.css. This file only adjusts what is
   specific to the sheets and the table inside them.
   ---------------------------------------------------------------- */

/* ============================== OVERLAY ================================== */
.overlay{
  position:fixed;inset:0;
  background:rgba(10,17,32,.58);backdrop-filter:blur(3px);
  display:none;align-items:center;justify-content:center;
  padding:var(--s4);z-index:50;
}
.overlay.show{display:flex}

.sheet{
  background:var(--card);border-radius:var(--r-lg);
  box-shadow:var(--shadow-3);
  width:100%;max-width:480px;
  max-height:min(92vh,780px);
  display:flex;flex-direction:column;overflow:hidden;
  animation:pop .16s var(--ease);
}
.sheet.wide{max-width:960px}
@keyframes pop{from{transform:translateY(10px) scale(.99);opacity:0}to{transform:none;opacity:1}}

.sheet header{
  display:flex;align-items:center;gap:var(--s3);
  padding:var(--s4) var(--s5);
  border-bottom:1px solid var(--card-line);flex:0 0 auto;
}
.sheet header h2{margin:0;font-size:var(--fs-xl);flex:1 1 auto}
.sheet header .sub{
  font-size:var(--fs-sm);color:var(--ink-3);font-weight:500;
  display:block;margin-top:2px;line-height:var(--lh-tight);
}
.sheet .body{padding:var(--s5);overflow:auto;flex:1 1 auto;-webkit-overflow-scrolling:touch}
.sheet footer{
  padding:var(--s4) var(--s5);border-top:1px solid var(--card-line);
  display:flex;gap:var(--s2);flex:0 0 auto;background:var(--card-2);
  padding-bottom:calc(var(--s4) + env(safe-area-inset-bottom));
}

/* ============================ SUMMARY TABLE ============================== */
.tbl{width:100%;border-collapse:collapse;font-size:var(--fs-md)}
.tbl th,.tbl td{
  padding:var(--s3);border-bottom:1px solid var(--card-line-2);
  text-align:left;vertical-align:top;
}
.tbl th{
  font-size:var(--fs-xs);color:var(--ink-3);
  text-transform:uppercase;letter-spacing:.5px;font-weight:700;
  position:sticky;top:0;background:#fff;z-index:1;
  border-bottom-color:var(--card-line);
}
.tbl td.n{font-variant-numeric:tabular-nums;white-space:nowrap}

/* operator cell: face, name, employee code */
.person{display:flex;align-items:center;gap:var(--s2);min-width:0}
.person .who{min-width:0}
.person .nm{font-weight:600;overflow:hidden;text-overflow:ellipsis}
.person .code{font-size:var(--fs-xs);color:var(--ink-3);font-variant-numeric:tabular-nums}
.tbl tbody tr:hover{background:var(--card-2)}

.tag{
  display:inline-flex;align-items:center;gap:var(--s1);
  border-radius:var(--r-sm);padding:4px var(--s2);
  font-size:var(--fs-xs);font-weight:700;border:1px solid;white-space:nowrap;
}
.tag i{width:8px;height:8px;border-radius:50%;background:currentColor;opacity:.9}
.tag.cleaning{background:var(--clean-soft);color:var(--clean-ink);border-color:#bfe3cb}
.tag.inspection{background:var(--inspect-soft);color:var(--inspect-ink);border-color:#c7daff}
.tag.lubrication{background:var(--lube-soft);color:var(--lube-ink);border-color:#ecd9a5}

.grp{background:var(--card-2);font-weight:700;font-size:var(--fs-md)}
.grp .gcount{display:inline-flex;gap:var(--s3);margin-left:var(--s3);font-weight:600;font-size:var(--fs-xs);vertical-align:1px}
.grp .gcount span{display:inline-flex;align-items:center;gap:var(--s1);color:var(--ink-2)}
.grp .gcount i{width:8px;height:8px;border-radius:50%}

.empty-row{color:var(--ink-3);text-align:center;padding:var(--s7) var(--s3);font-size:var(--fs-md)}

.mini{
  height:var(--tap-sm);padding:0 var(--s3);border-radius:var(--r-sm);
  font-size:var(--fs-sm);font-weight:600;
  border:1px solid var(--card-line);background:#fff;
  transition:background var(--t-fast) var(--ease);
}
.mini:hover{background:var(--card-2)}
.mini.danger{color:var(--danger);border-color:#f2c7c7}
.mini.danger:hover{background:var(--danger-soft)}

/* ============================== STAT TILES =============================== */
.stat{display:flex;gap:var(--s3);flex-wrap:wrap;margin-bottom:var(--s5)}
.stat > div{
  flex:1 1 110px;border:1px solid var(--card-line);border-radius:var(--r);
  padding:var(--s3) var(--s4);background:#fbfdff;
  border-left:4px solid var(--card-line);
}
.stat > div.c-clean{border-left-color:var(--clean)}
.stat > div.c-insp{border-left-color:var(--inspect)}
.stat > div.c-lube{border-left-color:var(--lube)}
.stat b{display:block;font-size:var(--fs-2xl);line-height:1.15;font-variant-numeric:tabular-nums}
.stat span{font-size:var(--fs-xs);color:var(--ink-3)}

/* ================================ NOTES ================================== */
.note{
  border-radius:var(--r);padding:var(--s3) var(--s4);
  font-size:var(--fs-sm);line-height:var(--lh);
  border:1px solid;margin-bottom:var(--s4);
}
.note.info{background:#f2f8ff;border-color:#cfe2ff;color:#0b4a8f}
.note.warn{background:#fff8ec;border-color:#f6dfb5;color:#7a4c00}
.note.bad{background:var(--danger-soft);border-color:#f5cfcf;color:#8d1f1f}
.note code{background:rgba(0,0,0,.06);padding:2px var(--s1);border-radius:5px;font-size:var(--fs-xs);word-break:break-all}

.row{display:flex;gap:var(--s3)}
.row > *{flex:1 1 0;min-width:0}
hr.sep{border:0;border-top:1px solid var(--card-line);margin:var(--s6) 0}

/* ============================== RESPONSIVE =============================== */
@media (max-width: 860px){
  .sheet{max-width:100%}
  .sheet header{padding:var(--s3) var(--s4)}
  .sheet header h2{font-size:var(--fs-lg)}
  .sheet .body{padding:var(--s4)}
  .sheet footer{padding:var(--s3) var(--s4)}
  .tbl th,.tbl td{padding:var(--s2);font-size:var(--fs-sm)}
  .stat b{font-size:var(--fs-xl)}
}
@media (max-width: 560px){
  .overlay{padding:var(--s2)}
  .sheet{max-height:94vh}
  .row{flex-direction:column}
}

@media print{
  #controls,#topbar,#legend,.bar-actions{display:none}
}
