/* Simply Fleet — SF_Workshop. Brand: teal #009AA4 + navy #1B3A4B.
   Light theme — matches the workshop-flow explainer: warm off-white bg (#f6f5f2), white cards,
   soft two-layer shadows, teal accent, radius 14. Only colours changed vs. the old dark build;
   all layout / a11y / iOS rules below are unchanged. */
:root{
  color-scheme:light;
  --bg:#f6f5f2;--panel:#ecebe8;--panel2:#ffffff;--elev:#ffffff;
  --text:#1a1c1e;--muted:#5f6672;--faint:#8a929b;--line:#dfe1e4;
  --green:#15803d;--teal:#0d9488;--amber:#b45309;--red:#b91c1c;--purple:#7c3aed;--blue:#2563eb;
  --brand-teal:#009aa4;--brand-navy:#1b3a4b;
  --attn:#fdecea;--attn-line:#f2c9c4;--attn-ink:#b23b30;
  --radius:14px;--radius-sm:9px;
  --shadow:0 1px 2px rgba(16,20,30,.05),0 6px 20px rgba(16,20,30,.07);
  --ring:0 0 0 3px rgba(13,148,136,.22);
  --dur:.18s;
}
@media (prefers-reduced-motion: reduce){ :root{ --dur:0s } }
*{box-sizing:border-box}
html,body{height:100%}
body{margin:0;font:14px/1.5 system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;background:var(--bg);color:var(--text);-webkit-font-smoothing:antialiased}
.vh{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* ---- header / toolbar ---- */
header{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:10px max(20px,env(safe-area-inset-right)) 10px max(20px,env(safe-area-inset-left));border-bottom:1px solid var(--line);position:sticky;top:0;background:linear-gradient(180deg,rgba(246,245,242,.96),rgba(246,245,242,.82));backdrop-filter:blur(8px);z-index:10}
.brand{display:flex;align-items:center;gap:12px;min-width:0}
.brand .logo{display:flex;align-items:center;background:#fff;border-radius:8px;padding:5px 8px;flex:none;box-shadow:0 1px 2px rgba(16,20,30,.06)}
.brand .logo img{height:24px;display:block}
.brand .titles{min-width:0}
.brand h1{font-size:17px;margin:0;font-weight:680;letter-spacing:-.01em}
.brand .sub{margin:0;color:var(--muted);font-size:12px}
.brand .sub b{color:var(--brand-teal);font-weight:600;font-style:italic}
.tools{display:flex;align-items:center;gap:8px;flex-wrap:wrap;justify-content:flex-end}
.summary{display:flex;gap:6px;align-items:center;font-size:12px;margin-right:2px}
.summary .pill{background:var(--panel2);border:1px solid var(--line);border-radius:20px;padding:2px 10px;color:var(--muted)}
.summary .pill.attn{color:var(--red);border-color:var(--attn-line);background:var(--attn);font-weight:600}
input,select,button{font:inherit;color:var(--text)}
#search{background:var(--panel2);border:1px solid var(--line);border-radius:var(--radius-sm);padding:7px 11px;width:230px;transition:border-color var(--dur),box-shadow var(--dur)}
#search:focus{outline:none;border-color:var(--teal);box-shadow:var(--ring)}
#sort{background:var(--panel2);border:1px solid var(--line);border-radius:var(--radius-sm);padding:7px 8px;cursor:pointer}
button.toggle,#refresh{background:var(--panel2);border:1px solid var(--line);border-radius:var(--radius-sm);padding:7px 11px;cursor:pointer;transition:background var(--dur),border-color var(--dur),color var(--dur)}
button.toggle:hover,#refresh:hover{border-color:var(--teal)}
button.toggle[aria-pressed="true"]{background:var(--attn);border-color:var(--attn-line);color:var(--red)}
@media (prefers-reduced-motion: no-preference){ #refresh.spin{animation:spin .6s linear} }
@keyframes spin{to{transform:rotate(360deg)}}
.conn{display:flex;align-items:center;gap:6px;color:var(--muted);font-size:12px;white-space:nowrap}
.conn .dot{width:8px;height:8px;border-radius:50%;background:var(--faint);flex:none}
.conn.live .dot{background:var(--green)}
.conn.stale .dot{background:var(--amber)}
.conn.down .dot{background:var(--red)}
@media (prefers-reduced-motion: no-preference){ .conn.live .dot{animation:pulse 2.2s infinite} }
@keyframes pulse{0%{box-shadow:0 0 0 0 rgba(21,128,61,.5)}70%{box-shadow:0 0 0 6px rgba(21,128,61,0)}100%{box-shadow:0 0 0 0 rgba(21,128,61,0)}}

/* ---- board ---- */
main{display:grid;grid-template-columns:repeat(5,1fr);gap:14px;padding:18px 20px;align-items:start}
.lane{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);padding:10px;min-height:120px}
.lane h2{font-size:12px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);margin:4px 6px 10px;display:flex;justify-content:space-between;align-items:center}
.lane .count{color:var(--text);background:var(--panel2);border:1px solid var(--line);border-radius:10px;padding:0 8px;font-size:12px;min-width:22px;text-align:center}
.lane.attention{background:linear-gradient(180deg,var(--attn),var(--panel));border-color:var(--attn-line)}
.lane.attention h2{color:var(--red)}
.lane.attention .count{background:rgba(185,28,28,.1);color:var(--red);border-color:var(--attn-line)}
/* "Awaiting deploy" — the healthy waiting lane (rated "used it", prod deploy still pending). A neutral blue
   accent, deliberately NOT the red attention treatment (a lagging deploy is normal, not a fault). */
.lane.awaiting-lane h2{color:var(--blue)}
.lane.awaiting-lane .count{background:rgba(37,99,235,.1);color:var(--blue);border-color:transparent}
.cards{display:flex;flex-direction:column;gap:8px;scrollbar-width:thin;scrollbar-color:var(--line) transparent}
.cards::-webkit-scrollbar{width:8px}
.cards::-webkit-scrollbar-thumb{background:var(--line);border-radius:4px}
.cards::-webkit-scrollbar-thumb:hover{background:var(--faint)}
.more{color:var(--faint);font-size:11px;padding:7px 6px 2px;text-align:center}

/* Multi-column board (tablet/desktop): fill the viewport and scroll each lane independently — so a huge
   Complete lane never makes the page tall or buries a short Needs-attention lane. Mobile (≤680px) page-scrolls.
   100dvh tracks the iOS browser chrome so the bottom of every lane stays reachable (100vh is the fallback). */
@media (min-width:681px){
  html,body{height:100%}
  body{height:100vh;height:100dvh;display:flex;flex-direction:column;overflow:hidden}
  header{flex:0 0 auto}
  main{flex:1 1 auto;min-height:0;align-items:stretch;grid-template-rows:minmax(0,1fr)}
  .lane{display:flex;flex-direction:column;min-height:0}
  .lane h2{flex:0 0 auto}
  .cards{flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding-right:3px}
}

/* ---- cards ---- */
.card{background:var(--panel2);border:1px solid var(--line);border-radius:var(--radius-sm);padding:9px 11px;cursor:pointer;box-shadow:0 1px 2px rgba(16,20,30,.04);transition:transform var(--dur),border-color var(--dur),box-shadow var(--dur)}
@media (prefers-reduced-motion: no-preference){ .card{animation:cardin var(--dur) ease-out} }
@keyframes cardin{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}
.card:hover{border-color:var(--teal);transform:translateY(-1px);box-shadow:var(--shadow)}
.card:focus-visible{outline:2px solid var(--teal);outline-offset:2px;border-color:var(--teal)}
.card .id{font-weight:660;display:flex;align-items:center;gap:6px;flex-wrap:wrap;overflow-wrap:anywhere}
/* Per-card archive/unarchive button — quiet by default, pushed to the row's right edge; appears on hover/focus
   so resting cards stay clean, but stays reachable by keyboard (focus-within) and always visible on touch. */
.card .id .arch-btn{margin-left:auto;background:var(--bg);border:1px solid var(--line);color:var(--faint);border-radius:5px;min-height:26px;min-width:26px;display:inline-flex;align-items:center;justify-content:center;padding:0 6px;font-size:12px;line-height:1;cursor:pointer;opacity:0;transition:color var(--dur),border-color var(--dur),opacity var(--dur)}
.card:hover .id .arch-btn,.card:focus-within .id .arch-btn{opacity:1}
.card .id .arch-btn:hover{color:var(--text);border-color:var(--teal)}
.card .id .arch-btn:focus-visible{opacity:1;outline:2px solid var(--teal);outline-offset:2px}
.lane.archived-lane .card{opacity:.72}
.lane.archived-lane .card:hover,.lane.archived-lane .card:focus-within{opacity:1}
.mini-count{color:var(--faint);font-size:11px;font-variant-numeric:tabular-nums}
@media (hover: none){ .card .id .arch-btn{opacity:1} }
/* U4: the submitted title on the card — clamped to 2 lines so cards stay compact (full text on hover). */
.card .card-title{color:var(--text);font-size:12.5px;font-weight:560;margin-top:3px;line-height:1.35;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;overflow-wrap:anywhere}
.card .app{color:var(--muted);font-size:12px;margin-top:2px}
.card .by-line{color:var(--faint);font-size:11px;margin-top:2px}
.ev-by{color:var(--faint)}
.card .stat{color:var(--muted);font-size:11px;margin-top:4px}
.card .stat .warn{color:var(--amber);font-weight:600}
.card .reason{color:var(--attn-ink);font-size:12px;margin-top:5px;line-height:1.45;overflow-wrap:anywhere}
.card .age{color:var(--faint);font-size:11px;margin-top:5px}
.card .reason a{color:var(--red)}
/* A lease-HELD card (REQUESTED, waiting on an older same-app ticket) — a quiet blue "waiting on" badge, not
   the red failure-reason treatment: it's parked on purpose, nothing is wrong. */
.card .reason.blocked{color:var(--blue)}
/* Slip-up watcher (§3): the app's dev source changed outside a ticket. Amber, informational — the drift was
   folded into the baseline and filed as untracked, so nothing is broken, but it's worth a human's eye. */
.card .reason.drift{color:var(--amber)}
.state-pill{display:inline-block;font-size:10px;text-transform:uppercase;letter-spacing:.03em;color:var(--muted);border:1px solid var(--line);border-radius:10px;padding:1px 7px;cursor:help}
/* State color now lives on the pill (tinted background), not a card-edge stripe — same rgba-tint idiom as .lane.attention .count */
.card.s-PROPOSED .state-pill{background:rgba(124,58,237,.12);color:var(--purple);border-color:transparent}
.card.s-PR_OPEN .state-pill{background:rgba(180,83,9,.12);color:var(--amber);border-color:transparent}
.card.s-PR_MERGED .state-pill{background:rgba(21,128,61,.12);color:var(--green);border-color:transparent}
.card.s-UNROUTABLE .state-pill,.card.s-UNAPPLIABLE .state-pill,.card.s-PROPOSE_FAILED .state-pill,.card.s-PR_NO_FIX .state-pill,.card.s-PR_CHANGES_REQUESTED .state-pill,.card.s-PR_CLOSED .state-pill{background:rgba(185,28,28,.1);color:var(--red);border-color:transparent}
/* Confirmed-live-in-Zoho badge: same rgba-tint idiom as .card.s-PR_MERGED .state-pill (green), no border
   accent — this is the Zoho-side counterpart to the PR-lifecycle facts already in the drawer meta. */
.applied-pill{background:rgba(21,128,61,.12);color:var(--green);border-color:transparent;cursor:help}
/* Small distinguishing marker for human-authored timeline events (vs. automated poll-state/PICKED/PROPOSED
   events) — reuses the same tinted-pill idiom rather than a new color or a border accent. */
.human-pill{background:rgba(13,148,136,.12);color:var(--teal);border-color:transparent;cursor:default;margin-right:4px}

/* ---- drawer ---- */
.drawer{position:fixed;inset:0;background:rgba(16,20,30,.4);display:flex;justify-content:flex-end;z-index:30}
@media (prefers-reduced-motion: no-preference){ .drawer{animation:fadein var(--dur)} .drawer .drawer-inner{animation:slidein var(--dur) ease-out} }
@keyframes fadein{from{opacity:0}to{opacity:1}}
@keyframes slidein{from{transform:translateX(24px)}to{transform:none}}
.drawer.hidden{display:none}
/* Lock the body by POSITION (not just overflow, which iOS ignores for touch) so the board can't
   scroll-bleed behind an open drawer. JS captures/restores scrollY to avoid a jump. */
body.drawer-open{position:fixed;inset:0;width:100%;overflow:hidden}
.drawer-inner{width:min(480px,94vw);height:100%;background:var(--panel2);border-left:1px solid var(--line);padding:18px max(20px,env(safe-area-inset-right)) 24px 20px;overflow:auto;overscroll-behavior:contain;box-shadow:var(--shadow)}
#drawer-close{float:right;background:none;border:none;color:var(--muted);font-size:18px;cursor:pointer;border-radius:6px;padding:1px 7px;line-height:1.4}
#drawer-close:hover{color:var(--text);background:var(--bg)}
.drawer h3{margin:0 0 12px;display:flex;align-items:center;gap:8px;font-size:18px}
.drawer h4{margin:18px 0 8px;font-size:12px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted)}
#drawer-meta div{color:var(--muted);font-size:13px;margin:3px 0;display:flex;align-items:center;gap:6px;flex-wrap:wrap}
#drawer-meta b{color:var(--text)}
#drawer-meta .help{color:var(--faint);font-size:12px}
#drawer-meta a{color:var(--teal)}
#drawer-meta code{background:var(--bg);border:1px solid var(--line);border-radius:4px;padding:1px 6px;font-size:12px;color:var(--text);overflow-wrap:anywhere}
#drawer-meta .faint{color:var(--faint);font-size:12px;margin-top:8px}
/* Plain-English status banner at the top of the drawer — the first thing a human reads. Full-width block,
   not the inline flex the other meta rows use, so the sentence reads normally. */
