/* patrol-router — phase 2 UI.
   Design tokens copied verbatim from specs/mockup-full-flow.html <style>.
   That mockup is the approved design; do not redesign it here. */

:root{
  --ground:#F4F6F9; --surface:#fff; --sunk:#EDF0F4; --line:#D1D5DB;
  --ink:#1A2B4A; --body:#333; --soft:#5A6473; --faint:#8C95A3;
  --navy:#1A2B4A; --accent:#2563C9; --accent-strong:#1D4FA8; --accent-wash:#E4EDFB;
  --ok:#1E8E5A; --warn:#C77700; --crit:#C0102E;
  --t1:#2563C9; --t2:#1E8E5A; --t3:#C77700;
  --mono:'IBM Plex Mono',ui-monospace,Menlo,monospace;
  --sans:'Inter Tight','Inter',system-ui,-apple-system,'Segoe UI',sans-serif;
  --r:7px;
}
*{box-sizing:border-box}
body{margin:0;background:#E7EBF0;font-family:var(--sans);color:var(--body);font-size:13.5px}
.mono{font-family:var(--mono);font-variant-numeric:tabular-nums}
.micro{font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--soft);font-weight:700}
.page{max-width:1180px;margin:0 auto;padding:24px 20px 60px}

/* the app frame */
.app{border:1px solid #C3CBD4;border-radius:9px;overflow:hidden;
     box-shadow:0 2px 7px rgba(26,43,74,.11);background:var(--ground)}
