:root{
  --green:#76b841; --green-d:#478b34; --green-100:#eaf3de;
  --teal:#10301b; --teal-2:#1a4a2a; --teal-soft:#3f6b4d;
  --ash:#aebcae; --bg:#f3f5f4; --card:#fff; --line:#e3e7e5;
  --ink:#0f1a1c; --muted:#5b6a6c;
  --amber:#e0a72e; --amber-d:#a9781a; --red:#dc2626;
}
*{box-sizing:border-box}
body{margin:0;font-family:Nunito,"Segoe UI",system-ui,sans-serif;background:var(--bg);color:var(--ink)}
h1,h2,h3,.brand-name,.card-h,.kpi-n,.portal-name,.status-now,.login-card h1,.portal-main h1{
  font-family:Montserrat,"Segoe UI",system-ui,sans-serif}
h1{font-size:20px;font-weight:700;margin:0}
.muted{color:var(--muted)} .small{font-size:12px}

/* ---------- login ---------- */
.login-wrap{min-height:100vh;display:grid;place-items:center;
  background:radial-gradient(1100px 560px at 72% -10%, var(--green,#76b841) 0, #0e1a14 70%)}
.login-card{background:#fff;width:340px;padding:28px;border-radius:16px;
  box-shadow:0 20px 60px rgba(0,30,34,.35)}
.login-card h1{margin:14px 0 4px} .login-card .muted{margin:0 0 16px;font-size:14px}
.login-card label{display:block;font-size:13px;font-weight:500;margin-bottom:6px}
.login-card input{width:100%;padding:11px 12px;border:1px solid var(--line);
  border-radius:10px;font-size:14px;margin-bottom:16px;font-family:inherit}
.login-card button{width:100%;padding:11px;border:0;border-radius:10px;
  background:var(--green);color:#fff;font-weight:600;font-size:14px;cursor:pointer;font-family:inherit}
.login-card button:hover{background:var(--green-d)}
.login-stack{display:flex;flex-direction:column;align-items:center;gap:22px}
.login-foot{display:flex;flex-direction:column;align-items:center;gap:8px;opacity:.92}
.login-foot img{height:26px;width:auto}
.login-foot span{color:#dcebd0;font-size:12px;letter-spacing:.3px}
.alert{background:#fef2f2;color:#b91c1c;border:1px solid #fecaca;
  padding:9px 11px;border-radius:9px;font-size:13px;margin-bottom:14px}

/* ---------- brand ---------- */
.brand{display:flex;align-items:center;gap:10px}
.brand-dot{width:24px;height:24px;border-radius:50%;flex:none;background:var(--green);
  position:relative}
.brand-dot::before{content:"";position:absolute;left:6px;right:6px;top:7px;height:2px;
  background:#fff;box-shadow:0 4px 0 #fff,0 8px 0 #fff;border-radius:2px}
.brand-name{font-weight:800;letter-spacing:-.2px;line-height:1}
.brand-sub{font-size:11px;color:var(--ash);letter-spacing:.5px;text-transform:uppercase}

/* ---------- shell ---------- */
.shell{display:grid;grid-template-columns:240px 1fr;min-height:100vh}
.sidebar{background:var(--teal);color:#cfe0e2;padding:20px 14px;display:flex;
  flex-direction:column;gap:6px}
.sidebar .brand{padding:4px 8px 16px}
.sidebar .brand-name{color:#fff}
nav{display:flex;flex-direction:column;gap:3px;margin-top:4px}
.nav-item{display:flex;align-items:center;gap:11px;padding:10px 12px;border-radius:10px;
  color:#cfe0e2;text-decoration:none;font-size:14px;font-weight:500}
.nav-item .ic{width:18px;text-align:center;opacity:.85}
.nav-item.active{background:rgba(125,184,66,.20);color:#fff;
  box-shadow:inset 3px 0 0 var(--green)}
.nav-item.soon{opacity:.5;cursor:default}
.nav-item.soon::after{content:"soon";margin-left:auto;font-size:10px;
  background:rgba(255,255,255,.12);padding:2px 6px;border-radius:6px}
.signout{margin-top:auto;color:#9fb3b5;text-decoration:none;font-size:13px;
  padding:10px 12px;border-radius:10px}
.signout:hover{background:rgba(255,255,255,.08);color:#fff}

/* ---------- main ---------- */
.main{padding:22px 26px}
.topbar{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:18px}
.scope{font-size:13px;margin-top:3px}
.topbar-actions{display:flex;gap:10px;align-items:center}
.switcher{padding:9px 12px;border:1px solid var(--line);border-radius:10px;
  background:#fff;font-size:14px;font-weight:500;min-width:200px;cursor:pointer;font-family:inherit}
.switcher:focus{outline:2px solid var(--green);outline-offset:1px}
.btn-ghost{min-width:38px;height:38px;width:auto;padding:0 12px;display:inline-flex;align-items:center;
  justify-content:center;gap:6px;white-space:nowrap;border-radius:10px;
  border:1px solid var(--line);background:#fff;color:var(--muted);text-decoration:none;font-size:16px}

/* ---------- kpis ---------- */
/* Same custom-property trick as .grid: the accounts page asks for three
   across via style="--cols:repeat(3,1fr)", and the phone breakpoint below
   still overrides it because the inline style only sets the variable. */
.kpis{display:grid;grid-template-columns:var(--cols,repeat(auto-fit,minmax(168px,1fr)));
  gap:12px;margin-bottom:16px}
.kpi{background:var(--card);border-radius:14px;padding:13px 15px;
  border:1px solid var(--line);position:relative;overflow:hidden}
.kpi::before{content:"";position:absolute;left:0;top:0;bottom:0;width:4px}
.kpi-n{font-size:27px;font-weight:800;letter-spacing:-1px;font-variant-numeric:tabular-nums;
  line-height:1.15}
.kpi-l{font-size:13px;color:var(--muted);margin-top:2px}
.kpi-open::before{background:var(--teal)}
.kpi-urgent::before{background:var(--red)} .kpi-urgent .kpi-n{color:var(--red)}
.kpi-sla::before{background:var(--amber)} .kpi-sla .kpi-n{color:var(--amber-d)}
.kpi-done::before{background:var(--green)} .kpi-done .kpi-n{color:var(--green-d)}

/* ---------- cards ---------- */
/* Column widths come from a custom property, not from the property itself.
   Ten templates set their split inline (style="--cols:1.6fr 1fr"), and an
   inline grid-template-columns would beat the media query below — which is
   exactly why these pages never collapsed on a phone. Setting a variable
   inline leaves the real property to the stylesheet, so the breakpoint wins. */
.grid{display:grid;grid-template-columns:var(--cols,1fr 1fr);gap:14px;margin-bottom:16px}
.card{background:var(--card);border:1px solid var(--line);border-radius:14px;padding:16px 18px}
.card-h{font-weight:600;font-size:14px;margin-bottom:14px}

/* ---------- board ---------- */
.board{width:100%;border-collapse:collapse;font-size:14px}
.board th{text-align:left;font-size:12px;color:var(--muted);font-weight:600;
  padding:8px 10px;border-bottom:1px solid var(--line)}
.board td{padding:11px 10px;border-bottom:1px solid var(--line)}
.board tr:last-child td{border-bottom:0}
.board .name{font-weight:600}
.board .num{font-variant-numeric:tabular-nums}
.meter{height:7px;border-radius:5px;background:#eef1ef;overflow:hidden;width:120px;
  display:inline-block;vertical-align:middle}
.meter span{display:block;height:100%;background:var(--green);border-radius:5px}
.link{color:var(--green-d);text-decoration:none;font-weight:600;font-size:13px}
.pill{font-size:12px;font-weight:600;padding:3px 10px;border-radius:999px}
.pill-good{background:var(--green-100);color:#3b6d11}
.pill-watch{background:#fbe6c8;color:var(--amber-d)}
.pill-risk{background:#fee2e2;color:#b91c1c}

@media (max-width:920px){
  .shell{grid-template-columns:1fr}.sidebar{display:none}
  .kpis{grid-template-columns:repeat(2,1fr)}.grid{grid-template-columns:1fr}
}

/* ---------- compact charts (Step 2) ---------- */
.chart-box{position:relative;height:220px}

/* ---------- provisioning form (Step 2) ---------- */
.addform{display:flex;flex-direction:column;gap:6px}
.addform label{font-size:13px;font-weight:500;margin-top:6px}
.addform input[type=text],.addform input:not([type]){font-family:inherit}
.addform input{padding:10px 11px;border:1px solid var(--line);border-radius:9px;font-size:14px;font-family:inherit}
.addform input[type=color]{padding:3px;height:40px;width:64px;cursor:pointer}
.addform .row{display:flex;gap:12px}
.addform .check{display:flex;align-items:center;gap:8px;font-weight:400;font-size:13px;margin-top:10px}
.addform .check input{width:auto}
.addform button{margin-top:14px;padding:11px;border:0;border-radius:10px;background:var(--green);
  color:#fff;font-weight:600;font-size:14px;cursor:pointer;font-family:inherit}
.addform button:hover{background:var(--green-d)}
.linkbtn{background:none;border:0;color:var(--muted);font-weight:600;font-size:13px;
  cursor:pointer;padding:0 0 0 12px;font-family:inherit}
.linkbtn:hover{color:var(--ink)}
.linkbtn.danger:hover{color:var(--red)}

/* ---------- live map (Step 3) ---------- */
#map.map-full{height:calc(100vh - 150px);min-height:440px;border-radius:12px}
.mini-map{height:320px;border-radius:12px}
.leaflet-container{border-radius:12px;font-family:Outfit,"Segoe UI",sans-serif}
.agent-pin span{display:block;width:16px;height:16px;border-radius:50%;
  background:#1d4ed8;border:3px solid #fff;box-shadow:0 0 0 1px #1d4ed8}
.map-legend{background:#fff;padding:8px 11px;border-radius:10px;
  box-shadow:0 2px 12px rgba(0,30,34,.18);font-size:12px;line-height:1.55;color:var(--ink)}
.map-legend .ml-h{font-weight:600;margin-bottom:4px}
.map-legend .ml-row{display:flex;align-items:center;gap:7px}
.map-legend i{width:12px;height:12px;border-radius:3px;display:inline-block;flex:none}
.map-legend .ml-agent{background:#1d4ed8;border-radius:50%;border:2px solid #fff;box-shadow:0 0 0 1px #1d4ed8}

/* ---------- empty state + polish (Step 4) ---------- */
.empty{background:#fff;border:1px solid var(--line);border-radius:14px;padding:48px 32px;
  text-align:center;max-width:560px;margin:8px auto}
.empty-mark{width:46px;height:46px;border-radius:50%;background:var(--green);margin:0 auto 16px;position:relative}
.empty-mark::before{content:"";position:absolute;left:12px;right:12px;top:15px;height:3px;background:#fff;
  box-shadow:0 7px 0 #fff,0 14px 0 #fff;border-radius:2px}
.empty h2{margin:0 0 8px;font-size:20px}
.empty p{margin:0 auto 18px;max-width:420px;font-size:14px;line-height:1.5}
.empty-cta{display:inline-block;background:var(--green);color:#fff;text-decoration:none;
  font-weight:600;font-size:14px;padding:10px 18px;border-radius:10px}
.empty-cta:hover{background:var(--green-d)}

/* ---------- tickets / agents / reports (Step 6) ---------- */
.filters{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:14px}
.filters select,.filters input{padding:9px 11px;border:1px solid var(--line);border-radius:9px;
  font-size:14px;font-family:inherit;background:#fff}
.filters input{min-width:220px}
.filters button{padding:9px 16px;border:0;border-radius:9px;background:var(--green);color:#fff;
  font-weight:600;cursor:pointer;font-family:inherit}
.filters button:hover{background:var(--green-d)}

.st-open{background:#dbe7e9;color:#00343c}
.st-assigned{background:#e6e0f5;color:#5b3fa0}
.st-in_progress{background:#e0edf0;color:#0c4a54}
.st-work_in_progress{background:#e0edf0;color:#0c4a54}
.st-pending{background:#fbe6c8;color:#a9781a}
.st-resolved{background:#dcfce7;color:#15803d}
.st-closed{background:#eef1ef;color:#5b6a6c}
.pri-low{background:#eef1ef;color:#5b6a6c}
.pri-medium{background:#e0edf0;color:#0c4a54}
.pri-normal{background:#eef1ef;color:#5b6a6c}
.pri-high{background:#fbe6c8;color:#a9781a}
.pri-urgent{background:#fee2e2;color:#b91c1c}

.kv{width:100%;border-collapse:collapse;font-size:14px;margin-bottom:6px}
.kv td{padding:8px 4px;border-bottom:1px solid var(--line);vertical-align:top}
.kv td:first-child{color:var(--muted);width:120px}
.actions{display:flex;flex-direction:column;gap:10px;margin-top:14px}
.actions form{display:flex;gap:8px;align-items:flex-start}
.actions select{flex:1;padding:9px 11px;border:1px solid var(--line);border-radius:9px;
  font-family:inherit;font-size:14px;background:#fff}
.actions button{padding:9px 14px;border:0;border-radius:9px;background:var(--teal);color:#fff;
  font-weight:600;cursor:pointer;font-family:inherit;white-space:nowrap}
.actions button:hover{background:#0c4a54}
.note-form{flex-direction:column}
.note-form textarea{width:100%;padding:10px 11px;border:1px solid var(--line);border-radius:9px;
  font-family:inherit;font-size:14px;resize:vertical}
.note-form button{align-self:flex-start;background:var(--green)}
.note-form button:hover{background:var(--green-d)}

.tl{list-style:none;margin:0;padding:0}
.tl li{padding:9px 0 9px 18px;border-left:2px solid var(--line);position:relative}
.tl li:last-child{border-left-color:transparent}
.tl li::before{content:"";position:absolute;left:-5px;top:13px;width:8px;height:8px;border-radius:50%;background:var(--green)}
.tl .tl-body{font-size:14px}
.tl .tl-meta{font-size:12px;color:var(--muted);margin-top:1px}

.report-actions{display:flex;flex-direction:column;gap:10px}
.report-actions a{display:block;background:var(--green);color:#fff;text-decoration:none;font-weight:600;
  font-size:14px;padding:11px 16px;border-radius:10px;text-align:center}
.report-actions a:hover{background:var(--green-d)}

/* ---------- Step 7: SLA strip, capture, portal ---------- */
.btn-primary{display:inline-flex;align-items:center;height:38px;padding:0 16px;border-radius:10px;
  background:var(--green);color:#fff;text-decoration:none;font-weight:600;font-size:14px}
.btn-primary:hover{background:var(--green-d)}
.pill-soon{background:#fbe6c8;color:var(--amber-d)}
.pill-chan{background:#e7eef0;color:var(--teal-soft)}

.sla-strip{display:flex;gap:12px;flex-wrap:wrap;margin:-4px 0 16px}
.sla-chip{display:flex;align-items:center;gap:8px;background:#fff;border:1px solid var(--line);
  border-radius:11px;padding:9px 14px;font-size:13px;color:var(--muted)}
.sla-chip b{color:var(--ink);font-size:15px}
.sla-dot{width:9px;height:9px;border-radius:50%;flex:none}
.sla-over .sla-dot{background:var(--red)} .sla-over b{color:#b91c1c}
.sla-soon .sla-dot{background:var(--amber)} .sla-soon b{color:var(--amber-d)}
.sla-ok .sla-dot{background:var(--green)} .sla-ok b{color:var(--green-d)}

.two-col{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.two-col label{margin-top:6px}
.addform textarea{padding:10px 11px;border:1px solid var(--line);border-radius:9px;font-size:14px;
  font-family:inherit;resize:vertical}
.addform select{padding:10px 11px;border:1px solid var(--line);border-radius:9px;font-size:14px;
  font-family:inherit;background:#fff}
.hours-input{width:100%;padding:7px 9px;border:1px solid var(--line);border-radius:8px;
  font-size:14px;font-family:inherit}
.copy-row{display:flex;gap:8px}
.copy-row input{flex:1;padding:9px 11px;border:1px solid var(--line);border-radius:9px;
  font-size:13px;font-family:inherit;background:#f7f9f8;color:var(--muted)}
.copy-row button{padding:9px 14px;border:0;border-radius:9px;background:var(--teal);color:#fff;
  font-weight:600;font-size:13px;cursor:pointer;font-family:inherit}
.copy-row button:hover{background:var(--teal-2)}

/* ---------- public citizen portal ---------- */
.portal{min-height:100vh;background:var(--bg)}
.portal-top{display:flex;justify-content:space-between;align-items:center;
  background:var(--teal);color:#fff;padding:14px 18px}
.portal-brand{display:flex;align-items:center;gap:11px}
.portal-brand img{height:34px;width:auto;border-radius:6px}
.portal-dot{width:30px;height:30px;border-radius:50%;background:var(--green);flex:none;position:relative}
.portal-dot::before{content:"";position:absolute;left:7px;right:7px;top:9px;height:2px;background:#fff;
  box-shadow:0 5px 0 #fff,0 10px 0 #fff;border-radius:2px}
.portal-name{font-weight:800;line-height:1.1}
.portal-sub{font-size:11px;color:var(--ash);text-transform:uppercase;letter-spacing:.5px}
.portal-track{color:#cfe0e2;text-decoration:none;font-size:13px;font-weight:600;
  border:1px solid rgba(255,255,255,.25);padding:7px 12px;border-radius:9px}
.portal-track:hover{background:rgba(255,255,255,.1);color:#fff}
.portal-main{max-width:560px;margin:0 auto;padding:26px 18px 48px}
.portal-main h1{font-size:24px;margin:0 0 6px}
.portal-main>.muted{font-size:14px;line-height:1.5;margin:0 0 18px}
.portal-form{display:flex;flex-direction:column;gap:10px;position:relative}
.portal-form label{font-size:13px;font-weight:600;margin-top:8px}
.portal-form input:not([type=radio]):not([type=hidden]):not([type=checkbox]),.portal-form textarea{
  padding:12px 13px;border:1px solid var(--line);border-radius:11px;font-size:15px;
  font-family:inherit;background:#fff;width:100%;resize:vertical}
.portal-form input:focus,.portal-form textarea:focus{outline:2px solid var(--green);outline-offset:1px}
.cat-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}
.cat-opt{position:relative;margin:0}
.cat-opt input{position:absolute;opacity:0}
.cat-opt span{display:block;text-align:center;padding:13px 6px;border:1px solid var(--line);
  border-radius:11px;background:#fff;font-size:14px;font-weight:600;cursor:pointer}
.cat-opt input:checked+span{border-color:var(--green);background:var(--green-100);color:#3b6d11;
  box-shadow:inset 0 0 0 1px var(--green)}
.loc-btn{margin-top:6px;padding:11px;border:1px dashed var(--ash);border-radius:11px;background:#fff;
  font-size:14px;font-weight:600;color:var(--teal);cursor:pointer;font-family:inherit}
.loc-btn:hover{border-color:var(--green);color:var(--green-d)}
.loc-status{min-height:16px}
.portal-submit{margin-top:14px;padding:14px;border:0;border-radius:12px;background:var(--green);
  color:#fff;font-weight:700;font-size:16px;cursor:pointer;font-family:inherit}
.portal-submit:hover{background:var(--green-d)}
.portal-foot{text-align:center;margin-top:22px}

/* ---------- public status tracker ---------- */
.ok-banner{background:#dcfce7;color:#15803d;border:1px solid #bbf7d0;padding:12px 14px;
  border-radius:11px;font-size:14px;margin-bottom:16px}
/* Step 192 — a plain, non-alarming banner. A call sent to the board that is not
   on it yet is a normal state, not an error, so it must not look like one. */
.notice{background:#f4f6f5;border:1px solid var(--line);padding:12px 14px;
  border-radius:11px;margin-bottom:16px}
/* The card the Schedule route was aimed at. */
.jc-focus{border-color:var(--green);box-shadow:0 0 0 3px rgba(118,184,65,.22)}
/* Update and Schedule sit on one row: Schedule is a route away from the form,
   not a second way to save it, so it never looks like a submit button.
   .upd-btn carries its own margin-top, which in a flex row pushed Update down
   13px while the link stayed put — the margin moves to the row instead, and
   both are set to the same height so they line up on every zoom level. */
/* Step 196 — odometer capture. On the trip screen this is the one thing between
   a technician and their next tap, so it is full width and the number pad opens
   on a phone. */
/* Step 197 — proof of work from the trip screen. */
.trip-att{margin:14px 0 4px;padding:12px;border:1px solid var(--line);border-radius:11px;background:#fcfdfc}
.trip-att-h{font-weight:700;font-size:14px;display:flex;justify-content:space-between;
  align-items:baseline;gap:8px;margin-bottom:6px}
.trip-att-list{margin:4px 0 10px;padding-left:18px;font-size:14px}
.trip-att-list li{margin:3px 0}
.trip-att-ok{color:var(--green-d,#3d7a26);font-size:13px;font-weight:600;margin-bottom:6px}
.trip-att input[type=file]{width:100%;font-size:14px}
.trip-km{margin:10px 0 12px}
.trip-km label{display:block;font-size:13px;font-weight:600;margin-bottom:5px}
.trip-km input{width:100%;padding:12px 14px;font-size:17px;border:1px solid var(--line);
  border-radius:10px;box-sizing:border-box}
.trip-km-err{margin-top:7px;color:#b91c1c;font-size:13px;font-weight:600}
.field-km{display:block;margin:8px 0}
.field-km input{width:100%;max-width:260px;padding:8px 10px;border:1px solid var(--line);
  border-radius:8px;box-sizing:border-box}
.upd-actions{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-top:13px}
.upd-actions .upd-btn{margin-top:0}
.upd-actions .btn-ghost{height:40px}
.status-card{background:#fff;border:1px solid var(--line);border-radius:14px;padding:20px;text-align:center}
.status-ref{font-size:13px;color:var(--muted);font-weight:600;letter-spacing:.5px}
.status-now{display:inline-block;margin-top:8px;font-size:20px;font-weight:800;padding:6px 18px;border-radius:999px}
.status-open{background:#e7eef0;color:var(--teal)}
.status-in_progress{background:#dbeafe;color:#1d4ed8}
.status-pending{background:#fbe6c8;color:var(--amber-d)}
.status-resolved,.status-closed{background:var(--green-100);color:#3b6d11}
.track-steps{display:flex;justify-content:space-between;margin:22px 6px 4px;position:relative}
.track-steps::before{content:"";position:absolute;left:8%;right:8%;top:9px;height:2px;background:var(--line)}
.step{display:flex;flex-direction:column;align-items:center;gap:7px;z-index:1;flex:1}
.step-dot{width:20px;height:20px;border-radius:50%;background:#fff;border:2px solid var(--line)}
.step-l{font-size:12px;color:var(--muted);font-weight:600}
.step-done .step-dot{background:var(--green);border-color:var(--green)}
.step-done .step-l{color:var(--ink)}
.track-tl{background:#fff;border:1px solid var(--line);border-radius:14px;padding:16px 18px;margin-top:18px}

/* Step 8: portal opt-in + notifications */
.optin{display:flex;align-items:flex-start;gap:9px;margin-top:10px;font-size:14px;
  font-weight:500;color:var(--muted);cursor:pointer}
.optin input{margin-top:2px;width:18px;height:18px;flex:none;accent-color:var(--green)}
.optin span{line-height:1.35}

/* Step 9: identity + user management */
.whoami{margin-top:auto;padding:10px 12px;border-top:1px solid rgba(255,255,255,.12)}
.whoami-name{color:#fff;font-weight:600;font-size:14px}
.whoami-role{color:var(--ash);font-size:11.5px}
.sidebar{display:flex;flex-direction:column}
.rowmenu{position:relative;display:inline-block}
.rowmenu summary{list-style:none;cursor:pointer;padding:4px 10px;border:1px solid var(--line);
  border-radius:8px;color:var(--muted);font-weight:700}
.rowmenu summary::-webkit-details-marker{display:none}
.rowmenu-pop{position:absolute;right:0;top:110%;z-index:20;background:#fff;border:1px solid var(--line);
  border-radius:11px;box-shadow:0 10px 30px rgba(0,0,0,.12);padding:10px;width:230px;
  display:flex;flex-direction:column;gap:8px}
.rowmenu-pop form{display:flex;gap:6px;margin:0}
.rowmenu-pop button{padding:7px 10px;border:0;border-radius:8px;background:var(--teal);color:#fff;
  font-weight:600;font-size:13px;cursor:pointer;font-family:inherit;flex:none}
.rowmenu-pop button.danger{background:#dc2626;width:100%}
.inline-reset input{flex:1;min-width:0;padding:7px 9px;border:1px solid var(--line);border-radius:8px;
  font-size:13px;font-family:inherit}

/* Step 10: field operations */
.fieldcard{margin-bottom:14px}
.field-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:10px;margin:6px 0 14px}
.field-grid .fl{display:block;font-size:11px;text-transform:uppercase;letter-spacing:.4px;color:var(--muted)}
.field-grid>div{font-size:14px;font-weight:600}
.fs-allocated{background:#e7eef0;color:var(--teal)}
.fs-trip_started{background:#dbeafe;color:#1d4ed8}
.fs-work_started{background:#fbe6c8;color:var(--amber-d)}
.fs-done{background:var(--green-100);color:#3b6d11}
.fs-declined{background:#fee2e2;color:#b91c1c}
/* Allocate row. Every control is a labelled column and the row aligns on the
   BOTTOM edge, so the select and the button line up with the date inputs
   instead of centring against the taller label+input stacks. */
.dispatch-form{display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap;padding:12px 0;border-top:1px solid var(--line)}
.dispatch-form select,.dispatch-form input{padding:9px 10px;border:1px solid var(--line);border-radius:9px;font-family:inherit;font-size:14px;height:38px;box-sizing:border-box;width:100%}
.dispatch-form .dl{display:flex;flex-direction:column;font-size:11px;color:var(--muted);gap:3px;flex:0 1 200px;min-width:0}
.dispatch-form .dl-agent{flex:1 1 240px}
.dispatch-form button{padding:0 18px;height:38px;border:0;border-radius:9px;background:var(--green);color:#fff;font-weight:600;cursor:pointer;font-family:inherit;font-size:14px;white-space:nowrap;flex:0 0 auto}
@media (max-width:760px){
  /* stack cleanly rather than leaving a stranded button on its own line */
  .dispatch-form .dl,.dispatch-form .dl-agent{flex:1 1 100%}
  .dispatch-form button{width:100%}
}
.field-note{width:100%;padding:10px 11px;border:1px solid var(--line);border-radius:9px;font-family:inherit;font-size:14px;margin:12px 0 10px}
.field-actions{display:flex;gap:8px;flex-wrap:wrap}
.fa{padding:11px 16px;border:0;border-radius:10px;font-weight:700;font-size:14px;cursor:pointer;font-family:inherit;color:#fff}
.fa-go{background:#1d4ed8} .fa-work{background:var(--amber-d)} .fa-done{background:var(--green)} .fa-decline{background:#dc2626}
.fa:hover{filter:brightness(.94)}
.field-done{padding:12px 14px;background:var(--green-100);color:#3b6d11;border-radius:10px;font-weight:700}

/* kanban dispatch board */
.kanban{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;align-items:start}
/* Each column scrolls in place. Without this the whole page is as long as
   the Done column, and En route — the one dispatch actually works from —
   sits in a short column beside a very long one. */
.kcol-body{max-height:calc(100vh - 300px);overflow-y:auto}
.kcol-body::-webkit-scrollbar{width:8px}
.kcol-body::-webkit-scrollbar-thumb{background:rgba(0,0,0,.16);border-radius:8px}
/* An empty column is still worth showing — it is a real answer — but it
   does not need to be as tall as the ones with work in them. */
.kcol.is-empty{align-self:start}
.kcol.is-empty .kcol-body{min-height:0;padding:6px 10px 10px}
.kcol{background:#fff;border:1px solid var(--line);border-radius:14px;overflow:hidden}
.kcol-h{padding:11px 14px;font-weight:700;font-size:14px;display:flex;justify-content:space-between;align-items:center}
.kcount{background:rgba(0,0,0,.12);border-radius:999px;padding:1px 9px;font-size:12px}
.kcol-body{padding:10px;display:flex;flex-direction:column;gap:9px;min-height:60px}
.kcol-sub{padding:0 14px 9px;margin-top:-4px;border-bottom:1px solid var(--line)}
.jobcard{display:block;text-decoration:none;color:inherit;border:1px solid var(--line);border-radius:11px;padding:11px;background:#fcfdfc}
.jobcard:hover{border-color:var(--green);box-shadow:0 4px 14px rgba(0,0,0,.06)}
.jc-top{display:flex;justify-content:space-between;align-items:center;margin-bottom:3px}
.jc-ref{font-weight:700;font-size:13px}
.jc-cat{font-weight:600;font-size:14px}
.jc-addr{margin-top:2px}
.jc-meta{margin-top:6px;line-height:1.45}
.kempty{text-align:center;padding:8px 0;font-style:italic}
@media (max-width:1100px){.kanban{grid-template-columns:repeat(2,1fr)}.field-grid{grid-template-columns:repeat(2,1fr)}}

/* Langa brandmark */
.brandmark{flex:none;border-radius:50%}

/* Step 12: tasks-by-state, assets/contracts forms, calendar */
.tbs-card{margin-bottom:16px}
.tbs{display:flex;flex-direction:column;gap:9px;padding:4px 0}
.tbs-row{display:grid;grid-template-columns:120px 1fr 44px;align-items:center;gap:12px}
.tbs-label{font-size:13px;font-weight:600;color:var(--muted)}
.tbs-bar{background:#eef2ef;border-radius:8px;height:18px;overflow:hidden}
.tbs-fill{height:100%;border-radius:8px;min-width:2px}
.tbs-0{background:var(--teal-soft)} .tbs-1{background:#1d4ed8}
.tbs-2{background:var(--amber)} .tbs-3{background:var(--green)}
.tbs-n{text-align:right;font-weight:700;font-size:14px}

.addbox{background:#fff;border:1px solid var(--line);border-radius:12px;padding:6px 14px;margin-top:6px}
.addbox summary{cursor:pointer;font-weight:700;color:var(--green-d);padding:8px 0}
.rowform{display:flex;flex-wrap:wrap;gap:8px;align-items:flex-end;padding:6px 0 12px}
.rowform input,.rowform select{padding:9px 11px;border:1px solid var(--line);border-radius:9px;font-family:inherit;font-size:14px}
.rowform input{width:150px}.rowform .wide{width:280px;flex:1}
.rowform .dl{display:flex;flex-direction:column;font-size:11px;color:var(--muted);gap:2px}
.rowform button{padding:10px 18px;border:0;border-radius:9px;background:var(--green);color:#fff;font-weight:700;cursor:pointer;font-family:inherit}
.mini{padding:5px 9px;border:1px solid var(--line);border-radius:7px;background:#fff;font-size:12px;font-weight:600;cursor:pointer;font-family:inherit;color:var(--muted)}
.mini.danger{color:#dc2626;border-color:#f3c8c8}

/* calendar */
.cal-nav{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px;max-width:520px}
.cal-title{font-weight:800;font-size:18px;font-family:Montserrat,sans-serif}
.cal-head{display:grid;grid-template-columns:repeat(7,1fr);background:var(--teal);color:#cfe0e2}
.cal-head>div{padding:9px 10px;font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.4px}
.cal-week{display:grid;grid-template-columns:repeat(7,1fr)}
.cal-cell{min-height:96px;border-right:1px solid var(--line);border-bottom:1px solid var(--line);padding:6px;display:flex;flex-direction:column;gap:3px}
.cal-cell:nth-child(7n){border-right:0}
.cal-out{background:#fafbfa}
.cal-today{background:var(--green-100)}
.cal-day{font-size:12px;font-weight:700;color:var(--muted)}
.cal-today .cal-day{color:var(--green-d)}
.cal-job{display:block;text-decoration:none;font-size:11px;font-weight:600;color:#fff;background:var(--teal-soft);
  padding:3px 6px;border-radius:6px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cal-job.pri-high{background:var(--amber-d)} .cal-job.pri-urgent{background:#dc2626}
.cal-more{margin-top:1px}
@media (max-width:900px){.cal-cell{min-height:72px}.rowform input,.rowform .wide{width:100%}}

/* Step 13: task meta strip + attachments */
.metacard{margin-bottom:14px}
.meta-strip{display:grid;grid-template-columns:repeat(5,1fr);gap:10px}
.meta-strip>div{font-size:14px;font-weight:600}
.meta-strip .fl{display:block;font-size:11px;text-transform:uppercase;letter-spacing:.4px;color:var(--muted);font-weight:600}
.attach-form{display:flex;gap:8px;align-items:center;margin-bottom:12px}
.attach-form input[type=file]{font-family:inherit;font-size:13px}
.attach-form button{padding:8px 16px;border:0;border-radius:9px;background:var(--green);color:#fff;font-weight:600;cursor:pointer;font-family:inherit}
.attach-grid{display:flex;flex-wrap:wrap;gap:12px}
.attach-item{width:150px;border:1px solid var(--line);border-radius:11px;padding:8px;background:#fcfdfc;position:relative}
.attach-item img{width:100%;height:110px;object-fit:cover;border-radius:8px;display:block}
.attach-file{display:flex;align-items:center;justify-content:center;height:110px;font-size:40px;text-decoration:none;border-radius:8px;background:#eef2ef}
.attach-meta{margin-top:6px;line-height:1.35;word-break:break-word}
.attach-item>form{position:absolute;top:12px;right:12px;margin:0}
@media (max-width:900px){.meta-strip{grid-template-columns:repeat(2,1fr)}}

/* Step 14: layout — sidebar groups, scroll, mobile, ticket map */
.sidebar nav{flex:1;overflow-y:auto;display:flex;flex-direction:column;gap:1px;padding-right:2px}
.sidebar nav::-webkit-scrollbar{width:6px}
.sidebar nav::-webkit-scrollbar-thumb{background:rgba(255,255,255,.18);border-radius:3px}
.nav-label{font-size:10px;font-weight:800;letter-spacing:.8px;text-transform:uppercase;
  color:rgba(255,255,255,.38);padding:12px 12px 4px}

/* Step 208 — collapsible sidebar sections, asked for 3 Sep.
   The headings were labels; they are now the <summary> of a <details>, so they
   fold without any script and the browser gives us Enter, Space and focus for
   free. */
.navsec{border:0}
.navsec > summary.nav-label{display:flex;align-items:center;justify-content:space-between;
  gap:8px;cursor:pointer;list-style:none;user-select:none;border-radius:8px;
  padding:12px 12px 5px}
.navsec > summary.nav-label::-webkit-details-marker{display:none}
.navsec > summary.nav-label:hover{color:rgba(255,255,255,.72)}
.navsec > summary.nav-label:focus-visible{outline:2px solid rgba(255,255,255,.85);
  outline-offset:2px}
/* A caret drawn in CSS rather than a glyph, so it cannot be read out as a word
   and cannot pick up a font the box does not have. */
.navsec-caret{width:8px;height:8px;border-right:2px solid currentColor;
  border-bottom:2px solid currentColor;transform:rotate(45deg);margin-bottom:3px;
  transition:transform .15s ease;flex:0 0 auto;opacity:.75}
.navsec[open] > summary .navsec-caret{transform:rotate(-135deg);margin-bottom:0}
.navsec-items{display:flex;flex-direction:column;gap:2px;padding-bottom:2px}
/* A collapsed section that contains the page you are on would be a menu that
   has apparently lost an item. The script keeps it open; this is the belt to
   that pair of braces if the script never runs. */
.navsec:not([open]) > summary .nav-label{opacity:.6}
@media (prefers-reduced-motion:reduce){
  .navsec-caret{transition:none}
}
.nav-item{font-size:14px}
.tmap{height:340px;border-radius:12px;overflow:hidden;border:1px solid var(--line)}

/* mobile sidebar toggle (off-canvas) */
.navtoggle{display:none;position:fixed;top:12px;left:12px;z-index:1250;width:42px;height:42px;
  border:0;border-radius:10px;background:var(--teal);color:#fff;font-size:20px;cursor:pointer;
  box-shadow:0 2px 10px rgba(0,0,0,.2)}
/* Above Leaflet. Its control containers are z-index 1000, which is why the
   Field Agents panel and the layer picker painted over the open drawer. */
.navscrim{display:none;position:fixed;inset:0;background:rgba(0,0,0,.4);z-index:1150}
@media (max-width:820px){
  .navtoggle{display:block}
  .sidebar{position:fixed;top:0;left:0;height:100vh;z-index:1200;width:230px;
    transform:translateX(-100%);transition:transform .22s ease;box-shadow:2px 0 20px rgba(0,0,0,.25)}
  body.nav-open .sidebar{transform:none}
  body.nav-open .navscrim{display:block}
  .main{margin-left:0 !important;padding-top:60px}
  .topbar{flex-wrap:wrap}
}

/* Step 15: tabs + initial data */
.tabs{display:flex;gap:2px;border-bottom:2px solid var(--line);margin-bottom:16px;flex-wrap:wrap}
.tab{background:none;border:0;padding:10px 16px;font-family:inherit;font-size:14px;font-weight:600;
  color:var(--muted);cursor:pointer;border-bottom:2px solid transparent;margin-bottom:-2px}
.tab:hover{color:var(--ink)}
.tab.active{color:var(--green-d);border-bottom-color:var(--green)}
.tabn{display:inline-block;background:var(--green);color:#fff;font-size:11px;border-radius:999px;padding:0 7px;margin-left:4px;vertical-align:middle}
.tabpane{display:none}
.tabpane.active{display:block}
.idata td:first-child{font-weight:600;color:var(--muted);width:220px;vertical-align:top}
.idata .mini.danger{padding:2px 8px}

/* Step 16: view toggle, responsive tables, skill chips */
.viewtoggle{display:inline-flex;border:1px solid var(--line);border-radius:9px;overflow:hidden}
.viewtoggle .vt{padding:8px 14px;font-size:13px;font-weight:600;color:var(--muted);text-decoration:none;background:#fff}
.viewtoggle .vt.on{background:var(--green);color:#fff}
.table-wrap{width:100%}
@media (max-width:820px){
  .table-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
  .table-wrap .board{min-width:680px}
}
.chips{display:flex;flex-wrap:wrap;gap:8px}
.chip{display:inline-flex;align-items:center;gap:4px;background:var(--green-100);color:#2f5d23;
  border:1px solid #cfe6b6;border-radius:999px;padding:5px 6px 5px 14px;font-size:13px;font-weight:600}
.chip-x{border:0;background:none;color:#2f5d23;font-size:17px;line-height:1;cursor:pointer;padding:0 4px}
.chip-x:hover{color:#dc2626}

/* Step 17: required skills + agent linking + completion form */
.reqskills{padding:10px 0 4px;border-top:1px solid var(--line)}
.reqskills .fl{display:block;font-size:11px;text-transform:uppercase;letter-spacing:.4px;color:var(--muted);margin-bottom:6px}
.linkform{display:inline-block;margin:0}
.linkform select{padding:6px 8px;border:1px solid var(--line);border-radius:8px;font-family:inherit;font-size:13px;max-width:200px}
.completion-form{padding:10px 0 4px}
.completion-form .cf-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.completion-form label{display:block;font-size:11px;text-transform:uppercase;letter-spacing:.4px;color:var(--muted);margin-bottom:10px}
.completion-form label.cf-full{display:block}
.completion-form input,.completion-form textarea{display:block;width:100%;box-sizing:border-box;margin-top:3px;padding:9px 10px;
  border:1px solid var(--line);border-radius:9px;font-family:inherit;font-size:14px;color:var(--ink);text-transform:none;letter-spacing:normal;font-weight:600}
.completion-form textarea{resize:vertical;font-weight:400}
.completion-form button{padding:10px 18px;border:0;border-radius:9px;background:var(--green);color:#fff;font-weight:700;cursor:pointer;font-family:inherit}
.completion-form button:hover{background:var(--green-d)}
@media (max-width:900px){.completion-form .cf-grid{grid-template-columns:1fr}}

/* Scheduled/Calendar: toolbar, week view, technician resource grid */
.cal-bar{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:12px}
.cal-bar .switcher{max-width:240px}
.cal-head.wk>div{text-align:left}
.cal-cell.wk{min-height:340px;gap:6px}
.cal-cell.wk .cal-job{color:var(--ink);background:#fff;border:1px solid var(--line);
  border-left:3px solid var(--teal-soft);padding:6px 8px;border-radius:8px;line-height:1.35;white-space:normal}
.cal-cell.wk .cal-job.pri-high{border-left-color:var(--amber-d)}
.cal-cell.wk .cal-job.pri-urgent{border-left-color:#dc2626}
.cal-cell.wk .cal-job .muted{font-weight:500}
.cal-cell.wk .cal-job .pill{display:inline-block;margin-top:4px}
.restable{width:100%;border-collapse:collapse;min-width:780px}
.restable th{background:var(--teal);color:#cfe0e2;padding:9px 10px;font-size:12px;font-weight:700;text-align:center}
.restable th.rescol{text-align:left}
.restable th.cal-today{background:var(--green-d);color:#fff}
.restable td{border-right:1px solid var(--line);border-bottom:1px solid var(--line);padding:6px;vertical-align:top;min-width:118px}
.restable td.rescol{min-width:158px;font-weight:700;background:#fafbfa;position:sticky;left:0;z-index:1}
.restable td.cal-today{background:var(--green-100)}
.resrow.unassigned td.rescol{color:#b91c1c}
.resjob{display:block;text-decoration:none;font-size:11px;font-weight:600;color:#fff;
  background:var(--teal-soft);border-radius:7px;padding:4px 7px;margin-bottom:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.resjob.pri-high{background:var(--amber-d)} .resjob.pri-urgent{background:#dc2626}
.resjob.done{opacity:.5;text-decoration:line-through}

/* WhatsApp conversation thread on the ticket */
.wa-thread{display:flex;flex-direction:column;gap:8px;max-height:460px;overflow-y:auto;
  padding:12px;background:#f4f6f4;border:1px solid var(--line);border-radius:12px}
.wa-msg{display:flex;flex-direction:column;max-width:78%}
.wa-msg.in{align-self:flex-start;align-items:flex-start}
.wa-msg.out{align-self:flex-end;align-items:flex-end}
.wa-bubble{padding:8px 11px;border-radius:12px;font-size:14px;line-height:1.4;white-space:pre-wrap;word-break:break-word}
.wa-msg.in .wa-bubble{background:#fff;border:1px solid var(--line);border-top-left-radius:3px}
.wa-msg.out .wa-bubble{background:var(--green-100);border:1px solid #cfe6b6;border-top-right-radius:3px}
.wa-meta{font-size:11px;color:var(--muted);margin:3px 4px 0}
.wa-reply{display:flex;gap:8px;margin-top:12px}
.wa-reply textarea{flex:1;padding:10px 12px;border:1px solid var(--line);border-radius:10px;
  font-family:inherit;font-size:14px;resize:vertical}
.wa-reply button{align-self:flex-end;padding:10px 18px;border:0;border-radius:10px;
  background:var(--green);color:#fff;font-weight:600;cursor:pointer;font-family:inherit}
.wa-reply button:hover{background:var(--green-d)}

/* Step 36: larger sidebar menu font */
.sidebar .nav-item{font-size:14.5px;font-weight:500}
.sidebar .nav-label{font-size:11.5px}

/* Step 40: clickable dashboard KPI cards */
a.kpi{text-decoration:none;color:inherit;cursor:pointer;transition:transform .08s,box-shadow .08s}
a.kpi:hover{transform:translateY(-2px);box-shadow:0 6px 18px rgba(0,0,0,.08)}

/* ---- Step 43: Help widget + guided tour ---- */
.help-fab{position:fixed;right:22px;bottom:22px;z-index:900;width:50px;height:50px;border-radius:50%;
  border:0;background:var(--green);color:#fff;font-size:23px;font-weight:700;cursor:pointer;
  box-shadow:0 6px 20px rgba(0,0,0,.22);font-family:inherit;line-height:1}
.help-fab:hover{transform:translateY(-2px)}
.help-panel{position:fixed;right:22px;bottom:84px;z-index:901;width:296px;background:#fff;
  border:1px solid var(--line);border-radius:14px;box-shadow:0 14px 40px rgba(0,0,0,.18);overflow:hidden}
.help-panel-h{display:flex;align-items:center;justify-content:space-between;padding:12px 14px;
  border-bottom:1px solid var(--line);background:var(--green-100)}
.help-x{border:0;background:none;font-size:20px;line-height:1;cursor:pointer;color:var(--muted)}
.help-row{display:flex;gap:11px;align-items:center;width:100%;text-align:left;padding:12px 14px;
  border:0;border-bottom:1px solid var(--line);background:#fff;cursor:pointer;color:inherit;
  text-decoration:none;font-family:inherit;font-size:13.5px}
.help-row:last-child{border-bottom:0}
.help-row:hover{background:#f7faf4}
.help-call{background:#f3f9ec}
.help-ic{width:30px;height:30px;flex:none;border-radius:9px;background:var(--green-100);color:var(--green-d);
  display:grid;place-items:center;font-size:14px}

.tour-scrim{position:fixed;inset:0;background:rgba(8,20,14,.55);z-index:950}
.tour-target{z-index:960 !important;outline:3px solid var(--green);outline-offset:3px;
  border-radius:10px;background:rgba(255,255,255,.06)}
.tour-target-static{position:relative}
.tour-pop{position:fixed;z-index:970;width:322px;background:#fff;border-radius:14px;padding:15px 16px 12px;
  box-shadow:0 18px 50px rgba(0,0,0,.3)}
.tour-title{font-weight:700;font-size:15.5px;margin:2px 0 6px}
.tour-body{font-size:13.5px;line-height:1.6;color:#2c3a33}
.tour-actions{display:flex;align-items:center;gap:8px;margin-top:14px}
.tour-actions button{border:0;border-radius:9px;padding:8px 15px;cursor:pointer;font-family:inherit;
  font-size:13px;font-weight:600}
.tour-next{background:var(--green);color:#fff}
.tour-prev{background:#eef1ef;color:#2c3a33}
.tour-skip{background:none;color:var(--muted);padding-left:0}
@media (max-width:640px){.tour-pop{width:calc(100vw - 24px);left:12px !important}}
@media print{.help-fab,.help-panel,.tour-scrim,.tour-pop{display:none}}

/* Step 49: custom SVG menu icons */
.ic-svg{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px}
.ic-svg img{width:18px;height:18px;object-fit:contain;display:block}

.st-dispatched{background:#dbeafe;color:#1e40af}

/* ---- Step 51: consolidated ticket update panel ---- */
.upd{border:1px solid var(--line);border-radius:12px;padding:14px;background:#fbfcfb;margin-top:14px}
.upd-h{font-weight:700;font-size:14px;margin-bottom:11px}
.upd-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(168px,1fr));gap:10px}
.upd label{display:flex;flex-direction:column;gap:4px;font-size:12px;font-weight:600;color:var(--muted)}
.upd label select,.upd label input,.upd label textarea{width:100%;padding:8px 10px;border:1px solid var(--line);
  border-radius:8px;font-family:inherit;font-size:14px;color:var(--ink,#15201C);background:#fff;font-weight:400}
.upd-full{margin-top:11px}
.upd-btn{margin-top:13px;padding:10px 26px;border:0;border-radius:9px;background:var(--green);color:#fff;
  font-weight:700;cursor:pointer;font-family:inherit;font-size:14.5px}
.upd-btn:hover{filter:brightness(1.05)}
.tryit-btn{display:inline-flex;align-items:center;gap:7px;white-space:nowrap;width:auto;height:auto;
  padding:9px 15px;border:1px solid var(--line);border-radius:10px;background:#fff;color:inherit;
  text-decoration:none;font-size:14px;font-weight:600;font-family:inherit;line-height:1.2}
.tryit-btn:hover{border-color:var(--green);background:#f7faf4}

.upd-sub{font-weight:700;font-size:12.5px;color:var(--muted);text-transform:uppercase;letter-spacing:.4px;margin:16px 0 8px;padding-top:12px;border-top:1px dashed var(--line)}

/* ---- Step 57: portal hero ---- */
.portal-hero{text-align:center;padding:30px 20px 22px;background:#f4faef;
  background:linear-gradient(180deg, color-mix(in srgb, var(--green) 12%, #fff), #fff);
  border-bottom:1px solid var(--line)}
.portal-hero-mark{height:66px;width:auto;margin-bottom:12px}
.portal-hero h1{margin:0 0 8px;font-size:26px;color:var(--ink,#15201C)}
.portal-hero p{margin:0 auto;max-width:440px;color:var(--muted);font-size:14.5px;line-height:1.6}
@media (max-width:640px){.portal-hero{padding:24px 16px 18px}.portal-hero-mark{height:56px}.portal-hero h1{font-size:22px}}

/* Step 60: service-line pills */
.pill.sl-sales{background:#ede9fe;color:#6d28d9}
.pill.sl-support{background:#e0f2fe;color:#0369a1}
.pill.sl-billing{background:#fef3c7;color:#92400e}

/* ---- Step 65: mobile polish ---- */
@media (max-width:640px){
  .topbar{flex-direction:column;align-items:flex-start;gap:10px}
  .topbar-actions{display:flex;flex-wrap:wrap;gap:8px;width:100%}
  .topbar-actions .switcher{flex:1;min-width:0}
  .filters{width:100%}
  .filters select,.filters input{flex:1 1 46%;min-width:0}
  .filters button{flex:1 1 100%}
  .kpis{grid-template-columns:repeat(2,1fr)}
  .table-wrap .tbl{min-width:560px}
  .upd-grid{grid-template-columns:1fr 1fr}
  .help-fab{right:14px;bottom:14px}
  .help-panel{right:10px;left:10px;width:auto;bottom:76px}
  .main{padding:60px 14px 14px}
}

/* ---- Step 67: SMS in the conversation ---- */
.wa-bubble.sms{background:#fff8e6;border:1px solid #f1dfae}
.ch-tag{display:inline-block;background:#f59e0b;color:#fff;font-size:10px;font-weight:800;
  padding:1px 6px;border-radius:99px;letter-spacing:.4px}
.sms-sep{display:flex;align-items:center;gap:10px;margin:14px 0 8px;color:var(--muted);font-size:12px}
.sms-sep::before,.sms-sep::after{content:"";flex:1;height:1px;background:var(--line)}
.sms-btn{background:#f59e0b !important}

/* ---- Step 75: sortable table headers ---- */
.board th.sortable{padding:0}
.board th.sortable a{display:flex;align-items:center;gap:5px;padding:11px 12px;color:inherit;
  text-decoration:none;white-space:nowrap}
.board th.sortable a:hover{color:var(--green-d,#3d7a26)}
.board th.sorted a{color:var(--green-d,#3d7a26);font-weight:800}
.sort-arrow{font-size:10px;opacity:.45}
.board th.sorted .sort-arrow{opacity:1}

/* ---- Step 76: custom date range ---- */
.date-range{display:inline-flex;align-items:center;gap:6px}
.date-range[hidden]{display:none}
.date-range input[type=date]{padding:9px 10px;border:1px solid var(--line);border-radius:9px;
  font-family:inherit;font-size:14px;color:var(--ink,#15201C);background:#fff}
@media (max-width:640px){.date-range{flex:1 1 100%}.date-range input[type=date]{flex:1;min-width:0}}

/* ---- Step 81: call button as a link variant ---- */
a.mini{display:inline-flex;align-items:center;gap:4px;padding:3px 9px;border-radius:8px;
  border:1px solid var(--line);background:#fff;color:var(--muted);text-decoration:none;font-size:12.5px}
a.mini:hover{color:var(--green-d,#3d7a26);border-color:var(--green)}

/* ---- Step 82: acknowledged status ---- */
.pill.st-acknowledged{background:#e0e7ff;color:#3730a3}

/* ---- Step 83: fleet ---- */
.lock-note{display:block;font-size:11.5px;color:#92400e;margin-top:3px}
.upd-grid input:disabled,.upd-grid select:disabled{background:#f8f8f6;color:var(--muted);cursor:not-allowed}
.veh-state{display:inline-block;font-size:11.5px;font-weight:700;padding:2px 8px;border-radius:99px}
.veh-ok{background:#dcfce7;color:#15803d}
.veh-due_soon{background:#fef3c7;color:#92400e}
.veh-overdue{background:#fee2e2;color:#b91c1c}
.veh-untracked{background:#eef1ee;color:#5B6A6C}

/* ---- Step 84: two-column form rows ---- */
/* .addform stacks its direct children, but labels nested inside .two-col cells
   stayed inline and sat next to their inputs. Make each cell stack too. */
.addform .two-col > div{display:flex;flex-direction:column;gap:4px;min-width:0}
.addform .two-col > div > label{margin-top:0;font-size:13px;font-weight:500}
.addform .two-col input,.addform .two-col select,.addform .two-col textarea{
  width:100%;box-sizing:border-box}

/* ---- Step 88: duplicate resolution panel ---- */
.dupe-panel{max-width:900px;margin-bottom:14px;border-left:4px solid #f59e0b}
.dupe-table{width:100%;border-collapse:collapse}
.dupe-table td{padding:9px 8px;border-top:1px solid var(--line);vertical-align:top;font-size:13.5px}
.dupe-table tr:first-child td{border-top:0}
.dupe-name{font-weight:800;white-space:nowrap;padding-right:14px !important}

/* ---- Step 89: live map — agent state, staleness, trails ---- */
.agent-pin{position:relative}
.agent-pin span{position:absolute;inset:0;border-radius:50%;border:2px solid #fff;
  box-shadow:0 1px 6px rgba(0,0,0,.35)}
.agent-pin i{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  font-style:normal;font-weight:800;font-size:12px;color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.4)}
.agent-pin.state-trip_started span{animation:pinpulse 1.8s ease-out infinite}
.agent-pin.is-stale span{opacity:.45;border-style:dashed}
.agent-pin.is-stale i{opacity:.6}
@keyframes pinpulse{0%{box-shadow:0 0 0 0 rgba(3,105,161,.55)}
  70%{box-shadow:0 0 0 12px rgba(3,105,161,0)}100%{box-shadow:0 0 0 0 rgba(3,105,161,0)}}

.map-summary{background:#fff;border-radius:10px;padding:9px 11px;box-shadow:0 1px 8px rgba(0,0,0,.18);
  font-size:12.5px;min-width:150px}
.map-summary .ms-h{font-weight:800;margin-bottom:5px}
.map-summary .ms-row{display:flex;align-items:center;gap:7px;padding:1px 0}
.map-summary .ms-row i{width:10px;height:10px;border-radius:50%;flex:none}
.map-summary .ms-note{margin-top:5px;color:#92400e;font-size:11.5px}
.map-legend .ml-stale{background:#6b7280;opacity:.45;border:1px dashed #6b7280}
.mp-chip{display:inline-block;color:#fff;font-size:11px;font-weight:700;padding:1px 7px;border-radius:99px}
.mp-sub{color:#5B6A6C;font-size:11.5px}

/* ---- Step 90: dispatch from the map ---- */
.map-filters{background:#fff;border-radius:10px;box-shadow:0 1px 8px rgba(0,0,0,.18);overflow:hidden;display:flex}
.map-filters button{border:0;background:#fff;padding:7px 11px;font-family:inherit;font-size:12.5px;
  cursor:pointer;color:var(--muted);border-right:1px solid var(--line)}
.map-filters button:last-child{border-right:0}
.map-filters button.on{background:var(--green);color:#fff;font-weight:700}
.mp-near{margin-top:6px}
.mp-near-h{font-weight:800;font-size:12px;margin:6px 0 3px}
.mp-near-row{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:3px 0;
  border-top:1px solid var(--line);font-size:12.5px}
.mp-near-row button{border:1px solid var(--line);background:#fff;border-radius:7px;padding:2px 9px;
  font-family:inherit;font-size:12px;cursor:pointer;color:var(--green-d,#3d7a26);font-weight:700}
.mp-near-row button:hover{background:var(--green);color:#fff;border-color:var(--green)}

/* ---- Step 91: address suggestions ---- */
.addr-suggest{position:absolute;left:0;right:0;top:100%;z-index:40;background:#fff;
  border:1px solid var(--line);border-radius:10px;box-shadow:0 8px 24px rgba(0,0,0,.14);
  max-height:230px;overflow:auto;margin-top:3px}
.addr-row{display:block;width:100%;text-align:left;border:0;background:#fff;padding:9px 11px;
  font-family:inherit;font-size:13.5px;cursor:pointer;border-bottom:1px solid var(--line);color:var(--ink,#15201C)}
.addr-row:last-child{border-bottom:0}
.addr-row:hover{background:#f4f8f1}

/* ---- Step 91: navigate buttons ---- */
.nav-btns{display:flex;gap:8px;margin-top:8px;flex-wrap:wrap}
.nav-btn{display:inline-block;padding:9px 14px;border-radius:10px;text-decoration:none;
  font-weight:700;font-size:13.5px;color:#fff}
.nav-btn.waze{background:#33ccff}
.nav-btn.gmaps{background:#4285f4}
.addr-empty{padding:9px 11px;font-size:12.5px;color:var(--muted)}

/* Live map: the technician's name beside their pin. Sits to the right of the dot
   so the dot still marks the exact position, and ignores pointer events so it
   never blocks a click on a ticket underneath. */
.agent-pin{position:relative}
.agent-pin .agent-name{position:absolute;left:30px;top:50%;transform:translateY(-50%);
  white-space:nowrap;font-size:11px;font-weight:700;color:#15201c;
  background:rgba(255,255,255,.88);border-radius:6px;padding:1px 6px;
  box-shadow:0 1px 3px rgba(0,0,0,.18);pointer-events:none}
.agent-pin.is-stale .agent-name{opacity:.55}
.map-legend .ml-who-row{cursor:pointer}
.map-legend .ml-who-row:hover{background:rgba(0,0,0,.05);border-radius:5px}
.map-legend .ml-who{max-height:132px;overflow:auto}
@media (max-width:760px){
  /* names would cover half the screen on a phone */
  .agent-pin .agent-name{display:none}
}

/* Live map: field agents drawn as a figure rather than a dot, so people and
   tickets are distinguishable without reading the legend. */
.agent-pin .agent-fig{display:block;color:var(--pin);line-height:0}
.agent-pin .agent-fig svg{display:block;filter:drop-shadow(0 1px 2px rgba(0,0,0,.25))}
.agent-pin .agent-name{left:34px}
.agent-pin.is-stale .agent-fig{opacity:.5}
/* Clickable status key */
.map-legend .ml-pick{cursor:pointer;border-radius:5px;padding:1px 4px;margin-left:-4px}
.map-legend .ml-pick:hover{background:rgba(0,0,0,.06)}
.map-legend .ml-pick.on{background:var(--green);color:#fff;font-weight:600}
.map-legend .ml-any{background:linear-gradient(135deg,#0e7490 0 50%,#b45309 50% 100%)}

/* Reports: Excel is the primary download, CSV the secondary. */
.report-actions{display:flex;gap:10px;align-items:center;flex-wrap:wrap}
.report-actions .dl-primary{background:var(--green);color:#fff;padding:8px 16px;border-radius:9px;
  font-weight:600;text-decoration:none}
.report-actions .dl-primary:hover{filter:brightness(.95)}

/* On route now: name and job reference were running together. */
.map-legend .ml-who-row{display:flex;align-items:center;gap:6px}
.map-legend .ml-who-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.map-legend .ml-who-ref{font-size:10.5px;color:var(--muted);flex:0 0 auto}
.map-legend .ml-who-row.on .ml-who-ref{color:rgba(255,255,255,.8)}
/* Right-hand column: legend sits under the summary panel, both scroll if long. */
.leaflet-top.leaflet-right .map-legend{margin-top:8px;max-height:44vh;overflow:auto}

/* Asset status pills — colour carries the state at a glance down a long list. */
.pill.st-in_stock{background:#e5e7eb;color:#374151}
.pill.st-allocated{background:#dbeafe;color:#1e40af}
.pill.st-installed{background:#dcfce7;color:#15803d}
.pill.st-faulty{background:#fee2e2;color:#b42318}
.pill.st-removed{background:#fef3c7;color:#92400e}
.pill.st-retired{background:#f3f4f6;color:#6b7280}

/* List pagination. Deliberately plain: page numbers past a few thousand calls
   are noise, so it's a count plus previous/next. */
.pager{display:flex;align-items:center;gap:10px;padding:12px 2px;flex-wrap:wrap}
.pager .mini{padding:6px 14px}
.pager .mini.disabled{opacity:.4;pointer-events:none}
.pager .muted{margin-right:auto}

/* Add forms sit above the list, collapsed. A paginated list would otherwise
   bury the form on page 1 of N. */
.addbox{margin:0 0 14px}
.addbox > summary{cursor:pointer;display:inline-block;padding:9px 18px;border-radius:9px;
  background:var(--green);color:#fff;font-weight:600;font-size:14px;list-style:none}
.addbox > summary::-webkit-details-marker{display:none}
.addbox > summary:hover{filter:brightness(.95)}
.addbox[open] > summary{margin-bottom:10px}

/* Contract status, derived from the end date rather than stored. */
.pill.ct-active{background:#dcfce7;color:#15803d}
.pill.ct-expiring{background:#fef3c7;color:#92400e}
.pill.ct-expired{background:#fee2e2;color:#b42318}
.pill.ct-none{background:#e5e7eb;color:#374151}

/* Checkbox rows. This must come last: `.addform .two-col input{width:100%}` has
   the same specificity, so an earlier rule loses and the box stretches across
   the cell, dragging its label to the far side. Matches the inline pattern
   already used on the assets and WhatsApp pages.  */
.addform label.check,
.addform .two-col label.check{display:flex;align-items:center;gap:8px;
  font-weight:400;font-size:13px;margin:0;min-height:38px;white-space:normal}
.addform label.check input[type="checkbox"],
.addform .two-col label.check input[type="checkbox"]{width:18px;height:18px;
  flex:0 0 18px;margin:0;padding:0}

/* Onboarding stage pills — same shape as the asset and contract ones. */
.pill.onb-requested{background:#e5e7eb;color:#374151}
.pill.onb-coverage{background:#ede9fe;color:#5b21b6}
.pill.onb-survey{background:#dbeafe;color:#1e40af}
.pill.onb-quoted{background:#fef3c7;color:#92400e}
.pill.onb-accepted{background:#e0e7ff;color:#3730a3}
.pill.onb-scheduled{background:#cffafe;color:#155e75}
.pill.onb-installed{background:#dcfce7;color:#15803d}
.pill.onb-testing{background:#fef3c7;color:#92400e}
.pill.onb-signoff{background:#e0e7ff;color:#3730a3}
.pill.onb-activated{background:#bbf7d0;color:#14532d}
.pill.onb-billing{background:#bbf7d0;color:#14532d}
.pill.onb-lost{background:#fee2e2;color:#b42318}
/* Filter chips double as counters; the active one is filled. */
.sla-strip a.sla-chip{text-decoration:none}
.sla-strip a.sla-chip.on{background:var(--green);color:#fff}
.sla-strip a.sla-chip.on b{color:#fff}

/* ---- layout containment. Must be last: these override earlier sizing. ----
   `.shell` is `grid-template-columns:240px 1fr`, and a `1fr` track will NOT
   shrink below its content unless told to. So one wide table or a two-column
   form pushed the whole PAGE sideways — a horizontal scrollbar under every
   screen, on desktop and phone alike. `min-width:0` is the fix; the overflow
   then belongs to the thing that is actually too wide, not the document. */
.shell > .main{min-width:0}
.main{min-width:0;max-width:100%}
.main > *{max-width:100%}
/* Grid cells have the same rule: without min-width:0 a long input or a long
   word stops the column ever getting narrower. */
.addform .two-col > *,
.two-col > *{min-width:0}
.addform input,.addform select,.addform textarea{max-width:100%}

/* Wide tables scroll rather than stretching the page.
   The scrolling belongs to .table-wrap (see the phones block above), NOT to the
   table. Making the table display:block forces thead and tbody into two
   independent table boxes, and two table boxes size their columns separately —
   so a wide cell in the body slides every header out of line with its data.
   That is exactly what the ticket-list description did on 20 Aug.
   A .board that is not inside a .table-wrap still needs somewhere to scroll,
   hence the wrapper rule rather than nothing at all. */
.table-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
/* 13 .board tables are not inside a .table-wrap. Rather than touch all of them,
   the card scrolls instead — same result, and it cannot desynchronise a header
   from its body because the table itself stays one table box. */
.card{overflow-x:auto}

/* ---- phones ---- */
@media (max-width:760px){
  .shell{grid-template-columns:1fr}          /* sidebar stacks, never a 240px gutter */
  /* Top padding must clear the fixed hamburger — the suite enforces this
     because a bare `padding:` shorthand here has hidden it before. */
  .main{padding:64px 14px 16px}
  .topbar{flex-wrap:wrap;gap:10px}
  .topbar .switcher,.topbar select.switcher{width:100%;max-width:100%}
  .addform .two-col{grid-template-columns:1fr}   /* one field per row, full width */
  .filters{flex-wrap:wrap}
  .filters input,.filters select{flex:1 1 100%;min-width:0}
  .sla-strip{flex-wrap:wrap}
  .kpi-row{grid-template-columns:repeat(2,1fr)}
  .pager{gap:8px}
  .pager .muted{flex:1 1 100%;margin:0 0 6px}
}

/* A paused SLA. Deliberately not green: the target is not being met, it is
   simply not running. */
.pill.pill-paused{background:#e0e7ff;color:#3730a3}

/* ---------- wall mode: a TV in the NOC, watched from across the room ----------
   No sidebar, no gutter, bigger type. Everything here is scoped to .shell.wall
   so nothing leaks into the normal app. */
.shell.wall{grid-template-columns:1fr}
.shell.wall .main{padding:18px 22px}
.shell.wall .topbar h1{font-size:26px}
.shell.wall .kpi-n{font-size:54px;line-height:1.05}
.shell.wall .kpi-l{font-size:14px}
.shell.wall .card-h{font-size:16px}
.shell.wall .map-wrap,.shell.wall #map{height:calc(100vh - 190px);min-height:420px}
.shell.wall .board td,.shell.wall .board th{font-size:15px;padding:10px 12px}
.shell.wall .muted.small{font-size:12.5px}
/* Things nobody can click from across a room */
.shell.wall .addbox,.shell.wall .filters,.shell.wall .report-actions{display:none}

/* The wall controls sit top-right and fade until you move the mouse. */
.wall-bar{display:flex;gap:8px;align-items:center}
.wall-bar a,.wall-bar button{font:inherit;font-size:13px;padding:7px 14px;border-radius:9px;
  border:1px solid var(--line);background:#fff;color:inherit;cursor:pointer;text-decoration:none}
.shell.wall .wall-bar{opacity:.25;transition:opacity .2s}
.shell.wall .wall-bar:hover,.shell.wall:hover .wall-bar{opacity:1}

/* A stopped display is worse than a blank one: say so, loudly. */
.wall-stale{display:none;position:fixed;left:0;right:0;bottom:0;z-index:50;
  background:#b42318;color:#fff;font-weight:700;text-align:center;padding:12px 16px;font-size:16px}
.wall-stale.on{display:block}
@media (min-width:1400px){
  .shell.wall .kpi-n{font-size:64px}
  .shell.wall .topbar h1{font-size:30px}
}

/* Clustered technicians, coloured by the most urgent state inside the cluster —
   a grey number tells a controller nothing. Ours must beat the plugin's own
   default styling, which is why the .marker-cluster overrides are here too. */
.agent-cluster{display:flex;align-items:center;justify-content:center;border-radius:50%;
  color:#fff;font-size:13px;font-weight:700;border:2px solid #fff;
  box-shadow:0 1px 4px rgba(0,0,0,.3);background:#6b7280}
.agent-cluster.cluster-trip_started{background:#0e7490}
.agent-cluster.cluster-work_started{background:#15803d}
.agent-cluster.cluster-idle{background:#6b7280}
.marker-cluster-small,.marker-cluster-medium,.marker-cluster-large{background:transparent}
.marker-cluster-small div,.marker-cluster-medium div,.marker-cluster-large div{background:transparent}

/* Card headers carrying action buttons. Floats overlapped on a phone and the
   top one swallowed the tap meant for the one beneath it — the sign-off button
   opened the job card instead. */
.card-h.card-h-actions{display:flex;flex-wrap:wrap;align-items:center;gap:8px;
  justify-content:space-between}
.card-h .hdr-actions{display:flex;flex-wrap:wrap;gap:8px}
.card-h .hdr-actions .tryit-btn{padding:8px 14px;font-size:13px;float:none;margin:0;
  min-height:38px;display:inline-flex;align-items:center}
@media (max-width:760px){
  /* Full-width tap targets: a 38px button beside another is a mis-tap waiting
     to happen on a phone held in one hand. */
  .card-h .hdr-actions{width:100%}
  .card-h .hdr-actions .tryit-btn{flex:1 1 100%;justify-content:center}
}

/* Live map: field agents as small dots (18 Aug request). The wall view is a TV
   across the room — the figure markers crowded into each other at that size,
   so the name moved to a hover label and the marker became a bead. */
.agent-dot{position:relative}
.agent-dot .agent-bead{display:block;width:14px;height:14px;border-radius:50%;
  background:var(--pin,#dc2626);border:2px solid #fff;
  box-shadow:0 1px 3px rgba(0,0,0,.45)}
.agent-dot.state-trip_started .agent-bead{animation:pinpulse 1.8s ease-out infinite}
.agent-dot.is-stale .agent-bead{opacity:.5;border-style:dashed}

/* Step 158: every field in the update form is caption, control, then hint —
   in that order, always. A hint sitting inside the caption wrapped to a second
   line in a narrow column and pushed that one input below its neighbours,
   which is the misalignment reported on 19 Aug.
   margin-top:auto keeps a hint pinned to the bottom of its cell, so a tall
   neighbour stretches the row without moving any input. */
.upd label > .upd-hint{margin-top:auto;padding-top:4px;font-size:11.5px;
  font-weight:400;line-height:1.35;color:var(--muted)}
.upd-grid > label{align-content:start}

/* Live map on a phone (step 163).
   Three always-open panels covered the whole map on a ~400px screen. They now
   start collapsed to their heading and open on a tap. The class sits on the
   panel container, which survives the innerHTML rewrite on every poll. */
.map-summary.is-min > *:not(.ms-h),
.map-legend.is-min  > *:not(.ml-h){display:none}
.map-summary.is-min .ms-h,
.map-legend.is-min  .ml-h{margin-bottom:0}
.map-summary .ms-h,
.map-legend  .ml-h{cursor:pointer;user-select:none;display:flex;
  align-items:center;justify-content:space-between;gap:10px}
.map-summary .ms-h::after,
.map-legend  .ml-h::after{content:'\25B4';font-size:10px;opacity:.5;flex:none}
.map-summary.is-min .ms-h::after,
.map-legend.is-min  .ml-h::after{content:'\25BE'}

@media (max-width:760px){
  /* Never wider than half the screen, so the map stays readable behind them. */
  .map-summary,.map-legend{max-width:52vw;font-size:11.5px}
  .map-summary{min-width:0}
  .leaflet-control-layers-expanded{max-width:52vw}
  /* The status filter row sits top-left and was running under the summary. */
  .map-filters{max-width:44vw;flex-wrap:wrap}
}

/* Ticket list: the call description under the reference (19 Aug request).
   Clamped to two lines — an operator scanning the list needs the gist, and a
   paragraph in one row pushes every other row off the screen. */
.tk-blurb{max-width:340px;line-height:1.35;margin-top:2px;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}

/* Services delivered at a site (19 Aug request). Nested under their site row
   rather than given their own page — a circuit only means anything in the
   context of where it lands. */
.svc{padding:6px 10px;margin:4px 0;border-left:3px solid var(--brand);
  background:rgba(0,0,0,.03);border-radius:0 8px 8px 0;font-size:13px}
.svc.is-off{opacity:.55;border-left-color:var(--muted)}
.svc-add summary{cursor:pointer;padding:4px 0}
.svc-add[open] summary{margin-bottom:6px}

/* Field help on the log-a-request form (step 167). One line under a control,
   explaining what it changes — not what it is called. */
.fh{display:block;font-size:11.5px;line-height:1.4;color:var(--muted);margin:3px 2px 10px}
.req{font-size:11px;font-weight:600;color:#b42318;text-transform:uppercase;letter-spacing:.4px}

/* "Add a user" / "Add agent" / "Add client" (step 171).
   On a desktop these sit open beside the list, as before. On a phone the grid
   stacks, which put a long form ABOVE or BELOW the list you came to read —
   several screens of scrolling to reach either. They now sit first, collapsed
   to a single tappable row, and open on demand. */
.add-card > summary{cursor:pointer;list-style:none;display:flex;align-items:center;
  justify-content:space-between;gap:10px}
.add-card > summary::-webkit-details-marker{display:none}
.add-card > summary::after{content:'+';font-size:19px;font-weight:700;line-height:1;
  color:var(--green,#5a9e2f);flex:none;transition:transform .15s}
.add-card[open] > summary::after{transform:rotate(45deg)}

@media (max-width:920px){
  /* First in the stack — the action you came for, not an afterthought at the
     bottom of a list that may run to hundreds of rows. */
  .grid > .add-card{order:-1}
  .add-card:not([open]){padding-top:12px;padding-bottom:12px}
  .add-card:not([open]) > summary{margin-bottom:0}
}

/* An assumed position: we are drawing the JOB's location because the
   technician's phone has not reported. Hollow, so it reads as "this is where
   the work is" rather than "this is where the person is". */
.agent-dot.is-assumed .agent-bead{background:transparent;
  border:3px dashed var(--pin,#dc2626);box-shadow:none;opacity:.85;animation:none}

/* An approximate address suggestion: the town, not the building. Marked so a
   pin landing 2km from the actual site is a choice rather than a surprise. */
.addr-row.addr-approx{font-style:italic;color:var(--muted)}
.addr-row.addr-approx::after{content:' (town only)';font-size:11px;opacity:.75}

/* Inline mobile-number editor on the Agents list. There are dozens of records
   to fill in; a page per agent would make that a morning's work. */
.ag-phone{display:flex;gap:5px;align-items:center;margin-top:4px}
.ag-phone input{width:140px;padding:4px 7px;font-size:12.5px;margin:0}

/* Sign-off: choosing between a completion certificate and a delivery note. */
.sokind{display:flex;gap:10px;flex-wrap:wrap;margin:0 0 14px}
.sokind-opt{display:flex;align-items:center;gap:8px;flex:1 1 220px;margin:0;
  padding:11px 13px;border:2px solid var(--line);border-radius:10px;cursor:pointer;
  font-weight:600;font-size:13.5px}
.sokind-opt:has(input:checked){border-color:var(--green,#5a9e2f);background:rgba(90,158,47,.07)}
.sokind-opt input{width:18px;height:18px;flex:none;margin:0}
.so-row-off{display:none !important}
.soitems input{width:100%;margin:0;padding:6px 8px;font-size:13px}
.soitems td{padding:5px 6px}

/* The ticket update panel ran to three screens. The fields changed on most
   calls stay visible; customer, contract and SLA details fold away behind a
   summary that reads as a button rather than a stray line of text. */
.upd-more{margin:4px 0 10px;border:1px solid var(--line);border-radius:10px;
  background:rgba(0,0,0,.015)}
.upd-more > summary{cursor:pointer;user-select:none;padding:10px 13px;
  font-size:12.5px;font-weight:700;color:#00343c;list-style:none;
  display:flex;align-items:center;justify-content:space-between}
.upd-more > summary::-webkit-details-marker{display:none}
.upd-more > summary::after{content:'+';font-size:18px;font-weight:700;
  color:var(--green,#5a9e2f);transition:transform .15s}
.upd-more[open] > summary::after{transform:rotate(45deg)}
.upd-more[open] > summary{border-bottom:1px solid var(--line);margin-bottom:10px}
.upd-more > *:not(summary){padding:0 13px}
.upd-more > *:last-child{padding-bottom:12px}

/* Step 200 — the two sign-off panels on the Activity tab.
   Step 199 shipped them with no CSS at all. The waiver textarea therefore fell
   back to the browser default — about 20 characters wide, two rows, sitting
   beside its button — on a field asking an operator to write a sentence
   explaining why a compliance document is unsigned. Reported off the screen. */
.awaitsig{border-left:3px solid var(--green)}
.awaitsig .hdr-actions{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
.awaitsig .hdr-actions form{margin:0}
.awaitsig .hdr-actions .tryit-btn{padding:8px 14px;font-size:13px;float:none;margin:0;
  min-height:38px;display:inline-flex;align-items:center}

.waivebox summary{cursor:pointer;font-weight:600;font-size:14px;color:var(--ink);
  padding:2px 0;list-style-position:outside}
.waivebox summary:hover{color:var(--green-d)}
.waivebox > p{margin:10px 0 12px;max-width:70ch}
.waivebox textarea{display:block;width:100%;box-sizing:border-box;padding:10px 11px;
  border:1px solid var(--line);border-radius:9px;font-family:inherit;font-size:14px;
  resize:vertical;min-height:76px}
.waivebox button{margin-top:10px}

/* Step 207 — Users & access.
   The page held 55 people across 26 clients with no way to find one, and the
   single most consequential fact on it — that an Administrator sees every
   client — was rendered as the same grey text as everything else. */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}
.sr-only:focus{position:static;width:auto;height:auto;margin:0;clip:auto;
  white-space:normal}

.users-top{display:flex;gap:10px;align-items:center;margin-bottom:12px;flex-wrap:wrap}
.usearch{flex:1 1 320px;min-width:0}
.usearch input{width:100%;box-sizing:border-box;padding:10px 12px;border:1px solid var(--line);
  border-radius:10px;font-family:inherit;font-size:15px;background:var(--card)}
.users-top .tryit-btn{flex:0 0 auto;margin:0;float:none}

.ufilters{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:14px}
.fchip{display:inline-flex;align-items:center;gap:7px;padding:7px 13px;border-radius:999px;
  border:1px solid var(--line);background:var(--card);color:var(--ink);font:inherit;
  font-size:13px;cursor:pointer;min-height:36px}
.fchip:hover{border-color:var(--green)}
.fchip.is-on{background:var(--green-100);border-color:var(--green);font-weight:600}
.fchip-n{background:#eef2ee;border-radius:999px;padding:1px 7px;font-size:12px;color:#3c4a41}
.fchip.is-on .fchip-n{background:#fff}
.fchip-alt{border-style:dashed}

.utable td{vertical-align:top}
.utable .name .link{font-weight:600}
.utable tr.is-off .name .link{color:var(--muted)}
.pill-all{background:#fff5e6;border:1px solid #f0d8a8;color:#8a5a00;border-radius:999px;
  padding:2px 9px;font-size:12px;white-space:nowrap}
.utable .never{color:#9a6b00;background:#fff8e8;border-radius:5px;padding:1px 6px}
.note-scope{margin:2px 2px 10px;min-height:1.1em}

/* Focus you can actually see — the row menus and chips are keyboard-reachable
   and were showing the browser default over a green background. */
.fchip:focus-visible,.usearch input:focus-visible,.utable .rowmenu summary:focus-visible,
.utable .link:focus-visible,.users-top .tryit-btn:focus-visible{
  outline:3px solid #1d4ed8;outline-offset:2px;border-radius:6px}
.utable .rowmenu summary{list-style:none;cursor:pointer;min-width:38px;min-height:38px;
  display:inline-flex;align-items:center;justify-content:center;border-radius:8px;
  font-size:18px;color:var(--ink)}
.utable .rowmenu summary::-webkit-details-marker{display:none}
.utable .rowmenu summary:hover{background:#eef2ee}
.rowacts{text-align:right;white-space:nowrap}

@media (max-width:760px){
  /* A five-column table on a phone scrolls sideways and the actions end up off
     the edge. One card per person instead. */
  .utable thead{display:none}
  .utable,.utable tbody,.utable tr,.utable td{display:block;width:auto}
  .utable tr{border:1px solid var(--line);border-radius:12px;padding:12px 14px;
    margin-bottom:10px;position:relative;background:var(--card)}
  .utable td{border:none;padding:2px 0}
  .utable td:nth-child(2)::before{content:"Role: ";color:var(--muted)}
  .utable td:nth-child(3)::before{content:"Client: ";color:var(--muted)}
  .utable td:nth-child(4)::before{content:"Last sign-in: ";color:var(--muted)}
  .rowacts{position:absolute;top:8px;right:8px}
}

/* Step 209 — chrome that every page shares.

   The sidebar comes before the content in the document on every screen, so
   reaching the page meant tabbing through up to twenty links each time. */
.skiplink{position:absolute;left:-9999px;top:0;z-index:1000;background:var(--green);
  color:#04270f;font-weight:700;padding:12px 18px;border-radius:0 0 10px 0;
  text-decoration:none}
.skiplink:focus{left:0}

/* The scrim is a <button> now so it is a real control rather than a div with a
   click handler; it stays out of the tab order because Escape and the toggle
   are the keyboard ways out. */
.navscrim{border:0;padding:0;appearance:none;font:inherit}

/* One visible focus style for everything that did not have one. Scoped to
   :focus-visible so a mouse click does not leave a ring behind. */
a:focus-visible,button:focus-visible,select:focus-visible,
input:focus-visible,textarea:focus-visible,summary:focus-visible{
  outline:3px solid #1d4ed8;outline-offset:2px;border-radius:6px}
.sidebar a:focus-visible,.sidebar button:focus-visible,.sidebar summary:focus-visible{
  outline-color:rgba(255,255,255,.9)}

/* The current page was a colour and nothing else. */
.nav-item[aria-current="page"]{font-weight:700}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms !important;animation-iteration-count:1 !important;
    transition-duration:.01ms !important;scroll-behavior:auto !important}
}
/* Focus moves to the content, so it must not draw a ring around the whole page. */
.main:focus{outline:none}
.portal-main:focus{outline:none}

/* Step 210 — Agents.
   Eight columns inside 1.6fr of a two-column grid clipped the Remove button to
   a bare "R". The list takes the full width; Add agent is a button. */
.agwrap{display:block}
.agtable td{vertical-align:top}
.agtable .name{min-width:190px}
.agtable .ag-phone{display:flex;gap:6px;align-items:center;margin:6px 0 2px}
.agtable .ag-phone input{width:150px;padding:6px 8px;border:1px solid var(--line);
  border-radius:8px;font:inherit;font-size:13px}
.agtable .linkform select{max-width:230px}
.agtable .num a{font-weight:700}
@media (max-width:900px){
  /* Eight columns do not fit a phone, and the actions were the first thing off
     the edge — which is how "Remove" became "R" on a laptop. */
  .agtable thead{display:none}
  .agtable,.agtable tbody,.agtable tr,.agtable td{display:block;width:auto}
  .agtable tr{border:1px solid var(--line);border-radius:12px;padding:12px 14px;
    margin-bottom:10px;background:var(--card)}
  .agtable td{border:none;padding:3px 0}
  .agtable .ag-phone input{width:100%}
  .agtable .linkform select{max-width:100%;width:100%}
}
