/* ══════════════════════════════════════════════════════════════════════════
   Denly – the task UI, shared by the dashboard and the landing's product shot.

   The landing used to hand-copy the dashboard's markup and CSS into the shot
   under parallel class names (.trow/.tchip/.tcta), and it drifted every time
   the app moved: an "Inbox" item that had been renamed Tasks, a sidebar project
   list that had moved to the app bar, then paddings and chip sizes each a
   half-step off. Copies drift silently; there is no test that can notice.

   So the shot is no longer a copy. This file is the ONE source for:

     * the BOARD's journey card – title, meta line, the Describe → … → Merge
       rail with its per-node states, the action, the "where now" caption. This
       is what the shot shows: several real tasks at different stages.
     * the sidebar item and the app bar's stat pills, which is where the two
       historical drifts actually happened.
     * the OPENED task – stage chip, four-step rail, hero, tabs, facts rail.
       The app renders it; the shot does not today, but it is the same
       vocabulary and splitting it across two files would just invite a copy.

   Rendering is in task-ui.js beside it: the app builds the model from real
   board data, the landing from a fixed mock, and neither owns the markup.

   Everything here resolves against the design tokens both sides already define
   with the same names (--gate / --run / --done / --bad, --card, --line…), so
   nothing in this file hard-codes a colour.
   ══════════════════════════════════════════════════════════════════════════ */

@keyframes denly-breathe{0%,100%{opacity:1}50%{opacity:.4}}

