:root{
  --paper:#f4f6f9;
  --card:#ffffff;
  --card-2:#eef1f6;
  --line:#d6dde6;
  --line-soft:#e4e9ef;
  --ink:#101823;
  --ink-2:#33404f;
  --muted:#5c6875;
  --faint:#8a95a2;
  --accent:#0f6c8c;
  --accent-deep:#094f66;
  --accent-wash:#e3eef3;
  --crit:#b3402f;
  --crit-wash:#f7e7e3;
  --warn:#a06a12;
  --warn-wash:#f8efdd;
  --ok:#3c7a52;
  --ok-wash:#e5efe8;
  --p1:#b3402f;
  --p2:#a06a12;
  --p3:#0f6c8c;
  --p4:#9aa5b1;
  --shadow:0 1px 2px rgba(16,24,35,.06),0 6px 18px rgba(16,24,35,.06);
  --shadow-lg:0 12px 40px rgba(16,24,35,.18);
  --r:3px;
  --font-ui:"Archivo",system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  --font-mono:"IBM Plex Mono",ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
}
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){
    --paper:#0d1219;
    --card:#141c26;
    --card-2:#1a232f;
    --line:#28323f;
    --line-soft:#1f2833;
    --ink:#e4eaf1;
    --ink-2:#c3cdd9;
    --muted:#94a2b2;
    --faint:#6d7c8c;
    --accent:#4fb6d4;
    --accent-deep:#7fcde4;
    --accent-wash:#12303c;
    --crit:#f08a75;
    --crit-wash:#3a201b;
    --warn:#e5a94a;
    --warn-wash:#372a12;
    --ok:#7dbf92;
    --ok-wash:#1b2f22;
    --p1:#f08a75;
    --p2:#e5a94a;
    --p3:#4fb6d4;
    --p4:#67737f;
    --shadow:0 1px 2px rgba(0,0,0,.4),0 6px 18px rgba(0,0,0,.35);
    --shadow-lg:0 12px 40px rgba(0,0,0,.55);
  }
}
:root[data-theme="dark"]{
  --paper:#0d1219;
  --card:#141c26;
  --card-2:#1a232f;
  --line:#28323f;
  --line-soft:#1f2833;
  --ink:#e4eaf1;
  --ink-2:#c3cdd9;
  --muted:#94a2b2;
  --faint:#6d7c8c;
  --accent:#4fb6d4;
  --accent-deep:#7fcde4;
  --accent-wash:#12303c;
  --crit:#f08a75;
  --crit-wash:#3a201b;
  --warn:#e5a94a;
  --warn-wash:#372a12;
  --ok:#7dbf92;
  --ok-wash:#1b2f22;
  --p1:#f08a75;
  --p2:#e5a94a;
  --p3:#4fb6d4;
  --p4:#67737f;
  --shadow:0 1px 2px rgba(0,0,0,.4),0 6px 18px rgba(0,0,0,.35);
  --shadow-lg:0 12px 40px rgba(0,0,0,.55);
}

*{box-sizing:border-box}
html,body{margin:0;padding:0}
body{
  background:var(--paper);
  color:var(--ink);
  font-family:var(--font-ui);
  font-size:15px;
  line-height:1.5;
  -webkit-font-smoothing:antialiased;
}
button,input,select,textarea{font:inherit;color:inherit}
button{cursor:pointer;background:none;border:none;padding:0}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:2px}
.mono{font-family:var(--font-mono);font-variant-numeric:tabular-nums}
.vis-hidden{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* ---------- shell ---------- */
.app{min-height:100vh;display:flex;flex-direction:column}

.topbar{
  position:sticky;top:0;z-index:40;
  display:flex;align-items:center;gap:14px;
  padding:10px 18px;
  background:var(--card);
  border-bottom:1px solid var(--line);
}
.brand{display:flex;align-items:baseline;gap:9px;flex:0 0 auto}
.brand-mark{
  font-family:var(--font-mono);font-weight:600;font-size:11px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--card);background:var(--accent);
  padding:4px 7px;border-radius:2px;
}
.brand-name{font-weight:700;font-size:15px;letter-spacing:-.01em}
.search-wrap{position:relative;flex:1 1 auto;max-width:400px}
.search{
  width:100%;padding:7px 10px 7px 30px;
  background:var(--paper);border:1px solid var(--line);border-radius:var(--r);
  font-size:13.5px;
}
.search::placeholder{color:var(--faint)}
.search-icon{position:absolute;left:9px;top:50%;transform:translateY(-50%);color:var(--faint);pointer-events:none;display:flex}
.topbar-spacer{flex:1 1 auto}
.top-actions{display:flex;align-items:center;gap:8px;flex:0 0 auto}

.btn{
  display:inline-flex;align-items:center;gap:6px;
  padding:7px 12px;border:1px solid var(--line);border-radius:var(--r);
  background:var(--card);color:var(--ink-2);
  font-size:13px;font-weight:500;white-space:nowrap;
  transition:background .12s,border-color .12s,color .12s;
}
.btn:hover:not(:disabled){background:var(--card-2);border-color:var(--muted)}
.btn:disabled{opacity:.45;cursor:not-allowed}
.btn-primary{background:var(--accent);border-color:var(--accent);color:#fff}
.btn-primary:hover:not(:disabled){background:var(--accent-deep);border-color:var(--accent-deep);color:#fff}
:root[data-theme="dark"] .btn-primary,
:root[data-theme="dark"] .btn-primary:hover:not(:disabled){color:#0d1219}
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]) .btn-primary,
  :root:not([data-theme="light"]) .btn-primary:hover:not(:disabled){color:#0d1219}
}
.btn-ghost{border-color:transparent;background:transparent}
.btn-ghost:hover:not(:disabled){background:var(--card-2)}
.btn-danger{color:var(--crit);border-color:var(--line)}
.btn-danger:hover:not(:disabled){background:var(--crit-wash);border-color:var(--crit)}
.btn-sm{padding:4px 9px;font-size:12px}

.savestate{
  font-family:var(--font-mono);font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;
  color:var(--faint);display:flex;align-items:center;gap:6px;white-space:nowrap;
}
.savedot{width:6px;height:6px;border-radius:50%;background:var(--faint);flex:0 0 auto}
.savestate[data-s="saved"] .savedot{background:var(--ok)}
.savestate[data-s="saving"] .savedot,.savestate[data-s="pending"] .savedot{background:var(--warn)}
.savestate[data-s="error"] .savedot,.savestate[data-s="readonly"] .savedot{background:var(--crit)}
.savestate[data-s="saving"] .savedot{animation:pulse 1s ease-in-out infinite}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.3}}
@media (prefers-reduced-motion: reduce){.savestate .savedot{animation:none}}

.body{display:flex;align-items:flex-start;flex:1 1 auto;min-height:0}