.topbar{background:var(--navy);padding:9px 18px;display:flex;align-items:center;gap:20px}
.mark{font-weight:800;letter-spacing:.03em;font-size:14px;color:#fff}
.mark .b{color:var(--accent)}
.topbar .sp{flex:1}
.topbar .who{font-size:11px;color:rgba(255,255,255,.6)}
.body{padding:18px}

.card{background:var(--surface);border:1px solid var(--line);border-radius:var(--r)}
.pad{padding:16px}
.btn{border:1px solid var(--accent);background:var(--accent);color:#fff;padding:9px 17px;
     border-radius:var(--r);font-family:var(--sans);font-size:13.5px;font-weight:600;cursor:pointer}
.btn.ghost{background:transparent;color:var(--accent)}
.btn.grey{background:transparent;border-color:var(--line);color:var(--soft)}
.btn:disabled{opacity:.45;cursor:not-allowed}
.chip{display:inline-flex;align-items:center;gap:5px;font-size:11.5px;font-weight:600;
      border:1px solid var(--line);border-radius:20px;padding:2px 10px;background:var(--sunk)}
.chip.ok{color:var(--ok);background:#E7F4EC;border-color:#BFE4CF}
.chip.warn{color:var(--warn);background:#FBF0DE;border-color:#F0D9AE}
.chip.crit{color:var(--crit);background:#FBE7E9;border-color:#F2C2C8}

/* drop zone */
.drop{border:2px dashed #B6C2CE;border-radius:10px;background:var(--surface);
      padding:38px 20px;text-align:center}
.drop[hidden]{display:none}
.drop.over{border-color:var(--accent);background:var(--accent-wash)}
.drop .ic{font-size:30px;color:#AAB6C2;line-height:1}
.drop h3{font-size:16px;color:var(--navy);margin:9px 0 3px}
.drop p{font-size:12.5px;color:var(--soft);margin:0 0 14px}
/* screen 1 progress card — replaces the drop zone during an upload.
   Padded to stand at the same height so swapping the two does not shift the
   page. Same tokens as the screen 2 card it hands over to. */
.progress{border:1px solid var(--line);border-radius:10px;background:var(--surface);
          padding:22px 20px;display:flex;flex-direction:column;justify-content:center;
          /* the drop zone's measured height (205.5px incl. its 2px dashed border),
             so swapping the two never shifts the page */
          min-height:205px}
.progress[hidden]{display:none}
.phd{display:flex;align-items:baseline;gap:10px;margin-bottom:9px}
.phd .mono{margin-left:auto;font-size:12px;color:var(--soft)}
.pnow{display:flex;align-items:center;gap:8px;margin-top:14px;
      font-size:12.5px;color:var(--soft);min-height:17px}
.pnow .spin{flex:none}
/* the drop zone while an upload is running: visibly out of action, not just
   inert. A second file dropped mid-flight would race the first. */
.drop.busy{opacity:.45;pointer-events:none;filter:grayscale(.5)}

.cols{display:grid;grid-template-columns:1fr 1fr;gap:14px}
.fmt{font-size:12px;color:var(--soft);line-height:1.75}
.fmt code{background:var(--sunk);padding:1px 5px;border-radius:3px;
          font-family:var(--mono);font-size:11px;color:var(--ink)}

table.t{width:100%;border-collapse:collapse;font-size:12.5px;background:var(--surface)}
table.t th{text-align:left;font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;
           color:var(--soft);font-weight:700;padding:7px 10px;border-bottom:1px solid var(--line);
           background:var(--sunk)}
table.t td{padding:7px 10px;border-bottom:1px solid #EDF0F4;vertical-align:middle}
tr.amb{background:#FDF7EC}
tr.bad{background:#FBE7E9}

.bar{height:7px;background:var(--sunk);border-radius:4px;overflow:hidden}
.bar i{display:block;height:100%;background:var(--accent);transition:width .25s ease}
/* Screen 4, stage 3 (the OneMap fetch): nothing observable advances for ~13 s,
   which read as a hang on a phone. While that stage is live the fill eases
   50%→85% over the expected window instead of freezing at 63%. Motion only —
   no fabricated percentage; the live elapsed-seconds counter in the stage meta
   carries the honest signal. Same keyframe-driven spirit as .spin below. */
.bar i.sweep{transition:width 13s linear}
.stat{display:flex;gap:22px;margin:12px 0 0}
.stat .n{font-family:var(--mono);font-size:21px;font-weight:700;color:var(--ink);line-height:1.1}
.stat .n.ok{color:var(--ok)} .stat .n.warn{color:var(--warn)} .stat .n.crit{color:var(--crit)}

.set{display:grid;grid-template-columns:repeat(4,1fr);gap:13px}
.field label{display:block;font-size:11px;letter-spacing:.05em;text-transform:uppercase;
             color:var(--soft);font-weight:700;margin-bottom:4px}
.inp{border:1px solid var(--line);border-radius:6px;padding:7px 10px;background:var(--surface);
     font-family:var(--mono);font-size:14px;color:var(--ink);width:100%}
.capline{background:var(--accent-wash);border:1px solid #C7D9F5;border-radius:var(--r);
         padding:11px 15px;margin-top:14px;font-size:13px;color:#22314d}
.capline b{color:var(--accent-strong)}

.solve{display:flex;flex-direction:column;gap:9px}
.sline{display:flex;align-items:center;gap:10px;font-size:13px}
.sline .tick{width:19px;height:19px;border-radius:50%;display:inline-flex;align-items:center;
             justify-content:center;font-size:11px;color:#fff;flex:0 0 19px;background:var(--ok)}
.sline .tick.run{background:var(--accent)}
.sline .tick.wait{background:#C6CDD6}
.sline .meta{margin-left:auto;font-family:var(--mono);font-size:11.5px;color:var(--soft)}
.sline .dim{color:var(--faint)}

.week{display:grid;grid-template-columns:repeat(5,1fr);gap:10px}
.wday{border:1px solid var(--line);border-radius:var(--r);background:var(--surface);overflow:hidden}
.wday .h{background:var(--sunk);padding:6px 10px;font-size:12px;font-weight:700;color:var(--navy);
         border-bottom:1px solid var(--line);display:flex;justify-content:space-between}
.wday .h .c{font-family:var(--mono);color:var(--soft);font-weight:600}
.wday .b{padding:8px 10px}
.trow{display:flex;align-items:center;gap:6px;padding:2.5px 0;font-size:11.5px}
.dot{width:8px;height:8px;border-radius:50%;flex:0 0 8px}
.trow .n{margin-left:auto;font-family:var(--mono);color:var(--soft)}
.wday.empty .b{color:var(--faint);font-size:11.5px;text-align:center;padding:18px 10px}
.wday.clickable{cursor:pointer}
.wday.clickable:hover{border-color:var(--accent)}

/* results screen bits */
.cov{display:flex;align-items:center;gap:9px;background:#E7F4EC;border:1px solid #BFE4CF;
     border-radius:var(--r);padding:8px 14px}
.cov .n{font-family:var(--mono);font-size:19px;font-weight:700;color:var(--ok)}
.cov.warn{background:#FBF0DE;border-color:#F0D9AE}
.cov.warn .n{color:var(--warn)}
.days{display:flex;gap:5px}
.day{border:1px solid var(--line);background:var(--surface);border-radius:6px;padding:5px 12px;
     font-size:12px;font-weight:600;color:var(--soft);text-align:center;line-height:1.25;cursor:pointer}
.day .d2{font-size:9.5px;color:var(--faint)}
.day.on{background:var(--navy);border-color:var(--navy);color:#fff}
.day.on .d2{color:rgba(255,255,255,.65)}

.map{height:330px;position:relative;background:#EAF0F4;border-radius:6px;overflow:hidden;z-index:0}
.attrib{position:absolute;right:8px;bottom:8px;font-size:9px;color:#7B8894;
        background:rgba(255,255,255,.88);padding:2px 6px;border-radius:3px;z-index:500;
        max-width:70%;line-height:1.35}
/* Leaflet's own attribution control is suppressed — we render the mandated
   OneMap string ourselves so it is always visible and never collapsed. */
.leaflet-control-attribution{display:none}
.pinmark{display:flex;align-items:center;justify-content:center;width:21px;height:21px;
         border-radius:50%;color:#fff;font-family:var(--mono);font-size:10px;font-weight:700;
         border:2px solid #fff;box-shadow:0 1px 3px rgba(0,0,0,.3)}
.pinmark.t1{background:var(--t1)} .pinmark.t2{background:var(--t2)} .pinmark.t3{background:var(--t3)}
.pinmark.t4{background:#9BB6E0} .pinmark.t5{background:#93CDB0} .pinmark.t6{background:#E3C48A}

.team{border:1px solid var(--line);border-radius:var(--r);margin-bottom:9px;overflow:hidden}
.team .th{padding:6px 11px;display:flex;align-items:center;gap:8px;font-size:12px;
          font-weight:700;color:#fff}
.team.t1 .th{background:var(--t1)} .team.t2 .th{background:var(--t2)} .team.t3 .th{background:var(--t3)}
.team.t4 .th{background:#9BB6E0} .team.t5 .th{background:#93CDB0} .team.t6 .th{background:#E3C48A}
.team .th .sp{flex:1;font-weight:500;font-size:10.5px;opacity:.9}
.stop{padding:7px 11px;border-bottom:1px solid #EDF0F4}
.stop:last-child{border-bottom:none}
.stop .l1{display:flex;align-items:baseline;gap:7px}
.stop .idx{font-family:var(--mono);font-size:10px;font-weight:700;color:#fff;background:var(--soft);
           width:16px;height:16px;border-radius:50%;display:inline-flex;align-items:center;
           justify-content:center;flex:0 0 16px}
.stop.t1 .idx{background:var(--t1)} .stop.t2 .idx{background:var(--t2)} .stop.t3 .idx{background:var(--t3)}
.stop.t4 .idx{background:#9BB6E0} .stop.t5 .idx{background:#93CDB0} .stop.t6 .idx{background:#E3C48A}
.stop .nm{font-weight:600;color:var(--ink);font-size:12px}
.stop .win{margin-left:auto;font-family:var(--mono);font-size:10.5px;color:var(--soft)}
.stop .times{display:flex;gap:11px;margin:4px 0 0 23px;font-family:var(--mono);font-size:11px}
.stop .times b{color:var(--ink)}
.ontime{color:var(--ok);font-weight:700;font-size:10px}
.leg{margin:5px 0 0 23px;padding:4px 8px;background:var(--sunk);border-radius:5px;font-size:10.5px;
     display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.leg.taxileg{background:#FDF7EC;border:1px solid #F0D9AE}
.modebit{display:inline-flex;align-items:center;gap:4px;font-weight:600}
.bus{background:#1E8E5A;color:#fff;padding:0 5px;border-radius:3px;font-family:var(--mono);font-size:9.5px}
.mrt{background:#C0102E;color:#fff;padding:0 5px;border-radius:3px;font-family:var(--mono);font-size:9.5px}
.taxi{background:#C77700;color:#fff;padding:0 5px;border-radius:3px;font-family:var(--mono);font-size:9.5px}
.walk{color:var(--soft)}
.leg .far{margin-left:auto;color:var(--soft);font-family:var(--mono)}
.leg .why{color:#6b5327}
/* Rule 1: geometry missing => draw nothing and say so. */
.leg .nogeo{color:var(--soft);font-style:italic}

.amber{border:1px solid #F0D9AE;background:#FDF7EC;border-radius:var(--r);padding:10px 13px}
.amber .t{font-weight:700;color:var(--warn);font-size:12.5px;margin-bottom:4px}
.amber .r{font-size:11.5px;color:#6b5327;padding:2px 0}
.crit-box{border:1px solid #F2C2C8;background:#FBE7E9;border-radius:var(--r);padding:10px 13px}
.crit-box .t{font-weight:700;color:var(--crit);font-size:12.5px;margin-bottom:4px}
.crit-box .r{font-size:11.5px;color:#7d2130;padding:2px 0}
.basis{font-size:11px;color:var(--soft);background:var(--sunk);border-radius:5px;
       padding:7px 11px;margin-top:10px}
.foot{font-size:11px;color:var(--faint);margin-top:22px;line-height:1.6;
      border-top:1px solid #D3DAE2;padding-top:12px}

/* screen switching */
.screen{display:none}
.screen.on{display:block}

/* ambiguity resolver */
.choices{margin:6px 0 0 0;display:flex;flex-direction:column;gap:4px}
.choice{display:flex;align-items:center;gap:8px;font-size:11.5px;padding:4px 7px;
        background:var(--surface);border:1px solid var(--line);border-radius:5px;cursor:pointer}
.choice:hover{border-color:var(--accent)}
.choice.picked{border-color:var(--accent);background:var(--accent-wash)}
.choice .ad{color:var(--soft)}
.choice .pc{margin-left:auto;font-family:var(--mono);color:var(--soft)}
.rowfix{padding:9px 11px;border-bottom:1px solid #EDF0F4}
.rowfix:last-child{border-bottom:none}
.rowfix .hd{display:flex;align-items:baseline;gap:8px;font-size:12px}
.rowfix .hd b{color:var(--ink)}

.err{background:#FBE7E9;border:1px solid #F2C2C8;color:#7d2130;border-radius:var(--r);
     padding:10px 13px;font-size:12.5px;margin-top:12px}
.spin{display:inline-block;width:13px;height:13px;border:2px solid var(--accent-wash);
      border-top-color:var(--accent);border-radius:50%;animation:sp .7s linear infinite;
      vertical-align:-2px}
@keyframes sp{to{transform:rotate(360deg)}}
.legendrow{display:flex;gap:16px;margin-top:9px;font-size:11.5px;color:var(--soft);flex-wrap:wrap}

/* ---- mobile (≤760px). The operator reads on a phone.
   Every desktop rule above is untouched; this block only overrides what
   breaks at 390px. !important appears only where an inline style in
   index.html would otherwise win (helper classes carry no desktop rules,
   so the desktop look is unchanged). */
@media (max-width: 760px){
  .page{padding:12px 12px 40px}
  .body{padding:12px}
  .topbar{flex-wrap:wrap;gap:6px 14px;padding:9px 12px}

  /* multi-column layouts collapse to one column */
  .cols{grid-template-columns:1fr}
  .set{grid-template-columns:1fr}
  .week{grid-template-columns:1fr}
  .daygrid{grid-template-columns:1fr!important}   /* map first, schedule second */

  /* side-by-side buttons stack full-width */
  .btnrow{flex-direction:column!important;align-items:stretch!important}
  .btnrow>a{display:block}
  .btnrow .btn{width:100%}

  /* chip rows and the week header wrap instead of overflowing */
  .days{flex-wrap:wrap}
  .dayrow{flex-wrap:wrap}
  .weekhead{flex-wrap:wrap}
  .stat{gap:14px;flex-wrap:wrap}

  /* the check table scrolls inside its card — columns kept, not deleted */
  .tcard{overflow-x:auto!important;-webkit-overflow-scrolling:touch}
  .tcard table.t{min-width:560px}
  table.t{font-size:12px}
  table.t th{padding:6px 8px}
  table.t td{padding:6px 8px}

  /* long stop lines and match choices wrap instead of clipping */
  .stop .l1{flex-wrap:wrap}
  .stop .times{flex-wrap:wrap}
  .choice{flex-wrap:wrap}
}