/* ── the board's journey card ─────────────────────────────────────────────── */
.pl-card{position:relative;background:var(--card);border:1px solid var(--line);border-radius:var(--r);overflow:hidden;transition:border-color .12s,background .12s}
.pl-card::before{content:'';position:absolute;left:0;top:0;bottom:0;width:3px;background:transparent}
.pl-card.gate::before{background:var(--gate)}
.pl-card.gate{border-color:var(--gate-line);background:linear-gradient(90deg,var(--gate-soft),transparent 30%),var(--card)}
.pl-card.running::before{background:var(--run-line)}
.pl-card.failed::before{background:var(--bad)}
.pl-card.failed{border-color:var(--bad);background:linear-gradient(90deg,var(--bad-soft),transparent 30%),var(--card)}
.pl-card.cf .cf-tap{padding:16px 20px 15px;cursor:pointer}
.pl-card.cf:hover{border-color:var(--line-2)}
.pl-top{display:flex;align-items:flex-start;gap:16px;margin-bottom:15px}
.pl-id{flex:1;min-width:0}
.pl-title{font-size:15px;font-weight:600;letter-spacing:-.01em;line-height:1.3;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pl-meta{display:flex;align-items:center;gap:9px;font-size:12px;color:var(--faint);margin-top:5px;flex-wrap:wrap}
.pl-meta .repo{color:var(--muted)}
.pl-meta .sep{width:3px;height:3px;border-radius:50%;background:var(--faint);opacity:.6}
.pl-meta .branch,.pl-meta .row-rt{display:inline-flex;align-items:center;gap:4px}
.pl-meta .row-rt svg{width:10px;height:10px;color:var(--run)}
.pl-act{flex:none;display:flex;align-items:center;gap:10px}
/* The rail scrolls rather than wraps: seven nodes at a phone width would break
   into two rows and read as two journeys. */
.pl-flow{display:flex;align-items:flex-start;overflow-x:auto;padding-bottom:2px;scrollbar-width:none}
.pl-flow::-webkit-scrollbar{display:none}
.pl-node{display:flex;flex-direction:column;align-items:center;gap:7px;flex:none;width:60px}
.pl-dot{width:28px;height:28px;border-radius:50%;flex:none;display:flex;align-items:center;justify-content:center;background:var(--card);border:1.5px solid var(--line-2);color:var(--faint);transition:.15s}
.pl-dot svg{width:12px;height:12px}
.pl-dot .core{width:7px;height:7px;border-radius:50%;background:currentColor}
.pl-dot.done{background:var(--run);border-color:var(--run);color:var(--gate-ink)}
.pl-dot.gate{border-color:var(--gate);color:var(--gate);background:var(--card);box-shadow:0 0 0 4px var(--gate-soft)}
.pl-dot.blocked{border-color:var(--gate);color:var(--gate);background:var(--gate-soft);box-shadow:0 0 0 4px var(--gate-soft)}
.pl-dot.run{border-color:var(--run);color:var(--run);box-shadow:0 0 0 4px var(--run-soft)}
.pl-dot.run .core{animation:denly-breathe 1.6s ease-in-out infinite}
.pl-dot.queued{border-color:var(--run);border-style:dashed;color:var(--run)}
.pl-dot.parked{border-color:var(--line-2);color:var(--faint)}
.pl-dot.failed{background:var(--bad);border-color:var(--bad);color:#fff}
.pl-dot.todo,.pl-dot.dead{color:transparent}
.pl-dot.dead{opacity:.5}
.pl-qm{font-size:14px;font-weight:800;line-height:1}
.pl-lbl{font-size:10.5px;font-weight:600;color:var(--faint);letter-spacing:.01em;white-space:nowrap}
.pl-node.on .pl-lbl{color:var(--text)}
.pl-link{flex:1;min-width:14px;height:2px;margin-top:13px;background:var(--line-2);border-radius:2px}
.pl-link.done{background:var(--run)}
.pl-link.dead{background:repeating-linear-gradient(90deg,var(--bad) 0 4px,transparent 4px 9px);opacity:.55}
/* the card's action: a button when it is your move, a chip when it is not */
.pl-cta{display:inline-flex;align-items:center;gap:7px;font-family:inherit;background:none;border:none;cursor:pointer;font-size:13px;font-weight:650;padding:9px 15px;border-radius:10px;transition:.12s;white-space:nowrap}
.pl-cta svg{flex:none}
.pl-cta.gate{background:var(--gate);color:var(--gate-ink)}
.pl-cta.gate:hover{background:var(--gate-strong)}
.pl-cta.ghost{background:var(--card-2);border:1px solid var(--line-2);color:var(--text)}
.pl-cta.ghost:hover{border-color:var(--faint)}
.pl-cta.deploy{background:var(--done-soft);border:1px solid var(--done);color:var(--done-ink)}
.pl-cta.deploy:hover{background:var(--done);color:var(--gate-ink)}
.pl-chip{display:inline-flex;align-items:center;gap:7px;font-size:12.5px;font-weight:650;padding:7px 12px;border-radius:20px;border:1px solid var(--line-2);color:var(--muted);white-space:nowrap}
.pl-chip svg{width:12px;height:12px}
.pl-chip.run{color:var(--run);border-color:var(--run-line);background:var(--run-soft)}
.pl-chip.run .dot{width:6px;height:6px;border-radius:50%;background:currentColor;animation:denly-breathe 1.8s ease-in-out infinite}
.pl-chip.done{color:var(--done-ink);border-color:var(--done);background:var(--done-soft)}
/* the card's top-right action: open this task in its own page */
.pl-page{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;border-radius:8px;font-family:inherit;background:none;cursor:pointer;color:var(--faint);border:1px solid var(--line);transition:color .12s,background .12s,border-color .12s}
.pl-card.cf:hover .pl-page{color:var(--muted);background:var(--card-2)}
.pl-page:hover{color:var(--text);background:var(--raise);border-color:var(--line-2)}

/* ── the shell bits the shot draws, and the two that historically drifted ─── */
.nav-item{display:flex;align-items:center;gap:11px;padding:8px 10px;border-radius:var(--r-sm);font-family:inherit;background:none;border:none;cursor:pointer;color:var(--muted);text-align:left;width:100%;font-size:14px;font-weight:550;transition:background .12s,color .12s}
.nav-item:hover{background:var(--card);color:var(--text)}
.nav-item.on{background:var(--card);color:var(--text)}
.nav-item svg{flex:none;color:var(--faint)}
.nav-item.on svg,.nav-item:hover svg{color:var(--text)}
.nav-item .ni-count{margin-left:auto;font-size:12px;font-weight:700;min-width:20px;height:20px;padding:0 6px;border-radius:20px;display:inline-flex;align-items:center;justify-content:center}
.ni-count.gate{background:var(--gate-soft);color:var(--gate);box-shadow:inset 0 0 0 1px var(--gate-line)}
.tb-stats{display:flex;align-items:center;gap:6px;padding-left:14px;margin-left:2px;border-left:1px solid var(--line);min-width:0}
.tb-stat{display:inline-flex;align-items:baseline;gap:6px;padding:6px 11px;border-radius:9px;font-family:inherit;cursor:pointer;border:1px solid var(--line);background:var(--card);white-space:nowrap;transition:.12s}
.tb-stat b{font-size:14px;font-weight:750;font-variant-numeric:tabular-nums;color:var(--text)}
.tb-stat span{font-size:12px;color:var(--muted)}
.tb-stat:disabled{cursor:default}
.tb-stat.gate:not(.zero){background:var(--gate-soft);border-color:var(--gate-line)}
.tb-stat.gate:not(.zero) b{color:var(--gate)}
.tb-stat.gate:not(.zero):hover{border-color:var(--gate)}
.tb-stat.run b{color:var(--run)}
.tb-stat.bad b{color:var(--bad)}

/* ── the stage chip ───────────────────────────────────────────────────────── */
.chip{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:600;padding:3px 9px 3px 7px;border-radius:20px;border:1px solid var(--line-2);color:var(--muted);white-space:nowrap;flex:none}
.chip.gate{color:var(--gate);border-color:var(--gate-line);background:var(--gate-soft)}
.chip.run{color:var(--run);border-color:var(--run-line);background:var(--run-soft)}
.chip.done{color:var(--done-ink)}
.chip.idle{color:var(--faint)}
.chip .dot{width:6px;height:6px;border-radius:50%;background:currentColor;flex:none}
.chip.run .dot{animation:denly-breathe 1.8s ease-in-out infinite}
.chip.err{color:var(--bad);border-color:var(--bad);background:var(--bad-soft)}
.chip.err svg{width:12px;height:12px}

/* ── the pipeline rail ────────────────────────────────────────────────────── */
.rail{display:flex;align-items:center;gap:0}
.rail .m{display:flex;align-items:center;gap:7px}
.rail .pip{width:16px;height:16px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;border:1.5px solid var(--line-2);color:var(--gate-ink);flex:none}
.rail .pip.done{background:var(--run);border-color:var(--run)}
.rail .pip.active{border-color:var(--gate);box-shadow:0 0 0 3px var(--gate-soft);color:var(--gate)}
.rail .pip.active.run{border-color:var(--run);box-shadow:0 0 0 3px var(--run-soft);color:var(--run)}
.rail .pip .core{width:6px;height:6px;border-radius:50%;background:currentColor}
.rail .lbl{font-size:11px;color:var(--faint);font-weight:600}
.rail .m.active .lbl{color:var(--text)}
.rail .bar{width:22px;height:2px;background:var(--line-2);margin:0 8px}
.rail .bar.done{background:var(--run)}
.rail .pip.err{border-color:var(--bad);box-shadow:0 0 0 3px var(--bad-soft);color:var(--bad)}
.rail .pip.err svg{width:11px;height:11px}
.rail .m.err .lbl{color:var(--bad)}

/* ── the plain-English "where is it now" caption ──────────────────────────── */
.pl-now{display:flex;align-items:center;gap:9px;margin-top:15px;padding-top:13px;border-top:1px solid var(--line);font-size:13px;color:var(--muted)}
.pl-now-dot{width:7px;height:7px;border-radius:50%;flex:none;background:var(--faint)}
.pl-now-t{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pl-now-x{margin-left:auto;flex:none;font-size:11.5px;color:var(--faint)}
.pl-now.gate{color:var(--gate-strong)}
.pl-now.gate .pl-now-dot{background:var(--gate);box-shadow:0 0 0 3px var(--gate-soft)}
.pl-now.run{color:var(--run)}
.pl-now.run .pl-now-dot{background:var(--run);animation:denly-breathe 1.6s ease-in-out infinite}
.pl-now.bad{color:var(--bad)}
.pl-now.bad .pl-now-dot{background:var(--bad)}
.pl-now.bad .pl-now-t{white-space:normal;line-height:1.45}
.pl-now.done .pl-now-dot{background:var(--done)}

/* ── the page frame (VIEW='task' in the app, the shot's body on the landing) ─ */
.tp{max-width:1180px;margin:0 auto;padding:22px 30px 60px}
.tp-bar{display:flex;align-items:center;gap:14px;margin-bottom:18px;flex-wrap:wrap}
.tp-back{display:inline-flex;align-items:center;gap:7px;font-family:inherit;background:none;cursor:pointer;padding:6px 12px 6px 9px;border-radius:9px;border:1px solid var(--line);color:var(--muted);font-size:13px;font-weight:600;transition:.13s}
.tp-back:hover{color:var(--text);border-color:var(--line-2);background:var(--card)}
.tp-crumb{font-size:12px;color:var(--faint)}
/* Not scoped to .tp-crumb: the facts rail separates owner/repo from #number
   with the same element, and unscoped it rendered `storefront#24` jammed. */
.tp-sep{padding:0 3px;opacity:.5}
.tp-hero{padding-bottom:20px;border-bottom:1px solid var(--line)}
.tp-title{font-size:29px;line-height:1.18;font-weight:750;letter-spacing:-.02em;margin:0 0 15px;max-width:30ch;text-wrap:pretty}
.tp-hero-row{display:flex;align-items:center;gap:20px;flex-wrap:wrap;margin-bottom:14px}
.tp-now{margin:0}
.tp-body{display:grid;grid-template-columns:minmax(0,1fr) 274px;gap:26px;align-items:start;margin-top:22px}
.tp-main{min-width:0;background:var(--card);border:1px solid var(--line);border-radius:15px;overflow:hidden}
.tp-main .tabs{padding:0 20px}
.tp-panes{padding-bottom:6px}
.tp-side{display:flex;flex-direction:column;gap:14px;position:sticky;top:18px}
.tp-card{background:var(--card);border:1px solid var(--line);border-radius:14px;padding:14px 15px}
.tp-card-h{font-size:10.5px;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--faint);margin-bottom:11px}
.tp-fact{display:flex;align-items:center;gap:10px;padding:5px 0;font-size:12.5px}
.tp-fact+.tp-fact{border-top:1px solid var(--line)}
.tp-k{width:76px;flex:none;color:var(--faint)}
.tp-v{min-width:0;flex:1;color:var(--text);display:flex;align-items:center;gap:6px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tp-dim{color:var(--muted)}
.tp-proj{display:inline-flex;align-items:center;gap:7px;min-width:0}
.tp-fact.tp-project .tp-v{overflow:visible}
.tp-proj>span:not(.pchip){overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tp-branch{color:var(--muted);font-size:11.5px}
.tp-fact.tp-multi{align-items:flex-start}
.tp-fact.tp-multi .tp-v{display:block;white-space:normal;overflow:visible;line-height:1.45}
@media (max-width:980px){.tp{padding:18px 16px 50px}.tp-body{grid-template-columns:1fr}.tp-side{position:static}.tp-title{font-size:23px}}

/* ── the tabs strip ───────────────────────────────────────────────────────── */
/* .tab and .tp-back are <button>s in the dashboard, which resets `button`
   globally. The landing does not, so the shared rules carry their own reset –
   a component that only looks right on one of its two hosts is the problem
   this file exists to solve. (First time round the landing's tabs rendered as
   grey OS buttons with the label invisible on its own background.) */
.tabs{display:flex;gap:2px;padding:8px 20px 0;border-bottom:1px solid var(--line)}
.tab{position:relative;font-family:inherit;background:none;border:none;cursor:pointer;font-size:13.5px;font-weight:600;color:var(--muted);padding:11px 13px;border-bottom:2px solid transparent;transition:.12s;display:inline-flex;align-items:center;gap:7px}
.tab:hover{color:var(--text)}
.tab.on{color:var(--text);border-bottom-color:var(--gate)}
.tab.off{opacity:.4;cursor:not-allowed}
.tab .tdot{width:7px;height:7px;border-radius:50%;background:var(--gate)}