#drawer-meta .banner{display:block;font-size:13px;line-height:1.5;padding:10px 12px;border-radius:var(--radius-sm);border:1px solid var(--line);margin:2px 0 10px}
#drawer-meta .banner b{color:inherit}
/* U4: the submitted ask — title as a heading, description as a scrollable quoted block (block, not the
   inline flex the other meta rows use; pre-wrap preserves the pasted ticket's line breaks). */
#drawer-meta .tk-title{display:block;color:var(--text);font-size:15px;font-weight:640;line-height:1.35;margin:2px 0 6px}
#drawer-meta .tk-desc{display:block;color:var(--muted);font-size:13px;line-height:1.5;white-space:pre-wrap;overflow-wrap:anywhere;background:var(--bg);border:1px solid var(--line);border-radius:var(--radius-sm);padding:9px 11px;margin:0 0 10px;max-height:40vh;overflow:auto}
#drawer-meta .tk-desc a{color:var(--teal)}
.banner.b-attn{background:var(--attn);border-color:var(--attn-line);color:var(--attn-ink)}
.banner.b-review{background:rgba(180,83,9,.1);border-color:transparent;color:var(--amber)}
.banner.b-done{background:rgba(21,128,61,.1);border-color:transparent;color:var(--green)}
.banner.b-wait,.banner.b-work{background:rgba(13,148,136,.1);border-color:transparent;color:var(--teal)}
/* "Rated — awaiting your prod deploy": the common, healthy waiting state — a neutral blue, deliberately NOT
   the red attention treatment (a lagging prod deploy is normal, not a fault). Released is a quieter grey:
   the app was force-unblocked but the fix still isn't confirmed live. */