/* ---------- rail ---------- */
.rail{
  flex:0 0 216px;width:216px;
  position:sticky;top:53px;align-self:flex-start;
  /* A column, and as tall as the window: the sync panel is the rail's footer
     and rides `margin-top:auto` down to the bottom. Without the min-height it
     would sit directly under the report figures on a short board, which reads
     as one more report rather than as the state of the app. */
  display:flex;flex-direction:column;
  height:calc(100vh - 53px);
  padding:16px 10px 8px;
  border-right:1px solid var(--line);
}
/* Only the groups scroll. The sync panel is the rail's footer and stays put. */
.rail-scroll{flex:1 1 auto;min-height:0;overflow-y:auto}
.rail-group+.rail-group{margin-top:20px}
.rail-title{
  font-size:10px;font-weight:600;letter-spacing:.13em;text-transform:uppercase;
  color:var(--faint);padding:0 8px;margin:0 0 6px;
}
.rail-item{
  width:100%;display:flex;align-items:center;gap:8px;
  padding:6px 8px 6px 10px;border-radius:var(--r);
  font-size:13.5px;color:var(--ink-2);text-align:left;
  position:relative;
}
.rail-item:hover{background:var(--card-2)}
.rail-item[aria-current="true"]{background:var(--accent-wash);color:var(--ink);font-weight:600}
.rail-item[aria-current="true"]::before{
  content:"";position:absolute;left:0;top:5px;bottom:5px;width:3px;
  background:var(--accent);border-radius:0 2px 2px 0;
}
.rail-label{flex:1 1 auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rail-count{
  font-family:var(--font-mono);font-size:11px;font-variant-numeric:tabular-nums;
  color:var(--faint);flex:0 0 auto;
}
.rail-item[aria-current="true"] .rail-count{color:var(--accent)}
.rail-count.alert{color:var(--crit);font-weight:600}

/* ---------- main ---------- */
/* The 1080px cap is a readability decision, not an accident: Fireflies writes
   sentence-length action items, and a line the full width of a 27" display is
   genuinely hard to scan back across. It is a default rather than a rule —
   `.body.wide` lifts it, and the toggle is in the top bar. */
.main{flex:1 1 auto;min-width:0;padding:18px 22px 80px;max-width:1080px}
.body.wide > .main{max-width:none}
/* With the rail hidden the column would otherwise sit hard against the left
   edge of the window; centring it keeps the board where the eye already is. */
.body:not(.wide) > .main:only-child{margin-inline:auto}
.viewhead{display:flex;align-items:flex-end;gap:14px;flex-wrap:wrap;margin-bottom:4px}
.viewtitle{font-size:22px;font-weight:700;letter-spacing:-.02em;margin:0;text-wrap:balance}
.viewsub{font-family:var(--font-mono);font-size:11.5px;color:var(--muted);margin:0 0 3px}
.viewtools{margin-left:auto;display:flex;align-items:center;gap:8px;padding-bottom:2px}
.sel{
  padding:5px 8px;border:1px solid var(--line);border-radius:var(--r);
  background:var(--card);font-size:12.5px;color:var(--ink-2);
}

/* stat row */
.stats{display:flex;gap:8px;flex-wrap:wrap;margin:16px 0 18px}
.stat{
  flex:1 1 130px;min-width:120px;
  border:1px solid var(--line);border-left:3px solid var(--line);
  border-radius:var(--r);background:var(--card);padding:9px 12px;
}
.stat-k{font-size:9.5px;font-weight:600;letter-spacing:.13em;text-transform:uppercase;color:var(--faint)}
.stat-v{font-family:var(--font-mono);font-size:22px;font-weight:600;line-height:1.25;font-variant-numeric:tabular-nums}
.stat-n{font-family:var(--font-mono);font-size:10.5px;color:var(--muted)}
.stat.crit{border-left-color:var(--crit)}.stat.crit .stat-v{color:var(--crit)}
.stat.warn{border-left-color:var(--warn)}.stat.warn .stat-v{color:var(--warn)}
.stat.ok{border-left-color:var(--ok)}.stat.ok .stat-v{color:var(--ok)}
.stat.acc{border-left-color:var(--accent)}

/* quick add */
.qa{
  display:flex;align-items:center;gap:8px;
  border:1px solid var(--line);border-radius:var(--r);background:var(--card);
  padding:6px 8px 6px 12px;margin-bottom:18px;box-shadow:var(--shadow);
}
.qa-input{flex:1 1 auto;border:none;background:none;padding:5px 0;font-size:14.5px;min-width:0}
.qa-input::placeholder{color:var(--faint)}
.qa-hint{font-family:var(--font-mono);font-size:10px;color:var(--faint);letter-spacing:.06em;white-space:nowrap}

/* section */
.section{margin-bottom:26px}
.section-head{
  display:flex;align-items:center;gap:10px;margin-bottom:8px;
  padding-bottom:5px;border-bottom:1px solid var(--line-soft);
}
.section-name{font-size:10.5px;font-weight:600;letter-spacing:.13em;text-transform:uppercase;color:var(--muted)}
.section-count{font-family:var(--font-mono);font-size:10.5px;color:var(--faint)}
.section-rule{flex:1 1 auto}

/* strip */
.strips{display:flex;flex-direction:column;gap:5px}
.strip{
  display:grid;grid-template-columns:auto 1fr auto;align-items:start;gap:10px;
  background:var(--card);border:1px solid var(--line);border-left-width:3px;
  border-radius:var(--r);padding:9px 11px 9px 10px;
  transition:border-color .12s,box-shadow .12s,transform .12s;
  position:relative;
}
.strip:hover{box-shadow:var(--shadow);border-color:var(--muted)}
.strip[data-p="1"]{border-left-color:var(--p1)}
.strip[data-p="2"]{border-left-color:var(--p2)}
.strip[data-p="3"]{border-left-color:var(--p3)}
.strip[data-p="4"]{border-left-color:var(--p4)}
.strip[data-done="true"]{opacity:.6}
.strip[data-done="true"] .strip-title{text-decoration:line-through;text-decoration-color:var(--faint)}
.strip.dragging{opacity:.4}
.strip.drop-before{box-shadow:0 -2px 0 0 var(--accent)}
.strip.drop-after{box-shadow:0 2px 0 0 var(--accent)}

.strip-lead{display:flex;align-items:center;gap:7px;padding-top:1px}
.drag{
  color:var(--faint);cursor:grab;display:none;padding:2px 0;line-height:0;
}
.drag:active{cursor:grabbing}
.sortable .drag{display:block}
.tick{
  width:17px;height:17px;flex:0 0 auto;border:1.5px solid var(--line);border-radius:2px;
  background:var(--paper);display:flex;align-items:center;justify-content:center;
  transition:background .12s,border-color .12s;
}
.tick:hover{border-color:var(--accent)}
.tick svg{opacity:0;color:#fff}
.strip[data-done="true"] .tick{background:var(--ok);border-color:var(--ok)}
.strip[data-done="true"] .tick svg{opacity:1}

.strip-body{min-width:0;cursor:pointer}
.strip-title{
  font-size:14.5px;line-height:1.4;margin:0;
  overflow-wrap:anywhere;
  display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;
}
.strip-steps{display:flex;flex-direction:column;gap:3px;margin:5px 0 0}
.strip-step{
  display:flex;align-items:baseline;gap:6px;margin:0;
  font-size:13px;line-height:1.45;color:var(--ink-2);overflow-wrap:anywhere;
}
.strip-step[data-done="true"]{color:var(--muted);font-size:12.5px}
.strip-step[data-done="true"] .step-text{
  text-decoration:line-through;text-decoration-color:var(--faint);
}
.step-tick{
  width:13px;height:13px;flex:0 0 auto;position:relative;top:2px;
  border:1.5px solid var(--line);border-radius:2px;background:var(--paper);
  display:flex;align-items:center;justify-content:center;
  transition:background .12s,border-color .12s;
}
.step-tick:hover:not(:disabled){border-color:var(--accent)}
.step-tick svg{opacity:0;color:#fff}
.strip-step[data-done="true"] .step-tick{background:var(--ok);border-color:var(--ok)}
.strip-step[data-done="true"] .step-tick svg{opacity:1}
.step-text{flex:1 1 auto;min-width:0}
.step-when{font-size:10px;color:var(--faint);white-space:nowrap;flex:0 0 auto}
.step-more{
  margin:2px 0 0;font-family:var(--font-mono);font-size:10px;color:var(--faint);
}

.strip-next{
  display:flex;align-items:baseline;gap:6px;margin:5px 0 0;
  font-size:13px;line-height:1.45;color:var(--ink-2);overflow-wrap:anywhere;
}
.next-tag,.done-tag{
  font-family:var(--font-mono);font-size:9px;font-weight:600;letter-spacing:.1em;
  border-radius:2px;padding:0 4px;flex:0 0 auto;position:relative;top:-1px;
}
.next-tag{color:var(--accent);border:1px solid var(--accent)}
/* Completed steps state their status too, rather than relying on the
   strikethrough alone — the same weight of label as NEXT, in the done colour. */
.done-tag{color:var(--ok);border:1px solid var(--ok)}
.next-when{
  font-size:10px;color:var(--faint);white-space:nowrap;flex:0 0 auto;
}

/* next-action list in the drawer */
.acts{
  display:flex;flex-direction:column;gap:1px;background:var(--line-soft);
  border:1px solid var(--line);border-radius:var(--r);overflow:hidden;margin-bottom:9px;
}
/* tick · body · note · delete. The note marker is optional, so the row is laid
   out as flex rather than a fixed grid — a four-column grid wrapped the delete
   button onto a line of its own on any sub-task without a note. */
.act{
  display:flex;gap:9px;align-items:flex-start;
  background:var(--card);padding:8px 10px;
}
.act>.act-body{flex:1 1 auto;min-width:0}
.act-tick{
  width:15px;height:15px;flex:0 0 auto;margin-top:2px;
  border:1.5px solid var(--line);border-radius:2px;background:var(--paper);
  display:flex;align-items:center;justify-content:center;
  transition:background .12s,border-color .12s;
}
.act-tick:hover:not(:disabled){border-color:var(--accent)}
.act-tick svg{opacity:0;color:#fff}
.act[data-done="true"] .act-tick{background:var(--ok);border-color:var(--ok)}
.act[data-done="true"] .act-tick svg{opacity:1}
.act-body{min-width:0;display:flex;flex-direction:column;gap:2px}
.act-text{font-size:13.5px;line-height:1.45;overflow-wrap:anywhere}
.act[data-done="true"] .act-text{
  text-decoration:line-through;text-decoration-color:var(--faint);color:var(--muted);
}
.act-meta{font-size:10px;color:var(--faint);letter-spacing:.02em}
.act-del{
  color:var(--faint);flex:0 0 auto;padding:2px;line-height:0;border-radius:2px;
  transition:color .12s,background .12s;
}
.act-del:hover:not(:disabled){color:var(--crit);background:var(--crit-wash)}
.act-add{display:flex;gap:6px;align-items:center}
.act-input{flex:1 1 auto;min-width:0}
.act-owner{flex:0 0 76px;min-width:0;font-size:12.5px}
.act-empty{margin:0;font-size:12.5px;color:var(--faint)}

.strip-meta{
  display:flex;align-items:center;gap:7px;flex-wrap:wrap;margin-top:4px;
  font-family:var(--font-mono);font-size:10.5px;color:var(--faint);letter-spacing:.02em;
}
.strip-meta .sep{opacity:.5}
.strip-meta a{color:var(--muted);text-decoration:none;border-bottom:1px solid var(--line)}
.strip-meta a:hover{color:var(--accent);border-bottom-color:var(--accent)}
.tag{
  font-family:var(--font-mono);font-size:10px;padding:1px 5px;border-radius:2px;
  background:var(--card-2);color:var(--muted);border:1px solid var(--line-soft);
}
.strip-tail{display:flex;align-items:center;gap:7px;flex:0 0 auto;padding-top:1px}

.pill{
  font-family:var(--font-mono);font-size:10px;font-weight:500;letter-spacing:.06em;
  text-transform:uppercase;padding:2px 6px;border-radius:2px;white-space:nowrap;
  border:1px solid transparent;
}
.pill.crit{background:var(--crit-wash);color:var(--crit);border-color:var(--crit)}
.pill.warn{background:var(--warn-wash);color:var(--warn);border-color:var(--warn)}
.pill.calm{background:var(--card-2);color:var(--muted);border-color:var(--line-soft)}
.pill.ok{background:var(--ok-wash);color:var(--ok);border-color:var(--ok)}
.pill.acc{background:var(--accent-wash);color:var(--accent);border-color:var(--accent)}
.pflag{
  font-family:var(--font-mono);font-size:10px;font-weight:600;
  padding:2px 5px;border-radius:2px;border:1px solid var(--line-soft);background:var(--card-2);
}
.pflag[data-p="1"]{color:var(--p1)}
.pflag[data-p="2"]{color:var(--p2)}
.pflag[data-p="3"]{color:var(--p3)}
.pflag[data-p="4"]{color:var(--p4)}

/* empty */
.empty{
  border:1px dashed var(--line);border-radius:var(--r);
  padding:34px 26px;text-align:center;color:var(--muted);background:var(--card);
}
.empty h3{margin:0 0 6px;font-size:15px;color:var(--ink);font-weight:600}
.empty p{margin:0 auto;max-width:46ch;font-size:13.5px;line-height:1.6}
.empty .btn{margin-top:16px}

/* first run */
.firstrun{border:1px solid var(--line);border-radius:var(--r);background:var(--card);padding:22px;box-shadow:var(--shadow)}
.firstrun h2{margin:0 0 4px;font-size:17px;font-weight:700;letter-spacing:-.01em}
.firstrun>p{margin:0 0 18px;color:var(--muted);font-size:13.5px;max-width:62ch}
.srcgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:10px;margin-bottom:18px}
.src{border:1px solid var(--line-soft);border-left:3px solid var(--accent);border-radius:var(--r);padding:11px 13px;background:var(--paper)}
.src[data-off="true"]{border-left-color:var(--p4);opacity:.72}
.src h4{margin:0 0 3px;font-size:12.5px;font-weight:600}
.src p{margin:0;font-size:11.5px;color:var(--muted);line-height:1.5}
.src .pill{margin-top:7px;display:inline-block}

/* inbox candidates */
.cand{
  display:grid;grid-template-columns:auto 1fr auto;gap:11px;align-items:start;
  background:var(--card);border:1px solid var(--line);border-left:3px solid var(--accent);
  border-radius:var(--r);padding:11px 12px;
}
.cand[data-sel="false"]{border-left-color:var(--p4);opacity:.62}
.cand-title{width:100%;border:none;background:none;font-size:14.5px;padding:0;line-height:1.4}
.cand-title:focus{outline:none;border-bottom:1px solid var(--accent)}
.cand-why{margin:5px 0 0;font-size:12px;color:var(--muted);line-height:1.5;overflow-wrap:anywhere}
.cand-meta{display:flex;gap:7px;align-items:center;flex-wrap:wrap;margin-top:6px;font-family:var(--font-mono);font-size:10.5px;color:var(--faint)}
.cand-meta a{color:var(--muted)}
.inbox-bar{
  display:flex;align-items:center;gap:9px;flex-wrap:wrap;
  padding:11px 13px;background:var(--accent-wash);border:1px solid var(--accent);
  border-radius:var(--r);margin-bottom:14px;
}
.inbox-bar p{margin:0;font-size:13px;flex:1 1 auto;min-width:180px}
.chk{width:16px;height:16px;accent-color:var(--accent);margin-top:3px;flex:0 0 auto}

/* progress */
.progress{height:2px;background:var(--line-soft);border-radius:2px;overflow:hidden;margin-bottom:14px}
.progress i{display:block;height:100%;background:var(--accent);transition:width .3s ease;width:0}
.pulling{
  display:flex;align-items:center;gap:9px;font-family:var(--font-mono);
  font-size:11.5px;color:var(--muted);margin-bottom:8px;
}
.spinner{
  width:11px;height:11px;border:2px solid var(--line);border-top-color:var(--accent);
  border-radius:50%;animation:spin .7s linear infinite;flex:0 0 auto;
}
@keyframes spin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion: reduce){.spinner{animation-duration:2.4s}.progress i{transition:none}}

/* drawer */
.scrim{
  position:fixed;inset:0;background:rgba(16,24,35,.42);z-index:60;
  opacity:0;pointer-events:none;transition:opacity .18s;
}
.scrim.open{opacity:1;pointer-events:auto}
/* The task modal.
 *
 * Centred and 940px, not a 440px panel down the right edge. The width is what
 * the content needs: a Fireflies sub-task title is a full sentence, and at
 * 440px it wrapped to three lines while the properties stacked into a narrow
 * ladder beside it.
 *
 * Height is capped at 88vh with the COLUMNS scrolling, not the page, so the
 * header and the Close/Delete row stay put however long the notes are. */
.taskmodal{
  position:fixed;inset:0;margin:auto;z-index:61;
  width:min(940px,calc(100vw - 40px));max-height:88vh;height:max-content;
  background:var(--card);border:1px solid var(--line);border-radius:10px;
  box-shadow:var(--shadow-lg);
  opacity:0;visibility:hidden;transform:translateY(8px) scale(.99);
  transition:opacity .15s ease,transform .15s cubic-bezier(.2,.8,.3,1),visibility 0s linear .15s;
  display:flex;flex-direction:column;overflow:hidden;
}
.taskmodal.open{
  opacity:1;visibility:visible;transform:none;
  transition:opacity .15s ease,transform .15s cubic-bezier(.2,.8,.3,1),visibility 0s;
}
@media (prefers-reduced-motion: reduce){.taskmodal,.scrim{transition:none}}

.tm-head{display:flex;align-items:center;gap:10px;padding:13px 18px;border-bottom:1px solid var(--line)}
.tm-eyebrow{font-family:var(--font-mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--faint);flex:1 1 auto}
.tm-foot{padding:11px 18px;border-top:1px solid var(--line);display:flex;gap:8px;align-items:center}

/* Two columns: what you read and edit on the left, what you set on the right.
   Each scrolls on its own, so a long note does not push the properties out of
   reach and a long sub-task list does not drag the notes with it. */
/* The title, spanning both columns. Full width in either layout, and always
   the first thing on the page. */
.tm-title{padding:16px 20px 0;flex:0 0 auto}
.tm-title .ta-title{margin:0}

.tm-cols{display:flex;flex:1 1 auto;min-height:0}
.tm-main{flex:1 1 auto;min-width:0;overflow-y:auto;padding:14px 20px 24px}
.tm-side{
  flex:0 0 320px;width:320px;overflow-y:auto;
  padding:14px 20px 24px;
  border-left:1px solid var(--line);background:var(--paper);
}

/* The properties were a label-beside-control table built for a 440px drawer.
   In a rail they lose 74px to the label column, which is enough to push the
   due-date shortcuts onto two lines and clip "Clear" off the edge. So in the
   rail the label goes ABOVE its control and the control gets the full width. */
.tm-side .props{padding:10px 10px;background:var(--card)}
.tm-side .prop{
  display:block;min-height:0;padding:5px 0;
}
.tm-side .prop + .prop{border-top:1px solid var(--line-soft)}
.tm-side .prop-label{display:block;margin-bottom:4px}
.tm-side .prop-control{flex-wrap:wrap;gap:5px}
/* The four due shortcuts share a line rather than each claiming a whole one. */
.tm-side .prop-control .seg{width:100%}
.tm-side .prop-control .inp{width:100%}
.tm-meta{font-size:10.5px;color:var(--faint);margin:16px 0 0;line-height:1.6}

/* Under 900px there is no room for two, so they stack — properties FIRST,
   because on a narrow window status and priority are what you came for. */
@media (max-width: 900px){
  .tm-cols{flex-direction:column}
  .tm-main,.tm-side{
    flex:0 0 auto;width:auto;overflow-y:visible;
    border-left:none;background:none;
  }
  .tm-side{order:-1;border-bottom:1px solid var(--line);background:var(--paper)}
  /* One scroller instead of two, or neither can reach its end. */
  .tm-cols{overflow-y:auto}
}
.field{margin-bottom:15px}
.field>label{display:block;font-size:10px;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--faint);margin-bottom:5px}
.inp,.ta{
  width:100%;padding:8px 10px;background:var(--paper);
  border:1px solid var(--line);border-radius:var(--r);font-size:14px;
}
.ta{resize:vertical;min-height:90px;line-height:1.55;font-size:13.5px}
.inp:focus,.ta:focus{border-color:var(--accent);outline:none}
.seg{display:flex;gap:4px;flex-wrap:wrap}
.seg button{
  flex:1 1 auto;padding:6px 4px;border:1px solid var(--line);border-radius:var(--r);
  background:var(--paper);font-size:12px;font-weight:500;color:var(--muted);
}
.seg button[aria-pressed="true"]{background:var(--accent);border-color:var(--accent);color:#fff}
:root[data-theme="dark"] .seg button[aria-pressed="true"]{color:#0d1219}
@media (prefers-color-scheme: dark){:root:not([data-theme="light"]) .seg button[aria-pressed="true"]{color:#0d1219}}
.seg.pri button[aria-pressed="true"][data-p="1"]{background:var(--p1);border-color:var(--p1)}
.seg.pri button[aria-pressed="true"][data-p="2"]{background:var(--p2);border-color:var(--p2)}
.seg.pri button[aria-pressed="true"][data-p="3"]{background:var(--p3);border-color:var(--p3)}
.seg.pri button[aria-pressed="true"][data-p="4"]{background:var(--p4);border-color:var(--p4)}
.evidence{
  background:var(--paper);border:1px solid var(--line-soft);border-radius:var(--r);
  padding:10px 11px;font-size:12.5px;color:var(--muted);line-height:1.55;
  max-height:200px;overflow-y:auto;overflow-wrap:anywhere;
}

/* modal */
.modal{
  position:fixed;z-index:62;top:50%;left:50%;transform:translate(-50%,-50%);
  width:min(460px,calc(100% - 32px));max-height:calc(100vh - 48px);overflow-y:auto;
  background:var(--card);border:1px solid var(--line);border-radius:var(--r);
  box-shadow:var(--shadow-lg);padding:20px;
}
.modal h2{margin:0 0 5px;font-size:16px;font-weight:700}
.modal>p{margin:0 0 16px;font-size:13px;color:var(--muted);line-height:1.55}
.modal-foot{display:flex;gap:8px;justify-content:flex-end;margin-top:18px;flex-wrap:wrap}
.row2{display:grid;grid-template-columns:1fr 1fr;gap:11px}

/* ---------------- settings ----------------
 *
 * Wider than the generic modal, because it is not a generic modal. 460px is
 * right for a confirmation with two buttons; Settings carries sources,
 * connected machines, downloads, the lock, the address book and the version —
 * paragraphs of explanation, side-by-side inputs, and a redirect URI that was
 * breaking mid-word ("callbac / k"). The same mistake as the 440px task
 * drawer, in the same direction.
 *
 * Sections are separated by a rule rather than by spacing alone: at this
 * length, whitespace stops being read as structure and the whole thing becomes
 * a wall. */
.modal-settings{
  width:min(820px,calc(100% - 40px));
  padding:26px 28px 24px
}
.modal-settings > h2{
  font-size:12px;font-weight:700;letter-spacing:.11em;text-transform:uppercase;
  color:var(--faint);margin:0 0 14px
}
.modal-settings .field{
  padding-top:20px;margin-top:20px;border-top:1px solid var(--line-soft)
}
.modal-settings .field:first-of-type{border-top:0;padding-top:0;margin-top:0}
.modal-settings .field > h2{
  font-size:15px;font-weight:700;color:var(--ink);margin:0 0 8px;
  letter-spacing:normal;text-transform:none
}
.modal-settings .field > label{
  display:block;font-size:12px;font-weight:700;letter-spacing:.09em;
  text-transform:uppercase;color:var(--faint);margin:0 0 8px
}
.modal-settings .field > p{max-width:64ch;line-height:1.55}

/* Long single tokens — a redirect URI, a connection string. `break-all` split
   words wherever the line happened to end; this breaks only when there is no
   alternative, and gives them room to avoid needing to. */
.redirect-uri,.dev-token-value{
  overflow-wrap:anywhere;word-break:normal;line-height:1.5
}

/* Side-by-side inputs stop being side-by-side before they become unusable
   rather than after. */
.modal-settings .act-add{flex-wrap:wrap;gap:8px}
.modal-settings .act-add .inp{min-width:220px;flex:1 1 220px}

@media (max-width: 700px){
  .modal-settings{padding:20px 18px}
  .modal-settings .act-add .inp{min-width:0;flex:1 1 100%}
}


/* toasts */
.toasts{position:fixed;right:16px;bottom:16px;z-index:80;display:flex;flex-direction:column;gap:7px;max-width:340px}
.toast{
  background:var(--card);border:1px solid var(--line);border-left:3px solid var(--accent);
  border-radius:var(--r);padding:9px 12px;font-size:13px;box-shadow:var(--shadow);
  animation:slidein .2s ease;
}
.toast.err{border-left-color:var(--crit)}
.toast.ok{border-left-color:var(--ok)}
@keyframes slidein{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion: reduce){.toast{animation:none}}

.banner{
  display:flex;gap:9px;align-items:center;flex-wrap:wrap;
  padding:9px 14px;background:var(--warn-wash);border-bottom:1px solid var(--warn);
  font-size:13px;color:var(--ink-2);
}

@media (max-width:860px){
  .body{flex-direction:column}
  /* The rail becomes a horizontal scroller here. As a flex item its default
     min-width:auto would size it to its content and push the page sideways,
     so pin it to the viewport and let overflow-x do the work. */
  .rail{
    position:static;flex:0 0 auto;width:100%;min-width:0;max-width:100%;max-height:none;
    border-right:none;border-bottom:1px solid var(--line);
    display:flex;gap:6px;overflow-x:auto;padding:9px 12px;
  }
  .rail-group{display:flex;gap:6px;align-items:center;flex:0 0 auto}
  .rail-group+.rail-group{margin-top:0;padding-left:6px;border-left:1px solid var(--line-soft)}
  .rail-title{display:none}
  .rail-item{width:auto;white-space:nowrap;padding:5px 10px}
  .rail-item[aria-current="true"]::before{display:none}
  .main{padding:14px 14px 70px}
  .row2{grid-template-columns:1fr}
  .search-wrap{max-width:none}
}
@media (max-width:600px){
  .brand-name{display:none}
  .stat{flex-basis:calc(50% - 4px)}
}

/* ---------- sign-in ---------- */
.signin-wrap{min-height:100vh;display:flex;align-items:center;justify-content:center;padding:24px}
.signin{
  width:min(420px,100%);background:var(--card);border:1px solid var(--line);
  border-radius:var(--r);box-shadow:var(--shadow);padding:30px 28px;
}
.signin .brand-mark{display:inline-block;margin-bottom:16px}
.signin h1{margin:0 0 6px;font-size:21px;font-weight:700;letter-spacing:-.02em}
.signin p{margin:0 0 22px;color:var(--muted);font-size:13.5px;line-height:1.6}
.signin .btn{width:100%;justify-content:center;padding:10px}
.signin-foot{
  margin-top:18px;padding-top:14px;border-top:1px solid var(--line-soft);
  font-family:var(--font-mono);font-size:10.5px;color:var(--faint);line-height:1.6;
}
.ms-logo{width:15px;height:15px;flex:0 0 auto}

/* ---------- history ---------- */
.hist{display:flex;flex-direction:column;gap:1px;background:var(--line-soft);
  border:1px solid var(--line);border-radius:var(--r);overflow:hidden}
.hist-row{
  display:grid;grid-template-columns:auto 1fr auto;gap:11px;align-items:baseline;
  background:var(--card);padding:9px 12px;font-size:13px;
}
.hist-when{font-family:var(--font-mono);font-size:10.5px;color:var(--faint);white-space:nowrap}
.hist-what strong{font-weight:600}
.hist-diff{font-family:var(--font-mono);font-size:11px;color:var(--muted);overflow-wrap:anywhere}
.hist-diff del{color:var(--crit);text-decoration:line-through;opacity:.8}
.hist-diff ins{color:var(--ok);text-decoration:none}
.hist-actor{
  font-family:var(--font-mono);font-size:9.5px;letter-spacing:.08em;text-transform:uppercase;
  padding:1px 5px;border-radius:2px;border:1px solid var(--line-soft);
  background:var(--card-2);color:var(--muted);white-space:nowrap;
}
.hist-actor[data-a="agent"]{color:var(--accent);border-color:var(--accent)}
.offline{
  background:var(--crit-wash);border-bottom:1px solid var(--crit);
  padding:8px 14px;font-size:13px;color:var(--ink-2);
}

/* ---------- sub-tasks ---------- */
/* Indented and a shade quieter, so the parent still reads as the unit of work
   and the children as its parts. */
.strip-child{
  margin-left:26px;
  border-left-width:2px;
  background:var(--card);
}
.strip-child .strip-title{font-size:13.5px}
.strip-child::before{
  content:"";position:absolute;left:-14px;top:-4px;bottom:50%;
  border-left:1px solid var(--line);border-bottom:1px solid var(--line);
  width:11px;border-bottom-left-radius:4px;
}
.kidcount{
  margin:4px 0 0;font-size:10.5px;color:var(--accent);
}
.under{color:var(--muted)}

.subadd{margin:2px 0 2px 26px}
.subadd-input{
  width:100%;padding:4px 8px;border:1px dashed transparent;border-radius:var(--r);
  background:transparent;font-size:12.5px;color:var(--muted);
  transition:border-color .12s,background .12s;
}
.subadd-input::placeholder{color:var(--faint)}
.subadd-input:hover{border-color:var(--line)}
.subadd-input:focus{
  border-color:var(--accent);border-style:solid;background:var(--card);
  color:var(--ink);outline:none;
}

/* ---------- dense list ---------- */
/* One task, one line. Everything that does not fit waits for the hover card. */
.rows{display:flex;flex-direction:column;gap:1px}
.rowgroup{display:flex;flex-direction:column}

.row{
  display:grid;grid-template-columns:auto auto minmax(0,1fr) auto auto;
  align-items:center;gap:10px;
  background:var(--card);border:1px solid var(--line);border-left-width:3px;
  border-radius:var(--r);padding:0 10px;height:34px;
  transition:background .1s,border-color .1s;
}
.row:hover{background:var(--card-2);border-color:var(--muted)}
.row[data-p="1"]{border-left-color:var(--p1)}
.row[data-p="2"]{border-left-color:var(--p2)}
.row[data-p="3"]{border-left-color:var(--p3)}
.row[data-p="4"]{border-left-color:var(--p4)}
.row[data-done="true"]{opacity:.55}
.row[data-done="true"] .row-title{text-decoration:line-through;text-decoration-color:var(--faint)}
.row-child{margin-left:22px}

/* ---------- dragging into order ---------- */
/* The grip appears on hover like delete does. It keeps its column when it is
   not shown, so rows do not shift sideways as the pointer crosses the list. */
.row-grip{
  width:12px;line-height:0;color:var(--faint);cursor:grab;
  opacity:0;transition:opacity .1s;
}
.row:hover .row-grip{opacity:1}
.row-grip:active{cursor:grabbing}
.row-grip-off{cursor:default}
.row:hover .row-grip-off{opacity:0}

.row[data-dragging="true"]{opacity:.4}

/* Where it will land. An inset line rather than a border, so the row does not
   change height as the marker moves between rows — a list that twitches by a
   pixel under the pointer is a list that is hard to aim at. */
.row.drop-before{box-shadow:inset 0 2px 0 0 var(--accent)}
.row.drop-after{box-shadow:inset 0 -2px 0 0 var(--accent)}

/* Parent breadcrumb, then title, sharing one cell of the row's grid. */
.row-main{display:flex;align-items:baseline;gap:6px;min-width:0}

/* Where a sub-task came from, read BEFORE its title. Quiet, and given a
   maximum so a long parent name cannot crowd out the thing it is labelling —
   the old chip cut every parent at 22 characters, which was fine for
   "Enviroserve" and useless for "2027 Budget Cycle – Procurement Planning". */
.row-parent{
  flex:0 1 auto;min-width:0;max-width:34%;
  display:flex;align-items:baseline;gap:4px;
  background:none;border:none;padding:0;font:inherit;font-size:12.5px;
  color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  cursor:pointer;
}
.row-parent:hover{color:var(--accent)}
.row-parent-count{font-size:10.5px;color:var(--faint);flex:0 0 auto}
.row-parent-sep{color:var(--faint);flex:0 0 auto}
.row-parent:hover .row-parent-sep{color:var(--accent)}

.row-title{
  min-width:0;flex:1 1 auto;text-align:left;padding:0;font-size:13.5px;color:var(--ink);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  background:none;border:none;
}
.row-title:hover{color:var(--accent)}

/* The row this card was opened from, inside its parent's list of children. */
.hc-list li[data-self="true"] .hc-sub-title{color:var(--ink);font-weight:600}

.row-badges{display:flex;gap:5px;align-items:center;flex:0 0 auto;overflow:hidden}
.chip{
  font-family:var(--font-mono);font-size:9.5px;letter-spacing:.02em;
  padding:1px 5px;border-radius:2px;white-space:nowrap;
  background:var(--card-2);color:var(--muted);border:1px solid var(--line-soft);
}
.chip-acc{color:var(--accent);border-color:var(--accent-wash);background:var(--accent-wash)}
.chip-quiet{color:var(--faint)}

.row-tail{display:flex;align-items:center;gap:6px;flex:0 0 auto}
.sel-p{padding:1px 4px;font-size:10.5px;font-family:var(--font-mono)}
.row-del{
  color:var(--faint);padding:2px;line-height:0;border-radius:2px;opacity:0;
  transition:opacity .1s,color .1s,background .1s;
}
.row:hover .row-del,.row-del:focus{opacity:1}
.row-del:hover{color:var(--crit);background:var(--crit-wash)}

/* Completing one task. Lives in the tail with the other things you DO to a
   row; the gutter box is how you PICK one. Revealed on hover like delete, but
   pinned on once the task is done, because "this is finished" is state the row
   has to keep showing when the pointer is somewhere else. */
.row-done{
  color:var(--faint);padding:2px;line-height:0;border-radius:2px;opacity:0;
  transition:opacity .1s,color .1s,background .1s;
}
.row:hover .row-done,.row-done:focus{opacity:1}
.row-done:hover{color:var(--ok);background:var(--ok-wash)}
.row-done.on{opacity:1;color:var(--ok)}

/* The gutter box SELECTS. Filled in the accent, not the green used for done —
   two different meanings must not share a colour. */
.row .tick{cursor:pointer}
.row .tick.on{background:var(--accent);border-color:var(--accent)}
.row .tick.on svg{opacity:1}
.row.picked{background:var(--accent-wash);border-color:var(--accent)}
.row.picked:hover{background:var(--accent-wash)}

/* the add-line only exists while you are pointing at the task */
.rowgroup .subadd{
  margin:0 0 0 22px;max-height:0;overflow:hidden;opacity:0;
  transition:max-height .12s,opacity .12s;
}
.rowgroup:hover .subadd,.rowgroup:focus-within .subadd{max-height:34px;opacity:1;margin:1px 0 1px 22px}
@media (prefers-reduced-motion: reduce){.rowgroup .subadd{transition:none}}

/* ---------- hover card ---------- */
/* The hover card.
 *
 * It restates a row, so it should look like that row rather than like a
 * generic panel that appeared nearby: the same priority stripe down the left,
 * the same coloured due pill, the same status vocabulary. Everything used to
 * be one weight of grey mono text, which is another way of saying nothing
 * stood out and the card read as a wall.
 */
.hovercard{
  /* max() floors it: in a zero-sized viewport — a collapsed pane, a print
     context — calc(100vw - 24px) goes negative and the card collapses to the
     width of its longest word. showHover() already defends its positioning
     arithmetic against exactly that case; this is the same guard for the
     width. */
  position:fixed;z-index:70;width:max(240px,min(430px,calc(100vw - 24px)));
  max-height:min(70vh,520px);overflow:hidden;
  background:var(--card);
  border:1px solid var(--line);border-left-width:3px;border-radius:8px;
  box-shadow:0 12px 32px -8px rgba(16,24,35,.28),0 2px 8px -2px rgba(16,24,35,.12);
  padding:13px 15px 11px;cursor:pointer;
  animation:hcfade .12s ease;
}
.hovercard[data-p="1"]{border-left-color:var(--p1)}
.hovercard[data-p="2"]{border-left-color:var(--p2)}
.hovercard[data-p="3"]{border-left-color:var(--p3)}
.hovercard[data-p="4"]{border-left-color:var(--p4)}
.hovercard[data-done="true"] .hc-title{color:var(--muted)}
@keyframes hcfade{from{opacity:0;transform:translateY(-3px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion: reduce){.hovercard{animation:none}}

.hc-title{
  margin:0 0 8px;font-size:14px;line-height:1.4;font-weight:650;
  letter-spacing:-.01em;overflow-wrap:anywhere;
}

/* Priority, status, due and project as marks rather than a run-on line. */
.hc-marks{display:flex;flex-wrap:wrap;gap:5px;align-items:center;margin:0 0 9px}
.hc-pri{
  font-family:var(--font-mono);font-size:10px;font-weight:600;letter-spacing:.04em;
  padding:2px 6px;border-radius:3px;color:#fff;
}
.hc-pri[data-p="1"]{background:var(--p1)}
.hc-pri[data-p="2"]{background:var(--p2)}
.hc-pri[data-p="3"]{background:var(--p3)}
.hc-pri[data-p="4"]{background:var(--p4)}
.hc-status{
  font-size:11px;padding:2px 7px;border-radius:3px;
  background:var(--card-2);color:var(--ink-2);border:1px solid var(--line-soft);
}
.hc-status[data-s="doing"]{background:var(--accent-wash);color:var(--accent-deep);border-color:transparent}
.hc-status[data-s="blocked"]{background:var(--crit-wash);color:var(--crit);border-color:transparent}
.hc-status[data-s="done"]{background:var(--ok-wash);color:var(--ok);border-color:transparent}
.hc-mark{font-family:var(--font-mono);font-size:10.5px;color:var(--muted)}

.hc-facts{margin:0 0 5px;font-size:11.5px;color:var(--muted);line-height:1.45}
.hc-head{
  margin:12px 0 5px;font-size:9.5px;font-weight:600;letter-spacing:.12em;
  text-transform:uppercase;color:var(--faint);
  padding-top:9px;border-top:1px solid var(--line-soft);
}
.hc-list{margin:0;padding:0;list-style:none;font-size:12.5px;line-height:1.5;color:var(--ink-2)}
.hc-list>li{margin:0 0 6px}
.hc-list>li:last-child{margin-bottom:0}

/* A checklist reads as a checklist. Struck-through text alone made a finished
   sub-task look like a mistake rather than like something achieved. */
.hc-box{
  flex:0 0 auto;width:13px;height:13px;margin-top:2px;
  border:1.5px solid var(--line);border-radius:2px;
  display:flex;align-items:center;justify-content:center;color:#fff;
}
.hc-list li[data-done="true"] .hc-box{background:var(--ok);border-color:var(--ok)}
.hc-sub{
  display:flex;gap:8px;align-items:flex-start;width:100%;text-align:left;
  background:none;border:none;padding:2px 3px;border-radius:4px;font:inherit;color:inherit;
}
.hc-sub:hover{background:var(--card-2)}
.hc-checks>li{display:flex;gap:8px;align-items:flex-start;padding:2px 3px}
.hc-sub-body{min-width:0;display:flex;flex-direction:column;gap:1px}
.hc-sub-title{font-size:12.5px;line-height:1.45;overflow-wrap:anywhere}
.hc-sub-meta{font-size:10px;color:var(--faint)}
.hc-sub-next{font-size:11px;color:var(--accent);overflow-wrap:anywhere}
.hc-list li[data-done="true"] .hc-sub-title{
  color:var(--muted);text-decoration:line-through;text-decoration-color:var(--line);
}

.hc-notes{
  margin:0;font-size:12.5px;color:var(--ink-2);line-height:1.55;overflow-wrap:anywhere;
  background:var(--paper);border-radius:5px;padding:8px 10px;
  max-height:96px;overflow:hidden;
}
.hc-src{margin:10px 0 0;font-size:10px;color:var(--faint);overflow-wrap:anywhere}
.hc-more{margin:5px 0 0;font-size:10px;color:var(--faint)}

.hc-open{
  display:flex;align-items:center;justify-content:space-between;
  margin:11px 0 0;padding-top:8px;border-top:1px solid var(--line-soft);
  font-size:10px;color:var(--faint);letter-spacing:.04em;
}
.hc-open-arrow{color:var(--accent);font-size:12px}
.hovercard:hover .hc-open{color:var(--muted)}

/* ---------------- attachments ----------------
   A file list has to stay quiet: it sits under the steps in a drawer that is
   already dense, so rows are 34px like the board's, and the drop target is a
   single dashed line rather than the usual large empty rectangle. */
.visually-hidden{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0
}
.files{display:flex;flex-direction:column;gap:4px;margin-bottom:8px}
.file{
  display:grid;grid-template-columns:26px minmax(0,1fr) auto auto;
  align-items:center;gap:8px;padding:4px 6px;border:1px solid var(--line-soft);
  border-radius:var(--r);background:var(--card)
}
.file[data-ready="false"]{opacity:.62}
.file-thumb{
  width:26px;height:26px;border-radius:2px;object-fit:cover;
  background:var(--card-2);border:1px solid var(--line-soft)
}
.file-thumb-generic{
  display:flex;align-items:center;justify-content:center;color:var(--faint)
}
.file-body{min-width:0;display:flex;flex-direction:column;gap:2px}
.file-name{
  font-size:12.5px;color:var(--ink);text-decoration:none;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap
}
a.file-name:hover{color:var(--accent);text-decoration:underline}
.file-meta{font-size:10px;color:var(--faint);letter-spacing:.02em}
.file-act{
  display:flex;align-items:center;justify-content:center;width:22px;height:22px;
  border:0;background:none;color:var(--faint);border-radius:2px;cursor:pointer
}
.file-act:hover{background:var(--card-2);color:var(--ink)}
.file-del:hover{color:var(--crit);background:var(--crit-wash)}

/* Progress, not a spinner: on a large file the difference between "working"
   and "37% of 240 MB" is the difference between waiting and force-quitting. */
.up-track{height:3px;border-radius:2px;background:var(--card-2);overflow:hidden}
.up-bar{display:block;height:100%;background:var(--accent);width:0;transition:width .15s linear}
@media (prefers-reduced-motion: reduce){.up-bar{transition:none}}

.dropzone{
  display:flex;align-items:center;gap:8px;width:100%;padding:8px 10px;
  border:1px dashed var(--line);border-radius:var(--r);background:transparent;
  color:var(--muted);cursor:pointer;text-align:left
}
.dropzone:hover{border-color:var(--accent);color:var(--ink)}
.dropzone[data-over="true"]{
  border-color:var(--accent);background:var(--accent-wash);color:var(--ink)
}
.dz-main{font-size:12.5px}
.dz-hint{margin-left:auto;font-size:10px;color:var(--faint);white-space:nowrap}
.chip-file{display:inline-flex;align-items:center;gap:3px;color:var(--muted)}

/* ---------------- reports ----------------
   Numbers get the same restraint as the board: no colour unless it means
   something (late, stalled), no chart that a row of text would say better. */
.rail-metrics{
  margin-top:10px;padding:9px 10px;border:1px solid var(--line-soft);
  border-radius:var(--r);background:var(--card);display:flex;
  flex-direction:column;gap:6px
}
.rm-row{display:flex;align-items:baseline;gap:8px}
.rm-label{flex:1 1 auto;font-size:11.5px;color:var(--muted)}
.rm-n{font-size:12.5px;font-weight:600;color:var(--ink)}
.rm-n.alert{color:var(--crit)}

.kpis{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));
  gap:8px;margin-bottom:14px
}
.kpi{
  display:flex;flex-direction:column;gap:2px;padding:10px 12px;background:var(--card);
  border:1px solid var(--line-soft);border-left:2px solid var(--line);border-radius:var(--r)
}
.kpi-crit{border-left-color:var(--crit)}
.kpi-warn{border-left-color:var(--warn)}
.kpi-ok{border-left-color:var(--ok)}
.kpi-n{font-size:22px;font-weight:600;line-height:1.1;color:var(--ink)}
.kpi-label{font-size:11.5px;color:var(--ink-2)}
.kpi-note{font-size:10.5px;color:var(--faint)}

.panel{
  background:var(--card);border:1px solid var(--line-soft);border-radius:var(--r);
  padding:12px 14px;margin-bottom:12px
}
.panel-head{display:flex;align-items:baseline;gap:10px;margin-bottom:10px}
.panel-head h2{margin:0;font-size:12px;font-weight:600;letter-spacing:.04em;color:var(--ink)}
.legend{display:flex;align-items:center;gap:5px;margin-left:auto;font-size:10px;color:var(--faint)}
.legend-key{width:9px;height:9px;border-radius:1px;display:inline-block}
.ch-added-key{background:var(--line)}
.ch-done-key{background:var(--accent)}
.muted-line{margin:0;font-size:12.5px;color:var(--faint)}

.chart{width:100%;height:auto;display:block}
.ch-grid{stroke:var(--line-soft);stroke-width:1}
.ch-axis{fill:var(--faint);font-size:8px;font-family:var(--font-mono)}
.ch-added{fill:var(--line)}
.ch-done{fill:var(--accent)}

.dists{display:flex;flex-direction:column;gap:6px}
.dist{display:grid;grid-template-columns:120px minmax(0,1fr) 74px;align-items:center;gap:10px}
.dist-label{font-size:12px;color:var(--ink-2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dist-track{height:8px;background:var(--card-2);border-radius:2px;overflow:hidden}
.dist-bar{display:block;height:100%;background:var(--accent)}
.dist-bar.p1{background:var(--p1)}
.dist-bar.p2{background:var(--p2)}
.dist-bar.p3{background:var(--p3)}
.dist-bar.p4{background:var(--p4)}
.dist-n{font-size:11px;color:var(--muted);text-align:right}

.minirows{display:flex;flex-direction:column;gap:1px}
.minirow{
  display:flex;align-items:center;gap:10px;width:100%;padding:5px 6px;border:0;
  background:none;border-radius:2px;cursor:pointer;text-align:left;font:inherit
}
.minirow:hover{background:var(--card-2)}
.minirow-title{
  flex:1 1 auto;min-width:0;font-size:12.5px;color:var(--ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap
}
.minirow-right{font-size:10.5px;color:var(--faint);white-space:nowrap}
@media (max-width: 720px){
  .dist{grid-template-columns:96px minmax(0,1fr) 60px}
}

/* ---------------- people ----------------
   An avatar here is initials on a flat ground, not a photo: there is no
   directory to fetch pictures from, and a coloured circle per person would be
   the loudest thing on a deliberately quiet board. */
.avatar{
  display:inline-flex;align-items:center;justify-content:center;
  width:24px;height:24px;border-radius:50%;background:var(--accent-wash);
  color:var(--accent-deep);font-size:9.5px;font-weight:700;letter-spacing:.04em;
  font-family:var(--font-mono);flex:0 0 auto
}
.avatar-quiet{background:var(--card-2);color:var(--muted)}
.avatar-xs{width:15px;height:15px;font-size:7.5px}
.assigned{
  display:grid;grid-template-columns:24px minmax(0,1fr) auto;align-items:center;
  gap:8px;padding:4px 6px;border:1px solid var(--line-soft);border-radius:var(--r);
  background:var(--card);margin-bottom:6px
}
.chip-who{display:inline-flex;align-items:center;gap:4px;padding-left:2px}
.chip-shared{color:var(--accent);border-color:var(--accent-wash);background:var(--accent-wash)}

/* ---------------- region clock ----------------
   Grouped by time, because these zones mostly share one. */
.rail-clock-toggle{gap:8px}
.rail-title-btn{
  display:flex;align-items:center;width:100%;border:0;background:none;
  cursor:pointer;font:inherit;font-size:10px;font-weight:600;letter-spacing:.12em;
  text-transform:uppercase;color:var(--faint);padding:0;margin-bottom:8px
}
.rail-title-x{margin-left:auto;font-size:13px;line-height:1}
.rail-title-btn:hover{color:var(--ink-2)}
.clock{
  display:flex;flex-direction:column;gap:5px;padding:8px 10px;
  border:1px solid var(--line-soft);border-radius:var(--r);background:var(--card)
}
.clock-row{display:flex;align-items:baseline;gap:9px}
.clock-time{font-size:12.5px;font-weight:600;color:var(--ink);flex:0 0 auto}
.clock-cities{
  font-size:10.5px;color:var(--muted);line-height:1.35;
  overflow:hidden;text-overflow:ellipsis
}
/* Shown only on a row whose date is not yours — which in practice is the one
   west of here, still on yesterday. Quiet, because it is a qualifier on the
   time rather than a second fact competing with it, but not so quiet it can be
   missed: being wrong about the day is the whole reason it is there. */
.clock-day{
  display:inline-block;margin-left:6px;padding:1px 5px;border-radius:999px;
  background:var(--line-soft);color:var(--ink-2);
  font-size:9.5px;font-weight:600;letter-spacing:.02em;white-space:nowrap
}

/* ---------------- properties block ----------------
   Label and control on one line, the way every tracker that expects you to
   read a task rather than fill in a form does it. */
.ta-title{
  font-size:16px;line-height:1.35;font-weight:600;min-height:56px;
  border-color:transparent;background:transparent;padding:6px 8px;margin-bottom:6px
}
.ta-title:hover{border-color:var(--line-soft)}
.ta-title:focus{border-color:var(--accent);background:var(--card)}
.props{
  display:flex;flex-direction:column;gap:2px;margin:0 0 18px;
  padding:8px 6px;border:1px solid var(--line-soft);border-radius:var(--r);
  background:var(--card)
}
.prop{display:grid;grid-template-columns:74px minmax(0,1fr);align-items:center;gap:10px;min-height:30px}
.prop-label{
  font-size:10px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;
  color:var(--faint)
}
.prop-control{min-width:0;display:flex;align-items:center;gap:6px}
.prop-control>*{min-width:0}
.prop-btn{
  display:inline-flex;align-items:center;gap:6px;border:1px solid transparent;
  background:none;border-radius:2px;padding:3px 6px;font:inherit;font-size:12.5px;
  color:var(--muted);cursor:pointer
}
.prop-btn:hover:not(:disabled){background:var(--card-2);color:var(--ink)}
.prop-btn-person{color:var(--ink)}
.prop-person{display:flex;align-items:center;gap:2px}
.inp-sm{padding:4px 7px;font-size:12.5px;height:28px}
.seg-sm button{padding:4px 8px;font-size:11.5px}
.assign-pick{display:flex;gap:5px;align-items:center;width:100%}
.assign-pick .inp-sm:first-child{flex:1 1 auto}
.assign-pick .inp-sm:nth-child(2){flex:0 0 92px}

/* Due: the picker, plus the three answers it almost always is. */
.due-line{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.due-line .inp-sm{flex:0 0 132px}
.daychips{display:flex;gap:4px}
.daychip{
  border:1px solid var(--line-soft);background:var(--card);color:var(--muted);
  border-radius:2px;padding:3px 7px;font:inherit;font-size:11px;cursor:pointer
}
.daychip:hover:not(:disabled){border-color:var(--accent);color:var(--accent)}
.daychip.on{background:var(--accent-wash);border-color:var(--accent);color:var(--accent-deep)}
.daychip-clear{color:var(--faint)}

/* Sharing is a header button and a popover, as in every document tool. */
.popover{
  position:absolute;top:46px;right:14px;z-index:6;width:min(360px,calc(100% - 28px));
  background:var(--card);border:1px solid var(--line);border-radius:var(--r);
  box-shadow:var(--shadow-lg);padding:12px 13px
}
.pop-title{margin:0 0 9px;font-size:12px;font-weight:600;color:var(--ink)}

/* ---------------- undo toast ---------------- */
.toast{
  position:fixed;left:50%;bottom:22px;transform:translateX(-50%);z-index:60;
  display:flex;align-items:center;gap:12px;padding:9px 10px 9px 14px;
  background:var(--ink);color:var(--paper);border-radius:4px;
  box-shadow:var(--shadow-lg);max-width:min(520px,calc(100vw - 32px))
}
.toast-text{font-size:12.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.toast-action{
  border:0;background:none;color:#7fd1ec;font:inherit;font-size:12.5px;font-weight:600;
  cursor:pointer;padding:2px 4px;border-radius:2px
}
.toast-action:hover{text-decoration:underline}
.toast-x{
  display:flex;border:0;background:none;color:rgba(255,255,255,.55);cursor:pointer;padding:2px
}
.toast-x:hover{color:#fff}

/* ---------------- command palette ---------------- */
.palette{
  position:fixed;top:14vh;left:50%;transform:translateX(-50%);z-index:70;
  width:min(620px,calc(100vw - 32px));background:var(--card);
  border:1px solid var(--line);border-radius:5px;box-shadow:var(--shadow-lg);
  display:flex;flex-direction:column;max-height:66vh;overflow:hidden
}
.pal-head{
  display:flex;align-items:center;gap:9px;padding:11px 14px;
  border-bottom:1px solid var(--line-soft);color:var(--faint)
}
.pal-input{
  flex:1 1 auto;border:0;background:none;font:inherit;font-size:14.5px;
  color:var(--ink);outline:none
}
.pal-list{overflow-y:auto;padding:6px 0}
.pal-group{
  margin:8px 14px 3px;font-size:9.5px;font-weight:600;letter-spacing:.12em;
  text-transform:uppercase;color:var(--faint)
}
.pal-item{
  display:flex;align-items:center;gap:12px;width:100%;padding:6px 14px;border:0;
  background:none;font:inherit;text-align:left;cursor:pointer
}
.pal-item.on{background:var(--accent-wash)}
.pal-label{
  flex:1 1 auto;min-width:0;font-size:13px;color:var(--ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap
}
.pal-hint{font-size:10.5px;color:var(--faint);white-space:nowrap}
.pal-foot{
  display:flex;gap:14px;padding:7px 14px;border-top:1px solid var(--line-soft);
  font-size:10px;color:var(--faint)
}
.pal-open{gap:5px}
@media (max-width: 640px){
  .prop{grid-template-columns:64px minmax(0,1fr)}
  .palette{top:8vh}
}

/* ---------------- sub-task composer ----------------
   A sub-task is a whole task, so it gets the same controls — but inline under
   the list rather than as a modal over the drawer, which would be a dialog on
   top of a dialog. */
.composer{
  margin-top:8px;padding:12px 13px;border:1px solid var(--line);
  border-radius:var(--r);background:var(--card-2);box-shadow:var(--shadow)
}
.composer .props{background:var(--card)}
.composer-foot{display:flex;align-items:center;gap:8px;margin-top:10px}
.crumb{
  display:flex;align-items:center;gap:6px;width:100%;padding:4px 6px;margin-bottom:6px;
  border:0;background:none;border-radius:2px;cursor:pointer;font:inherit;text-align:left
}
.crumb:hover{background:var(--card-2)}
.crumb-up{color:var(--faint);font-size:12px}
.crumb-text{
  font-size:11.5px;color:var(--muted);overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap
}

/* ---------------- device code sign-in ----------------
   Two steps and a code, big enough to read off the screen while typing it on a
   phone. */
.devicecode{
  border:1px solid var(--line);border-radius:var(--r);background:var(--card-2);
  padding:12px 14px;margin:10px 0
}
.dc-step{margin:0 0 4px;font-size:11px;color:var(--muted)}
.dc-link{font-size:12.5px;color:var(--accent);word-break:break-all}
.dc-code{
  margin:6px 0 12px;font-size:26px;font-weight:600;letter-spacing:.22em;
  color:var(--ink)
}
.dc-wait{display:flex;align-items:center;gap:8px;margin:0;font-size:11.5px;color:var(--faint)}

/* Region time, now in the top bar. */
.clock-wrap{position:relative;display:flex}
.clock-btn{gap:6px}
.clock-btn-time{font-size:12px;font-weight:600}
.popover-clock{
  position:absolute;top:36px;right:0;z-index:40;min-width:230px;
  border:1px solid var(--line);box-shadow:var(--shadow-lg)
}
.src-list{margin:0 0 10px;padding-left:18px;font-size:12.5px;color:var(--muted);line-height:1.6}

.prop-stack{display:flex;flex-direction:column;gap:3px;width:100%}
.prop-note{font-size:10px;color:var(--faint)}

.redirect-uri{
  font-size:11px;color:var(--ink-2);background:var(--card-2);border-radius:2px;
  padding:6px 8px;margin:6px 0;overflow-wrap:anywhere;user-select:all
}

.showmore{
  display:block;width:100%;padding:7px 10px;border:1px dashed var(--line-soft);
  border-radius:var(--r);background:transparent;color:var(--muted);
  font:inherit;font-size:12px;cursor:pointer;text-align:left
}
.showmore:hover{border-color:var(--accent);color:var(--accent)}

/* The whole card opens the task, and each sub-task opens itself. The rest of
   the card's styling is up with .hovercard — these duplicated it and, being
   later in the file, quietly won. */
.hovercard:hover{border-color:var(--line)}

/* The lock screen's passcode field. Sized to the sign-in card rather than to
   the form controls in the task modal, which sit in a much narrower rail. */
.passcode-input{
  width:100%;padding:9px 11px;margin:4px 0 10px;
  border:1px solid var(--line);border-radius:6px;background:var(--card);
  color:var(--ink);font-size:15px;letter-spacing:.12em;
}
.passcode-input:focus{outline:2px solid var(--accent);outline-offset:1px;border-color:var(--accent)}

/* ---------- view toggles ---------- */
/* Sidebar and width, beside the brand. Both stay visible in either state, so
   whatever was turned off can be turned back on from the same place. */
.view-toggles{display:flex;align-items:center;gap:2px;flex:0 0 auto}
.view-toggles .btn{padding:5px 6px;line-height:0;color:var(--faint)}
.view-toggles .btn:hover:not(:disabled){color:var(--ink-2)}
.view-toggles .btn.on{color:var(--accent)}
.view-toggles .btn:focus-visible{outline:2px solid var(--accent);outline-offset:1px}

/* The rail is hidden by not being rendered at all, rather than by width:0 —
   a zero-width scroll container still traps a scroll gesture aimed at the
   board behind it. Nothing here needs to hide it; this is the reminder why. */

/* Both toggles, at every width.
 *
 * The width one used to hide below 1140px, on the reasoning that it had
 * nothing to do there — the column is already narrower than the cap. That is
 * true and it was still wrong: the same app on two Macs showed a different set
 * of controls, which reads as one of them being broken or out of date. A
 * control that is momentarily inert is a far smaller cost than a person
 * comparing two machines and concluding the software is inconsistent. */

/* ---------- bulk bar ---------- */
/* Directly above the list, in place of the view heading — the actions belong
   beside the rows they act on. Sticky under the top bar so it stays reachable
   once the list is long enough to scroll. */
.bulkbar{
  position:sticky;top:53px;z-index:45;
  display:flex;align-items:center;gap:14px;flex-wrap:wrap;
  padding:9px 14px;margin-bottom:10px;
  background:var(--accent-wash);
  border:1px solid var(--accent);border-radius:var(--r);
}
.bulk-count{font-size:12px;color:var(--accent);font-weight:600;flex:0 0 auto}
.bulk-field{display:flex;align-items:center;gap:6px;flex:0 0 auto}
.bulk-label{font-size:12px;color:var(--muted)}
.bulk-working{font-size:11px;color:var(--muted)}
/* Wide enough for a project name or an address, narrow enough that the bar
   still fits on one line at a normal window width. */
.bulk-input{width:150px;height:26px}
.bulk-input::placeholder{color:var(--faint);font-size:11px}
.bulk-gap{flex:1 1 auto}

/* Below this the bar has five controls and no room to push the buttons right.
   Letting them pack keeps it to one line instead of stranding "Clear" alone on
   a second. */
.bulk-actions{display:flex;gap:8px;align-items:center;flex:0 0 auto}

@media (max-width: 1400px){
  /* Five controls and three buttons need the room more than the gap does. */
  .bulk-gap{display:none}
  .bulk-input{width:120px}
}

@media (max-width: 700px){
  /* The counts and the two actions matter; the labels are inferable. */
  .bulk-label{display:none}
}

/* ---------- sync panel ---------- */
/* Sits at the foot of the rail, under the report figures. Quiet by default:
   one grey line and a dot. It only takes colour when something needs saying,
   because a panel that is always shouting stops being read — and this one has
   to be believed the day it matters. */
.syncbox{
  /* margin-top:auto puts it at the foot when the rail is short; sticky keeps
     it in view when the rail is long enough to scroll. Without the sticky it
     sat below the fold on a normal window — a status nobody can see without
     scrolling for it is a status that is not being shown. */
  flex:0 0 auto;
  margin-top:8px;padding:9px 8px 2px;
  border-top:1px solid var(--line-soft);
  display:flex;flex-direction:column;gap:3px;
}
.sync-line{
  display:flex;align-items:center;gap:7px;width:100%;text-align:left;
  background:none;border:none;padding:2px 2px;border-radius:3px;
  font:inherit;font-size:11px;color:var(--muted);cursor:pointer;
}
.sync-line:hover:not(:disabled){background:var(--card-2);color:var(--ink-2)}
.sync-line:disabled{cursor:default}
.sync-dot{
  width:6px;height:6px;border-radius:50%;flex:0 0 auto;background:var(--faint);
}
.sync-text{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sync-sub{font-size:10px;color:var(--faint);padding-left:15px;line-height:1.4}
.sync-folder{
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:9.5px;
}

.syncbox[data-state="ok"] .sync-dot{background:var(--ok)}
.syncbox[data-state="busy"] .sync-dot{background:var(--accent)}
.syncbox[data-state="waiting"] .sync-dot{background:var(--warn)}
.syncbox[data-state="bad"] .sync-dot{background:var(--crit)}
/* Only a real problem changes the words' colour. "Waiting for iCloud" is a
   normal state of affairs, not a fault. */
.syncbox[data-state="bad"] .sync-text{color:var(--crit)}
.syncbox[data-state="off"]{opacity:.75}
.syncbox[data-state="off"] .sync-text{padding:2px}

/* ---------- a sub-task's notes ---------- */
/* Shown here, read-only. The note is edited on the sub-task itself, one click
   away; two textareas holding one field is a way to lose an edit. */
.field-head{display:flex;align-items:baseline;gap:10px;margin-bottom:5px}
.field-head>label{margin-bottom:0}
.field-head-btn{
  margin-left:auto;background:none;border:none;padding:0;font:inherit;
  font-size:11px;color:var(--accent);cursor:pointer;
}
.field-head-btn:hover{text-decoration:underline}

/* The marker only exists on a sub-task that has a note, so a row with nothing
   to say stays quiet. Unlike delete it does NOT wait for hover: whether a note
   exists is information, and information you have to go looking for is
   information you do not have. */
/* Now only a mark saying "there is writing here" — the note itself is on the
   page, so this no longer has to be the way to reach it. */
.act-note{
  flex:0 0 auto;color:var(--accent);padding:2px;line-height:0;
  align-self:flex-start;margin-top:2px;
}

/* Always there, two lines to start with.
 *
 * It began collapsed behind a marker, to keep the modal calm. The result was a
 * note you could not tell was there — which is the thing this was meant to
 * fix. So the note is on the page from the start, clamped to two lines, and
 * the whole block is a button that opens it out.
 *
 * Expanded it is still capped and scrolls inside itself: a note is whatever
 * somebody pasted, and what somebody pastes is often an entire email with a
 * signature block. Unclamped, one of those pushed the next actions, the files
 * and the parent's own notes off the screen. */
.sub-note{
  display:block;width:100%;text-align:left;
  margin:5px 0 1px;padding:7px 9px;
  background:var(--paper);border:none;border-left:2px solid var(--line);
  border-radius:0 4px 4px 0;
  font:inherit;font-size:12.5px;line-height:1.55;color:var(--ink-2);
  overflow-wrap:anywhere;cursor:pointer;
}
/* Collapsed, line breaks are folded away so the two lines of preview carry two
   lines of WORDS. A pasted email opens "Dear Sohail," and a blank line, which
   spent the whole preview saying nothing. Expanded, the original formatting
   comes back — that is when it matters. */
.sub-note .sub-note-text{white-space:normal}
.sub-note.open .sub-note-text{white-space:pre-wrap}
.sub-note:hover{border-left-color:var(--accent);background:var(--card-2)}
.sub-note-text{
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
  overflow:hidden;
}
.sub-note.open .sub-note-text{
  display:block;max-height:14em;overflow-y:auto;overscroll-behavior:contain;
}
.sub-note-more{
  display:block;margin-top:4px;font-size:10.5px;color:var(--accent);
  letter-spacing:.02em;
}
.act[data-done="true"] .sub-note{color:var(--muted)}

/* ---------- the reporting period ---------- */
/* Throughput is the one report that asks the database rather than counting the
   rows on screen, so it is the only one with a period to choose. */
/* The four reports, as tabs across the top of the pane.
 *
 * They sit above the heading rather than beside it: the heading names the
 * report you are reading, and a tab strip that pushed it sideways would make
 * the page look like it belonged to the strip rather than to the report. */
/* A newer app has landed. Stated once, where the version already is, rather
   than as a banner across the board — an update is not urgent, and something
   that interrupts you every time you open the app teaches you to dismiss it. */
.update-ready{
  margin-top:12px;padding:11px 13px;border-radius:var(--r);
  border:1px solid var(--accent, #1f6f8b);background:var(--line-soft)
}
.update-text{margin:0 0 9px;font-size:12.5px;line-height:1.45;color:var(--ink-2)}

/* The server has gone. There is nothing left to render against, so the page
   says so instead of quietly failing every request. */
.stopped{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  min-height:70vh;gap:8px;text-align:center;padding:24px
}
.stopped-title{margin:0;font-size:17px;font-weight:600;color:var(--ink)}
.stopped-sub{margin:0;font-size:13px;color:var(--muted)}

/* Signing in to the hosted board: one field, one button. */
/* Says which board you are looking at. Quiet, but always there: a warning you
   can dismiss is one you will dismiss, and the point is that this copy is
   never mistaken for the hosted one. */
.local-notice{
  display:flex;align-items:center;gap:7px;flex-wrap:wrap;
  padding:6px 14px;font-size:11.5px;color:var(--ink-2);
  background:var(--line-soft);border-bottom:1px solid var(--line)
}
.local-notice-dot{
  width:7px;height:7px;border-radius:50%;background:var(--muted);flex:0 0 auto
}
.local-notice a{color:var(--ink);font-weight:600}

.dev-row{
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:9px 0;border-bottom:1px solid var(--line-soft)
}
.dev-row.revoked{opacity:.55}
.dev-what{display:flex;flex-direction:column;gap:2px;min-width:0}
.dev-name{font-size:13px;font-weight:600;color:var(--ink)}
.dev-meta{font-size:10.5px;color:var(--muted)}
/* Shown once and never again, so it has to be hard to miss and easy to select. */
.dev-token{
  margin-top:12px;padding:12px 14px;border-radius:var(--r);
  border:1px solid var(--accent, #1f6f8b);background:var(--line-soft)
}
.dev-token-title{margin:0 0 6px;font-size:12.5px;font-weight:600;color:var(--ink)}
.dev-token-value{
  margin:0 0 8px;font-size:11.5px;word-break:break-all;user-select:all;
  padding:8px;border-radius:6px;background:var(--card);color:var(--ink)
}

.dl-row{
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:9px 0;border-bottom:1px solid var(--line-soft)
}
.dl-row:last-of-type{border-bottom:0}
.dl-what{display:flex;flex-direction:column;gap:2px;min-width:0}
.dl-platform{font-size:13px;font-weight:600;color:var(--ink)}
.dl-meta{font-size:10.5px;color:var(--muted)}

.magic-form{display:flex;flex-direction:column;gap:10px;width:100%}
.magic-form .inp{width:100%;font-size:14px;padding:9px 11px}
.magic-sent{
  display:flex;flex-direction:column;gap:8px;align-items:flex-start;
  padding:12px 14px;border-radius:var(--r);background:var(--line-soft);width:100%
}
.magic-sent-title{margin:0;font-weight:600;color:var(--ink)}

.rep-tabs{
  display:flex;gap:2px;margin:0 0 18px;padding:3px;border-radius:var(--r);
  background:var(--line-soft);overflow-x:auto;scrollbar-width:none
}
.rep-tabs::-webkit-scrollbar{display:none}
.rep-tab{
  flex:0 0 auto;border:0;background:none;cursor:pointer;font:inherit;
  font-size:12.5px;font-weight:600;color:var(--muted);
  padding:6px 13px;border-radius:calc(var(--r) - 2px);white-space:nowrap
}
.rep-tab:hover{color:var(--ink-2)}
.rep-tab.on{background:var(--card);color:var(--ink);box-shadow:0 1px 2px rgba(0,0,0,.07)}

.rep-window{display:flex;align-items:center;gap:9px;margin:0 0 14px;flex-wrap:wrap}
.rep-window-label{
  font-size:10px;font-weight:600;letter-spacing:.12em;text-transform:uppercase;
  color:var(--faint);
}
.rep-window-note{font-size:11.5px;color:var(--muted)}

/* Said plainly rather than drawn: a chart with flat zeroes across a stretch it
   has no records for is telling the reader nothing happened then. */
.rep-horizon{
  margin:0 0 14px;padding:8px 11px;border-radius:var(--r);
  background:var(--warn-wash);color:var(--warn);
  font-size:12px;line-height:1.5;
}

/* ---------- assigning to someone ---------- */
/* People you have assigned to before, written out rather than hidden in a
   browser datalist that only ever matched the email address. */
.assign-pick{display:flex;flex-direction:column;gap:6px;width:100%}
.assign-search{width:100%}
.assign-list{
  display:flex;flex-direction:column;gap:1px;
  border:1px solid var(--line-soft);border-radius:var(--r);
  background:var(--card);overflow:hidden;
}
.assign-opt{
  display:flex;align-items:center;gap:8px;width:100%;text-align:left;
  background:none;border:none;padding:5px 7px;font:inherit;cursor:pointer;
}
.assign-opt:hover{background:var(--accent-wash)}
.assign-opt-body{min-width:0;display:flex;flex-direction:column;gap:0}
.assign-opt-name{
  font-size:12.5px;color:var(--ink);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.assign-opt-mail{font-size:10px;color:var(--faint)}
.assign-new{display:flex;gap:6px;align-items:center}
.assign-new .inp{flex:1 1 auto;min-width:0}