.banner.b-await{background:rgba(37,99,235,.1);border-color:transparent;color:var(--blue)}
.banner.b-released{background:rgba(95,102,114,.1);border-color:transparent;color:var(--muted)}
/* Deploy escalation — a genuinely lagging prod deploy (N days) or one that's now BLOCKING another ticket for
   the app. Loud amber (attention, but not the red "something broke" one — nothing broke, it just needs the
   dev to deploy). It's a SEPARATE nudge below the neutral awaiting-deploy status banner, never a replacement
   for it (the status banner stays blue). */
.banner.b-escalate{background:rgba(180,83,9,.12);border-color:transparent;color:var(--amber)}
/* Demoted raw backend string on a failure ticket — muted, secondary, clearly not the headline. */
#drawer-meta .tech-detail{display:block;color:var(--faint);font-size:12px;line-height:1.45;overflow-wrap:anywhere}
#drawer-meta .tech-detail .tech-label{display:inline-block;text-transform:uppercase;letter-spacing:.03em;font-size:10px;font-weight:600;color:var(--muted);margin-right:4px}
#drawer-events{margin:8px 0 0;padding-left:6px;list-style:none}
#drawer-events li{position:relative;padding:0 0 14px 18px;border-left:2px solid var(--line);margin-left:4px} /* impeccable-disable-line side-tab -- timeline connector line, not a card accent stripe */
#drawer-events li:last-child{border-left-color:transparent;padding-bottom:0}
#drawer-events li::before{content:"";position:absolute;left:-5px;top:4px;width:8px;height:8px;border-radius:50%;background:var(--teal);border:2px solid var(--panel2)}
#drawer-events li.empty::before{display:none}
#drawer-events .ev{font-weight:600;color:var(--text)}
#drawer-events .detail{color:var(--muted);overflow-wrap:anywhere}
#drawer-events a{color:var(--teal)}
#drawer-events .ts{color:var(--faint);font-size:12px}

/* ---- copy buttons ---- */
.copy{background:var(--bg);border:1px solid var(--line);color:var(--muted);border-radius:5px;min-height:30px;min-width:30px;display:inline-flex;align-items:center;justify-content:center;padding:0 8px;font-size:12px;cursor:pointer;transition:color var(--dur),border-color var(--dur)}
.copy:hover{color:var(--text);border-color:var(--teal)}
.copy.copied{color:var(--green);border-color:var(--green)}
/* "Mark applied in Zoho" reuses .copy's secondary-button visual weight (quiet, not a primary CTA color) —
   a distinct class (not .copy itself) so it doesn't get swept up by the delegated copy-button click
   handler, which matches on the .copy class alone. */
.secondary-btn{background:var(--bg);border:1px solid var(--line);color:var(--muted);border-radius:5px;padding:6px 12px;font-size:13px;cursor:pointer;transition:color var(--dur),border-color var(--dur)}
.secondary-btn:hover{color:var(--text);border-color:var(--teal)}
.secondary-btn:focus-visible{outline:2px solid var(--teal);outline-offset:2px}
.secondary-btn:disabled{opacity:.5;cursor:not-allowed}
/* Retry is the primary action on a failed ticket — teal fill to lift it above the quiet secondary buttons. */
.retry-btn{background:var(--teal);border-color:var(--teal);color:#fff;font-weight:600}
.retry-btn:hover{color:#fff;filter:brightness(1.08)}
.retry-btn:disabled{opacity:.5;cursor:not-allowed}

/* ---- disposition: what the dev did with Miles's PR ---- */
/* The disposition (rating) block now lives in #drawer-feedback at the bottom of the drawer, so its styling is
   unscoped from #drawer-meta. #drawer-feedback groups the deploy nudge + rating + force-unblock next to the
   "Add a note" comments box; it collapses to nothing when the ticket has no feedback to show. */
#drawer-feedback:empty{display:none}
#drawer-feedback{margin-top:6px}
.disposition-block{display:block;margin:8px 0;padding:10px 12px;border:1px solid var(--line);border-radius:var(--radius-sm);background:var(--bg)}
.disposition-block .disp-q{color:var(--text);font-size:13px;font-weight:600;margin-bottom:8px}
.disposition-block .disp-btns{display:flex;flex-wrap:wrap;gap:6px}
.disp-btn.disp-active{background:var(--teal);border-color:var(--teal);color:#fff;font-weight:600}
.disp-btn.disp-active:hover{color:#fff}
.disposition-block .disp-recorded{color:var(--muted);font-size:13px;margin-bottom:8px}
.disposition-block .disp-note{color:var(--muted);font-size:13px;font-style:italic;line-height:1.45;margin:2px 0 8px;overflow-wrap:anywhere}
/* Prod-deploy state under a "used it" rating: green once confirmed live, neutral blue while it's still the
   dev's to promote (their nudge to re-open and confirm). */
.disposition-block .disp-deploy{font-size:13px;line-height:1.45;margin:2px 0 8px}
.disp-deploy.live{color:var(--green);font-weight:600}
.disp-deploy.await{color:var(--blue)}
.disposition-block .disp-summary{color:var(--muted);font-size:13px;line-height:1.5;background:var(--card,#fff);border:1px solid var(--line);border-radius:var(--radius-sm);padding:8px 10px;margin:6px 0 4px;white-space:pre-wrap;overflow-wrap:anywhere}
/* Inline rating form (comment box + prod-deploy toggle) injected on a rating click — replaces the old native
   prompt()/confirm() dialogs with on-screen controls. */
.disp-form{margin-top:10px;padding:10px 11px;border:1px solid var(--line);border-radius:var(--radius-sm);background:var(--bg)}
.disp-form-label{display:block;font-size:12px;color:var(--muted);margin-bottom:4px}
.disp-note-input{width:100%;background:var(--panel2);border:1px solid var(--line);border-radius:var(--radius-sm);padding:8px 10px;color:var(--text);font:inherit;resize:vertical}
.disp-note-input:focus{outline:none;border-color:var(--teal);box-shadow:var(--ring)}
.deploy-q{font-size:13px;font-weight:600;color:var(--text);margin:10px 0 6px}
.deploy-choices{display:flex;gap:6px}
.deploy-choice{background:var(--panel2);border:1px solid var(--line);color:var(--muted);border-radius:5px;padding:6px 12px;font-size:13px;cursor:pointer;transition:color var(--dur),border-color var(--dur),background var(--dur)}
.deploy-choice:hover{color:var(--text);border-color:var(--teal)}
.deploy-choice:focus-visible{outline:2px solid var(--teal);outline-offset:2px}
.deploy-choice.on{background:var(--teal);border-color:var(--teal);color:#fff;font-weight:600}
.disp-form-actions{display:flex;align-items:center;gap:10px;margin-top:12px}
.disp-save{background:var(--teal);border:1px solid var(--teal);color:#fff;font-weight:600;border-radius:5px;padding:6px 14px;font-size:13px;cursor:pointer;transition:filter var(--dur)}
.disp-save:hover{filter:brightness(1.06)}
.disp-save:focus-visible{outline:2px solid var(--teal);outline-offset:2px}
.disp-save:disabled{opacity:.5;cursor:not-allowed}
.disp-cancel{background:none;border:none;color:var(--muted);font-size:13px;cursor:pointer;padding:6px 4px}
.disp-cancel:hover{color:var(--text);text-decoration:underline}
/* "?" How-to button + the first-run guide modal body. */
.help-btn{min-width:34px;font-weight:700;text-align:center}
.help-modal .drawer-inner{width:min(460px,94vw)}
.help-body{font-size:14px;line-height:1.55;color:var(--text)}
.help-body p{margin:0 0 10px}
.help-body .help-lead{font-weight:600;margin-top:14px}
.help-body ul,.help-body ol{margin:0 0 10px;padding-left:20px}
.help-body li{margin:4px 0}
.help-body .faint{color:var(--muted);font-size:13px}

/* ---- add-a-note ---- */
#drawer-note{margin-top:18px}
#note-input{width:100%;background:var(--bg);border:1px solid var(--line);border-radius:var(--radius-sm);padding:9px 11px;color:var(--text);font:inherit;resize:vertical;transition:border-color var(--dur),box-shadow var(--dur)}
#note-input:focus{outline:none;border-color:var(--teal);box-shadow:var(--ring)}
.note-row{display:flex;align-items:center;justify-content:flex-end;gap:10px;margin-top:8px}
.note-counter{color:var(--amber);font-size:11px;margin-right:auto}

/* ---- submit-ticket form (shares the note/drawer visual language) ---- */
#submit-form{display:flex;flex-direction:column;gap:4px}
#submit-form label{font-size:12px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);margin-top:10px}
#submit-form input,#submit-form select,#submit-form textarea{width:100%;background:var(--bg);border:1px solid var(--line);border-radius:var(--radius-sm);padding:9px 11px;color:var(--text);font:inherit;transition:border-color var(--dur),box-shadow var(--dur)}
#submit-form textarea{resize:vertical}
#submit-form input:focus,#submit-form select:focus,#submit-form textarea:focus{outline:none;border-color:var(--teal);box-shadow:var(--ring)}
.drawer .help{font-size:13px;color:var(--muted);margin:0 0 4px}
.lookup-status{font-size:12px;min-height:15px;margin-top:4px}
.lookup-status.pending{color:var(--muted)}
.lookup-status.hit{color:var(--green)}
.lookup-status.miss{color:var(--faint)}

/* ---- skeletons ---- */
.skel{height:56px;border-radius:var(--radius-sm);background:linear-gradient(90deg,#ececea 25%,#f6f6f4 37%,#ececea 63%);background-size:300% 100%;border:1px solid var(--line)}
@media (prefers-reduced-motion: no-preference){ .skel{animation:shimmer 1.3s infinite} }
@keyframes shimmer{to{background-position:-300% 0}}

/* ---- toasts ---- */
.toasts{position:fixed;right:max(16px,env(safe-area-inset-right));bottom:max(16px,env(safe-area-inset-bottom));display:flex;flex-direction:column;gap:8px;z-index:50;max-width:min(360px,92vw)}
.toast{background:var(--elev);border:1px solid var(--line);border-radius:var(--radius-sm);padding:9px 12px 9px 32px;color:var(--text);font-size:13px;box-shadow:var(--shadow);position:relative}
.toast::before{position:absolute;left:11px;top:9px;font-size:13px;line-height:1.4}
.toast.success::before{content:"✓";color:var(--green)}
.toast.error::before{content:"✕";color:var(--red)}
.toast.info::before{content:"ℹ";color:var(--teal)}
@media (prefers-reduced-motion: no-preference){ .toast{animation:toastin var(--dur) ease-out} .toast.out{animation:toastout var(--dur) ease-in forwards} }
@keyframes toastin{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
@keyframes toastout{to{opacity:0;transform:translateX(12px)}}

/* ---- live progress (in-flight tickets) ---- */
/* In-flight state pills share the teal "active" tint; EXPORT_FAILED joins the red failure set. */
.card.s-EXPORTING .state-pill,.card.s-REFRESHING .state-pill,.card.s-PROPOSING .state-pill,.card.s-VALIDATING .state-pill,.card.s-OPENING_PR .state-pill{background:rgba(13,148,136,.12);color:var(--teal);border-color:transparent}
.card.s-EXPORT_FAILED .state-pill{background:rgba(185,28,28,.1);color:var(--red);border-color:transparent}
/* card: live "working now" row — replaces the static "updated Xm ago" while in-flight */
.card .live{display:flex;align-items:center;gap:7px;margin-top:6px;font-size:12px;color:var(--teal)}
.card .live.idle{color:var(--muted)}
.card .live .live-dot{width:8px;height:8px;border-radius:50%;background:var(--teal);flex:none}
@media (prefers-reduced-motion: no-preference){ .card .live .live-dot{animation:pulse-teal 1.8s infinite} }
@keyframes pulse-teal{0%{box-shadow:0 0 0 0 rgba(13,148,136,.5)}70%{box-shadow:0 0 0 6px rgba(13,148,136,0)}100%{box-shadow:0 0 0 0 rgba(13,148,136,0)}}
.card .live .live-label{font-weight:600;overflow-wrap:anywhere}
.card .live .live-time{margin-left:auto;color:var(--faint);font-variant-numeric:tabular-nums;font-size:11px}
/* card: mini 5-segment stepper */
.stepper.mini{display:flex;gap:3px;margin-top:6px}
.stepper.mini i{flex:1;height:3px;border-radius:2px;background:var(--line)}
.stepper.mini i.done,.stepper.mini i.active{background:var(--teal)}
@media (prefers-reduced-motion: no-preference){ .stepper.mini i.active{animation:seg 1.4s ease-in-out infinite} }
@keyframes seg{0%,100%{opacity:.45}50%{opacity:1}}

/* drawer: vertical workflow stepper (#drawer-progress) */
#drawer-progress .wf-steps{list-style:none;margin:6px 0 0;padding:0}
#drawer-progress h4{margin:18px 0 8px;font-size:12px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted)}
.wf-steps li{position:relative;padding:0 0 16px 24px;color:var(--faint);font-size:13px}
.wf-steps li::before{content:"";position:absolute;left:6px;top:16px;bottom:0;width:2px;background:var(--line)}
.wf-steps li:last-child::before{display:none}
.wf-dot{position:absolute;left:0;top:1px;width:14px;height:14px;border-radius:50%;background:var(--panel2);border:2px solid var(--line)}
.wf-steps li.done{color:var(--muted)}
.wf-steps li.done .wf-dot{background:var(--teal);border-color:var(--teal)}
.wf-steps li.done .wf-dot::after{content:"✓";position:absolute;inset:-3px 0 0 0;color:#fff;font-size:9px;text-align:center;line-height:14px}
.wf-steps li.active{color:var(--text);font-weight:600}
.wf-steps li.active .wf-dot{border-color:var(--teal);background:var(--panel2)}
@media (prefers-reduced-motion: no-preference){ .wf-steps li.active .wf-dot{animation:pulse-teal 1.8s infinite} }
.wf-steps li.stopped{color:var(--red);font-weight:600}
.wf-steps li.stopped .wf-dot{border-color:var(--red);background:var(--red)}
.wf-steps li.stopped .wf-dot::after{content:"✕";position:absolute;inset:-3px 0 0 0;color:#fff;font-size:9px;text-align:center;line-height:14px}
.wf-t{color:var(--faint);font-weight:400;font-size:12px;font-variant-numeric:tabular-nums;margin-left:6px}

.empty{color:var(--faint);font-size:12px;padding:8px 6px}
.board-error{margin:14px 20px 0;padding:10px 12px;border:1px solid var(--attn-line);background:var(--attn);color:var(--attn-ink);border-radius:var(--radius-sm);font-size:13px}
.board-error a{color:var(--red);font-weight:600}
.board-error.hidden{display:none}

/* ---- responsive ---- */
@media(max-width:1100px){main{grid-template-columns:1fr 1fr}}
@media(max-width:680px){
  header{flex-direction:column;align-items:stretch;gap:10px;padding-top:max(10px,env(safe-area-inset-top))}
  .tools{justify-content:flex-start}
  #search{flex:1 1 auto;min-width:140px;width:auto}
  main{grid-template-columns:1fr;padding:14px}
  .drawer-inner{width:100%}
}
/* Touch devices: enforce 44px minimum tap targets without bloating the desktop pointer UI. */
@media (pointer:coarse){
  button.toggle,#refresh,#sort,#search{min-height:44px}
  #refresh{min-width:44px}
  #drawer-close{min-height:44px;min-width:44px;display:flex;align-items:center;justify-content:center;padding:0;float:none;position:absolute;top:12px;right:14px}
  .drawer h3{padding-right:48px}
  .copy{min-height:40px;min-width:40px}
  .secondary-btn{min-height:44px}
}

/* ---- B5 Friday review modal ---- */
.review-modal .drawer-inner{width:min(940px,96vw)}
.review-sec{margin:0 0 22px}
.review-sec h4{margin:16px 0 8px;font-size:12px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted)}
.review-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch}
.review-tbl{width:100%;border-collapse:collapse;font-size:13px;font-variant-numeric:tabular-nums}
.review-tbl th,.review-tbl td{padding:6px 10px;text-align:right;border-bottom:1px solid var(--line);white-space:nowrap}
.review-tbl th:first-child,.review-tbl td:first-child,.review-tbl td.wk{text-align:left}
.review-ledger td:nth-child(2),.review-ledger td:nth-child(3),.review-ledger td:nth-child(4){text-align:left}
.review-tbl thead th{color:var(--muted);font-weight:600;font-size:11px;text-transform:uppercase;letter-spacing:.03em;border-bottom:2px solid var(--line);cursor:default}
.review-tbl tfoot td{border-top:2px solid var(--line);border-bottom:none;font-weight:600}
.review-tbl .lg-cost,.review-tbl .lg-err{font-weight:600}
.review-tbl .lg-err{color:var(--red)}
.review-tbl .lg-state{color:var(--muted);font-size:12px}
.review-note{font-size:12px;color:var(--muted);margin:8px 0 0;line-height:1.5}
.review-empty{color:var(--faint);font-size:13px;padding:10px 4px}
.review-controls{display:flex;gap:8px;align-items:center;margin:0 0 10px}
.review-controls #review-filter{flex:1 1 auto;min-width:120px;background:var(--panel2);border:1px solid var(--line);border-radius:var(--radius-sm);padding:7px 10px;font-size:13px;color:var(--text)}
.review-controls #review-sort{background:var(--panel2);border:1px solid var(--line);border-radius:var(--radius-sm);padding:7px 10px;font-size:13px;color:var(--text)}
.review-gaps{list-style:none;margin:0;padding:0}
.review-gaps .gap{padding:9px 0;border-bottom:1px solid var(--line)}
.review-gaps .gap-head{font-size:13px;display:flex;flex-wrap:wrap;align-items:baseline;gap:6px}
.review-gaps .gap-tag{font-size:11px;text-transform:uppercase;letter-spacing:.03em;color:#fff;background:var(--muted);border-radius:4px;padding:1px 6px}
.review-gaps .g-not_applied .gap-tag{background:var(--red)}
.review-gaps .g-applied_adjusted .gap-tag{background:var(--amber)}
.review-gaps .gap-note{font-size:13px;color:var(--text);margin:4px 0 0;line-height:1.5}
.review-gaps .gap-note.faint{color:var(--faint)}
