/* ============================================================================================
   BugKit — shared visual system for the owner surfaces (/, /board, /about, /setup).
   One static file, no build step, no dependency: the same rule the pages themselves follow.

   DIRECTION — "the track". This is an instrument panel for one operator returning to eleven
   projects after three days away, not a product site. Phases are a sequence with a cursor
   somewhere in it, so the signature element is a literal track: segment widths proportional to
   how much work each phase holds, fill showing what is built, one hot mark for where you are.

   TYPE. No webfonts — the pages are deliberately dependency-free. Personality comes from making
   monospace the voice of every ref, count and percentage. This system is about M14 and E82
   being quotable and 13/16 being comparable down a column; the mono is load-bearing, not
   decorative. Prose gets the sans.

   COLOUR DISCIPLINE. Hue encodes the STATE OF THE WORK and nothing else — see the tokens below.
   Position ("you are here") is carried structurally: a caret, weight, a ring. That split is the
   correction to an earlier rule which made --cursor mean location, because location and state
   then competed for the same hue and the active phase rendered as though it had failed.

   The three questions to ask before colouring anything:
     1. Is this a state of the WORK? Then use a state token, and only the matching one.
     2. Is it the interface responding to ME? Then --focus, never a state token.
     3. Is it neither — a position, a count, a normal condition? Then no hue at all.
   A number that is merely large is not a warning. A branch that is merely unmerged is not a
   warning. Amber must stay rare or it stops meaning anything.
   ============================================================================================ */

:root {
  --paper: #f6f6f3;
  --surface: #fffffe;
  --ink: #16181d;
  --rule: #dedad8;
  /* Darkened from #6e7178, which measured 4.43:1 on --paper — under the 4.5:1 WCAG AA floor,
     and this colour carries 11.5px text where the floor genuinely applies. Now 6.5:1. Most of
     the page's secondary text is this token, so it was most of the page failing. */
  --muted: #55585f;
  /* Body copy inside cards. Was hardcoded in six rules; named so it can be audited. 10.9:1. */
  --body: #33373f;
  /* --- Hue means STATE OF THE WORK, and nothing else. -----------------------------------
     One colour, one meaning. Overloading these is what made a project's current phase render
     as though it had failed, and the same mistake was live in three other places.

     done    finished, built, healthy
     warn    genuinely needs a decision — a number that could mislead, a high-severity report
     danger  wrong, failed, or destructive
     cursor  work in progress, and ONLY that

     Normal conditions of an active project — open reports, an unmerged branch, features added
     after a phase began — are NOT warnings and must stay neutral. Colouring them amber turns
     every project that is actually being worked on into a wall of caution. */
  --done: #2f6b46;
  --warn: #9a6700;
  --danger: #a4302a;
  --cursor: #d9480f;

  /* --- Hue for INTERACTION, kept out of the state palette above. -------------------------
     Focus rings, hover borders and links say "the interface is responding to you"; they say
     nothing about the work. They used to borrow --cursor, so tabbing into a field made it look
     like something in progress. Blue appears nowhere else, so it cannot be misread as state. */
  --focus: #1d4ed8;

  --font-ui: ui-sans-serif, -apple-system, "Segoe UI Variable Text", "Segoe UI", system-ui, sans-serif;
  --font-mono: ui-monospace, "Cascadia Mono", "SF Mono", "Segoe UI Mono", Menlo, Consolas, monospace;

  --r: 7px;
}

* { box-sizing: border-box; }

body {
  font: 14px/1.55 var(--font-ui);
  color: var(--ink);
  background: var(--paper);
  margin: 0;
  padding: 26px 20px 60px;
  -webkit-font-smoothing: antialiased;
}

.wrap { max-width: 1080px; margin: 0 auto; }

/* --- masthead ------------------------------------------------------------------------------
   The wordmark is an instrument label, not a logo: small mono caps above the page title, so
   the title itself carries the weight. */
.brand {
  font: 500 10.5px/1 var(--font-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  display: block;
  margin-bottom: 7px;
  width: fit-content;
}
/* Where the masthead links home it must look like it does. An underline on hover is the whole
   affordance; without it a link that only works when you guess is the same as no link. */
a.brand { text-decoration: none; }
a.brand:hover { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
h1 {
  font: 600 26px/1.15 var(--font-ui);
  letter-spacing: -0.021em;
  margin: 0;
}
h2 { font: 600 15px/1.3 var(--font-ui); letter-spacing: -0.01em; margin: 0 0 7px; }
.muted { color: var(--muted); }
.lbl {
  font: 500 10px/1 var(--font-mono);
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--muted);
}
.meta { font: 11.5px/1.5 var(--font-mono); color: var(--muted); margin-top: 4px; }
.next { font-size: 12.5px; color: var(--body); margin-top: 3px; }

/* "Now", straight from the repo's STATUS.md — so its length is not ours to control. One project
   writes a 2,000-character Now, and unclamped that single card pushes the other ten off the
   screen, which is the one thing this page must never do. Clamped here; the full text is on the
   element's title and on the project's own page. */
.now { font-size: 12.5px; color: var(--body); margin-top: 3px; }
.card .now {
  display: -webkit-box;
  -webkit-line-clamp: 4;
  line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.now.empty { color: var(--muted); font-style: italic; }

/* Where this was left, and where it goes — two questions, so two columns. Stacked they read as
   one block of similar-looking prose and the eye has to work out which half is which. */
.nownext {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px 20px;
  margin-top: 7px;
  align-items: start;
}
/* A hairline between them rather than a box: the columns are a pair, not two panels. */
.nownext > .nn + .nn { border-left: 1px solid var(--rule); padding-left: 20px; margin-left: -20px; }
.nn { min-width: 0; }
/* The column headers have to win against the prose beneath them, or the pair reads as one
   block again — the whole point of splitting it. Heavier, wider-tracked, and darker than the
   body they label, with a rule under them so the column has a visible top edge. */
.nn > .lbl {
  font: 700 10px/1 var(--font-mono);
  letter-spacing: 0.16em;
  color: var(--ink);
  margin-bottom: 5px;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--rule);
}
/* Which Next this is — from the repo's own file, or from the plan. Two sources answering the
   same question have to be told apart or the column silently mixes them. */
.src {
  font: 600 9.5px/1.4 var(--font-mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border-radius: 3px;
  padding: 1px 5px;
  margin-right: 6px;
  white-space: nowrap;
}
/* The repo's own words vs. what the plan says to build next — different sources, so different
   washes rather than two identical grey pills sitting one above the other. */
.src-repo { color: var(--muted); background: #ecece7; }
.src-build { color: var(--cursor); background: #fdf1ea; }

/* Markdown rendered inline. The text is authored as markdown in each repo's STATUS.md, so the
   asterisks and backticks were being displayed instead of the emphasis they encode. */
.now code, .next code, .prose code {
  font: 11.5px/1.4 var(--font-mono);
  background: #ecece7;
  border-radius: 3px;
  padding: 0 4px;
}
.now strong, .next strong { font-weight: 650; color: var(--ink); }
.now a, .next a { color: var(--focus); }
.card .nn > .next { display: -webkit-box; -webkit-line-clamp: 3; line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }

/* Two columns need width. Below it they stack, and the rule between them would be nonsense. */
@media (max-width: 760px) {
  .nownext { grid-template-columns: 1fr; gap: 9px; }
  .nownext > .nn + .nn { border-left: 0; padding-left: 0; margin-left: 0; }
}
.prose { white-space: pre-wrap; color: var(--body); font-size: 13px; }

/* --- "How it works", folded ----------------------------------------------------------------
   Two paragraphs of monospace above the list, read once and then furniture, pushing the actual
   content down the page on every visit. */
.howto { margin-top: 10px; }
.howto > summary {
  cursor: pointer;
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--muted);
  border: 1px solid var(--rule);
  background: var(--surface);
  border-radius: 999px;
  padding: 3px 11px;
}
.howto > summary::-webkit-details-marker { display: none; }
.howto > summary:hover { color: var(--ink); border-color: #c9c5c2; }
.howto[open] > summary { margin-bottom: 4px; }
.howto p { font: 12.5px/1.6 var(--font-ui); color: var(--body); margin: 8px 0 0; max-width: 78ch; }

/* --- drag to reorder -------------------------------------------------------------------------
   The grip is the only draggable part. Making the whole card draggable fights text selection,
   and this card is also a link — two gestures on one surface is one too many. */
.grip {
  flex: none;
  align-self: flex-start;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 26px;
  margin: -2px 0 0 -4px;
  border-radius: 5px;
  color: #b4b0ac;
  cursor: grab;
  touch-action: none;
}
.grip:hover { color: var(--muted); background: #efefea; }
.grip:active { cursor: grabbing; }
.grip:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; color: var(--muted); }
.card.dragging { opacity: 0.4; }
/* Where it will land. A line, not a highlight: the gap between cards is the thing being chosen. */
.card.over { box-shadow: 0 -3px 0 -1px var(--focus); border-color: #c9c5c2; }

/* --- icon + value pairs ----------------------------------------------------------------------
   Four facts — version, last commit, repo, freshness — used to run together as one grey
   dot-separated sentence you had to read through to find any single one. */
.ico { width: 11px; height: 11px; flex: none; fill: currentColor; opacity: 0.75; }
.mrow { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 14px; margin-top: 8px; }
.mbit { display: inline-flex; align-items: center; gap: 5px; min-width: 0; }
.mbit > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mbit.stale { color: var(--warn); }
.mbit.stale .ico { opacity: 1; }

/* --- controls ------------------------------------------------------------------------------ */
input, select, textarea, button { font: inherit; color: inherit; }
.ctl {
  border: 1px solid var(--rule);
  background: var(--surface);
  border-radius: var(--r);
  padding: 5px 8px;
  font-size: 12.5px;
}
/* Every textarea on these pages was an unstyled browser default sitting in a designed page —
   no border of ours, no padding, no width, and a drag handle in the corner. */
textarea {
  display: block;
  width: 100%;
  border: 1px solid var(--rule);
  background: var(--surface);
  border-radius: var(--r);
  padding: 8px 10px;
  font: 13px/1.55 var(--font-ui);
  color: var(--ink);
  resize: vertical;
}
textarea:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }
textarea::placeholder { color: var(--muted); }

/* A labelled edit form: eyebrow, field, eyebrow, field, actions. */
.form { margin-top: 8px; }
.form > .lbl { margin-bottom: 4px; }
.form > .lbl ~ .lbl { margin-top: 11px; }

.ctl:focus-visible, .btn:focus-visible, .tab:focus-visible, .chip:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 1px;
}
.btn {
  border: 1px solid var(--rule);
  background: var(--surface);
  border-radius: var(--r);
  padding: 6px 11px;
  font-size: 12px;
  font-weight: 500;
  cursor: pointer;
  text-decoration: none;
  color: inherit;
  display: inline-block;
}
.btn:hover { background: #efefea; }
/* The one primary per section. Ink, not the cursor colour — the cursor means "you are here",
   and a Save button is not a place. */
.btn.primary { background: var(--ink); border-color: var(--ink); color: var(--paper); }
.btn.primary:hover { background: #23262d; }

.row-gap { display: flex; flex-wrap: wrap; gap: 7px; align-items: center; }
.hide { display: none !important; }

/* --- chips: always mono, because they are all refs, counts or states ----------------------- */
.chip {
  font: 500 11px/1.45 var(--font-mono);
  border: 1px solid var(--rule);
  background: var(--surface);
  color: var(--muted);
  border-radius: 999px;
  padding: 1px 8px;
  white-space: nowrap;
}
.chip.pick { cursor: pointer; }
.chip.pick[aria-pressed='true'] { background: var(--ink); border-color: var(--ink); color: var(--paper); }
/* Badges carry a wash of their own state. Every one being the same neutral grey meant the eye
   had to READ each to sort a shipped version from an open-item count from a branch — and the
   washes stay pale, because a card with five saturated badges is a card you cannot skim either.
   Still bound by the palette rule: the hue is the state, never decoration. */
.chip.ver { color: var(--done); border-color: #bcd8c6; background: #eef6f1; text-decoration: none; }
/* Open reports and an unmerged branch are what a project being worked on LOOKS LIKE — pending
   work, not a warning. Amber here made the most active project wear the most caution. */
.chip.items { color: var(--ink); border-color: #d6d2cd; background: #f0efec; }
.chip.branch { color: var(--warn); border-color: #e8dbb4; background: #fbf7ec; font-style: normal; }
.ref {
  font: 600 11px/1.45 var(--font-mono);
  background: #ecece7;
  border-radius: 4px;
  padding: 1px 5px;
  white-space: nowrap;
}

/* --- cards --------------------------------------------------------------------------------- */
.card {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: 11px;
  padding: 13px 15px;
  display: flex;
  gap: 12px;
  align-items: flex-start;
}
.card.link { cursor: pointer; }
.card.link:hover { border-color: #c9c5c2; }
/* Dormant reads as unpowered, not as broken. */
.card.dormant { opacity: 0.5; }
.sec { background: var(--surface); border: 1px solid var(--rule); border-radius: 11px; padding: 14px 16px; margin-top: 10px; }
.title { font-weight: 600; letter-spacing: -0.01em; }

/* `.num` is still used by the backlog's per-row # inputs (board.html). The Across view's own
   order box is gone — dragging replaced it, so its styles went with it. */
.num { text-align: center; font-variant-numeric: tabular-nums; }
.num::-webkit-outer-spin-button, .num::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.num { -moz-appearance: textfield; appearance: textfield; }

/* --- health dot ---------------------------------------------------------------------------- */
.dot { width: 7px; height: 7px; border-radius: 50%; margin-top: 7px; flex: none; }
.dot.live { background: var(--done); }
/* Has work on a branch. Green like live, because it IS live — a ring distinguishes "moving,
   with something unmerged" from "moving, all on the default branch". It was amber, which made
   every project with work in flight look like it needed attention. */
.dot.branch { background: var(--surface); box-shadow: inset 0 0 0 2.5px var(--done); }
.dot.quiet { background: #c9c5c2; }
.dot.noremote { background: transparent; border: 1.5px solid #c9c5c2; }

/* --- THE TRACK — the signature -------------------------------------------------------------
   Each phase is a segment whose WIDTH is its share of the project's work and whose FILL is
   what is built. So a project reads at a glance as "one fat phase mostly done, five thin ones
   untouched" — which a row of equal chips cannot say. */
.track { display: flex; gap: 4px; margin-top: 10px; align-items: stretch; }

/* A segment is now JUST a bar. Six phase titles competing for the width of a card truncated
   every one of them — "1. Staff role…", "2. PMS li…", six labels none of which could be read,
   which is strictly worse than showing none. The names moved to the tooltip, where there is
   room for the whole thing plus its numbers, and the active one is spelled out below the bar
   where it has the full width to itself. */
.seg { min-width: 14px; padding-bottom: 1px; }
.seg > u {
  display: block;
  height: 8px;
  border-radius: 3px;
  background: #e2e0da;          /* the unbuilt remainder */
  overflow: hidden;
  text-decoration: none;
  cursor: help;
}
.seg > u > i {
  display: block;
  height: 100%;
  background: var(--done);
  transition: width 340ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
/* A future phase reads as lighter track, not as a different thing. */
.seg:not(.done):not(.on) > u { background: #eae8e2; }
.seg > u:hover { box-shadow: 0 0 0 1.5px #b4b0ac; }

/* You are here.
   The fill STAYS GREEN. It previously turned vermilion on the active segment, which changed
   what the colour meant: everywhere else in this interface green is built and red is wrong, so
   a project's current phase rendered as though something had failed in it — the first question
   anyone asked about the track was why hoteldsk was red.
   Colour encodes the state of the work. Position is carried by weight and a ring — neither of
   which can be mistaken for an alarm, and neither of which relies on hue alone. */
.seg.on > u { box-shadow: 0 0 0 1.5px var(--ink); }

/* The one phase worth naming, at full width and in the page's ink rather than the muted grey
   everything else in this strip uses. */
.phase-now { color: var(--ink); font-weight: 700; }
.phase-now::before { content: '▸ '; color: var(--muted); font-weight: 500; }

.track-key { font: 11px/1.4 var(--font-mono); color: var(--muted); margin-top: 6px; }

/* Project totals on an Across card: the summary table's three numbers, without its table.
   One line, because this page's job is choosing between eleven projects — not reading one. */
.totals { display: flex; gap: 14px; flex-wrap: wrap; margin-top: 6px; }
.tot { font: 11.5px/1.4 var(--font-mono); color: var(--muted); }
.tot > b { font-weight: 600; font-size: 13px; margin-right: 1px; }
.tot.tone-done > b { color: var(--done); }
.tot.tone-flight > b { color: var(--cursor); }
.tot.tone-muted > b { color: var(--ink); }

@media (prefers-reduced-motion: reduce) {
  .seg > i { transition: none; }
}

/* --- tabs ----------------------------------------------------------------------------------- */
.tabs { display: flex; gap: 2px; margin: 12px 0 6px; border-bottom: 1px solid var(--rule); }
.tab {
  border: 0; background: none; padding: 7px 13px;
  font: 500 12.5px/1 var(--font-ui);
  color: var(--muted); cursor: pointer;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.tab.on { color: var(--ink); border-bottom-color: var(--ink); }

/* The focus block: a ring, a name, and the one thing to do next.
   It carried a percentage, a bar, and a run-on line of dot-separated statistics — the headline
   number competing with three of its own footnotes. The secondary figures moved to the ring's
   tooltip: they are what you consult when a number looks wrong, not what you read every visit. */
.focus {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: 12px;
  padding: 16px 18px;
  margin-top: 10px;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 16px;
  align-items: center;
}
.focus-text { min-width: 0; }
.focus-title > span:first-child {
  font: 600 19px/1.25 var(--font-ui);
  letter-spacing: -0.018em;
  display: block;
  margin-top: 2px;
}
.focus-next {
  margin-top: 9px;
  padding-top: 9px;
  border-top: 1px solid var(--rule);
  font-size: 13px;
  color: var(--body);
}
.focus > .caveat { grid-column: 1 / -1; margin-top: 2px; }

/* The ring. pathLength="100" normalises the circumference so the dash array is literally the
   percentage — no 2πr constant to keep in step with the radius. */
.dial { position: relative; width: 56px; height: 56px; flex: none; cursor: help; }
.ring { width: 56px; height: 56px; transform: rotate(-90deg); }
.ring circle { fill: none; stroke-width: 4; }
.ring-bg { stroke: #eceae6; }
.ring-fg {
  stroke: var(--ink);
  stroke-linecap: round;
  transition: stroke-dasharray 420ms cubic-bezier(0.22, 1, 0.36, 1);
}
/* Green only near the end — spending the colour of "done" on 20% devalues it everywhere. */
.ring.near .ring-fg { stroke: var(--done); }
.dial-n {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font: 600 14px/1 var(--font-mono);
  letter-spacing: -0.02em;
}

/* --- plan detail ----------------------------------------------------------------------------- */
.bar { height: 5px; background: #eceae6; border-radius: 999px; overflow: hidden; margin: 8px 0 4px; }
.bar > i { display: block; height: 100%; background: var(--done); }
.nums { display: flex; gap: 22px; flex-wrap: wrap; font: 11.5px/1.4 var(--font-mono); color: var(--muted); }
.nums b { font: 600 21px/1.1 var(--font-mono); color: var(--ink); display: block; letter-spacing: -0.02em; }

/* Contextual AI actions.
   Interaction blue, never a state colour: a sparkle says the interface can do something for
   you, not that anything about the work is wrong.
   Hidden until the row is hovered, because sixteen feature rows each carrying a permanent
   button is the clutter this replaced. Still reachable by keyboard — an invisible button takes
   focus perfectly well, and :focus-visible brings it back. */
.aiw { position: relative; display: inline-flex; flex: none; }
.ai {
  border: 0; background: none; cursor: pointer; padding: 2px 5px; border-radius: 5px;
  color: var(--focus); line-height: 1; font-size: 12px; opacity: 0;
  transition: opacity 0.12s, background 0.12s;
}
.feat:hover .ai, .phase-head:hover .ai, .ai:focus-visible, .ai[aria-expanded='true'], .ai.always {
  opacity: 1;
}
.ai:hover { background: rgba(29, 78, 216, 0.09); }
.aimenu {
  position: absolute; right: 0; top: 100%; z-index: 30; margin-top: 4px; width: 214px;
  background: var(--surface); border: 1px solid var(--rule); border-radius: 9px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1); padding: 4px; text-align: left;
}
.aimenu > button {
  display: block; width: 100%; text-align: left; border: 0; background: none; cursor: pointer;
  padding: 6px 8px; border-radius: 6px; font: inherit; color: var(--ink);
}
.aimenu > button:hover { background: rgba(29, 78, 216, 0.07); }
.aimenu .h { display: block; font-size: 12.5px; font-weight: 600; }
.aimenu .s { display: block; font-size: 11px; line-height: 1.35; color: var(--muted); }
@media (prefers-reduced-motion: reduce) { .ai { transition: none; } }

/* A proposal you can accept. Blue, because it is the interface offering something — the green
   capture box means something shipped, and the two must not be confused at a glance. */
.propose {
  border: 1px solid var(--rule); border-left: 3px solid var(--focus); border-radius: var(--r);
  background: var(--surface); padding: 9px 11px; margin-top: 7px;
}
.propose > .lbl { margin-bottom: 5px; }
.propose .t { font-weight: 600; font-size: 13px; }

/* A read-only AI answer — Interpret and Brainstorm, which produce something to think about
   rather than something to save. Kept visually distinct from a proposal you can accept. */
.aiout {
  border: 1px solid var(--rule); border-left: 3px solid var(--focus); border-radius: var(--r);
  background: var(--surface); padding: 9px 11px; margin-top: 7px;
  font-size: 13px; line-height: 1.55; white-space: pre-wrap;
}

/* The one-line prompt shown when a feature is marked Built.
   Green, not amber: this is the moment something SHIPPED, and it is an invitation to write a
   line, never a warning that anything is wrong. Nothing here blocks — the stage change is
   already saved by the time this appears. */
.capture {
  border: 1px solid var(--rule);
  border-left: 3px solid var(--done);
  border-radius: var(--r);
  background: var(--surface);
  padding: 9px 11px;
  margin-top: 7px;
}
.capture > .lbl { margin-bottom: 5px; }

/* A number that could mislead never appears without this. */
.caveat {
  background: #fbf6e8; border: 1px solid #e6d5a8; border-radius: var(--r);
  padding: 7px 10px; font-size: 12px; margin-top: 8px; color: #6b4a06;
}
/* Only one callout survives: work built ahead of the active phase. The "next feature" callout
   it used to sit beside was folded into the focus header, and its rules outlived it here. */
.callout { border-radius: var(--r); padding: 9px 12px; margin-top: 8px; font-size: 13px; }
.callout.leak { background: #fbf6e8; border: 1px solid #e6d5a8; }

/* Accomplished / in flight / pending.
   The count is set in mono and sized up because it is the exact, computed part; the gloss is
   the written part and sits quieter. A reader should be able to take the numbers on trust and
   treat the sentence as commentary, which is exactly what each one is. */
.sumtable { border: 1px solid var(--rule); border-radius: 11px; background: var(--surface); margin-top: 10px; overflow: hidden; }
/* Three columns so the shape of the work — how much is done against how much is not — reads
   in one glance instead of down a list. The extra detail per column is a NAMED LIST rather
   than a longer paragraph: prose in a 220px measure wraps to six ragged lines, but four short
   rows sit in it comfortably and say more. */
.sumcols { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
.sumcol { padding: 12px 14px 14px; border-left: 1px solid var(--rule); min-width: 0; }
.sumcol:first-child { border-left: 0; }
.sumhead { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.sumlabel { font: 500 10.5px/1.4 var(--font-mono); letter-spacing: 0.09em; text-transform: uppercase; color: var(--muted); }
.sumcount { font: 600 23px/1 var(--font-mono); letter-spacing: -0.025em; }
/* The itemised list is disclosure now. Three columns naming four features each put twelve
   rows above the phase list that already contains every one of them. */
.sumdisc { margin-top: 9px; padding-top: 8px; border-top: 1px dotted var(--rule); }
.sumdisc > summary {
  cursor: pointer;
  list-style: none;
  font: 500 10.5px/1.4 var(--font-mono);
  letter-spacing: 0.06em;
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  gap: 5px;
}
.sumdisc > summary::-webkit-details-marker { display: none; }
.sumdisc > summary::before { content: '▸'; font-size: 9px; }
.sumdisc[open] > summary::before { content: '▾'; }
.sumdisc > summary:hover { color: var(--ink); }
.sumitems { margin-top: 6px; }
/* Ref and title on one line, title clipped rather than wrapping — the column is a summary,
   and a wrapped title turns four short rows into eight of uneven height. */
.sumitem { display: flex; gap: 6px; align-items: baseline; font-size: 11.5px; color: var(--muted); margin-top: 3px; }
.sumitem > span:last-child { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* The count takes the colour of the state it counts: finished green, in progress the cursor
   colour, not-started neutral. The middle one was named "warn" while rendering in --cursor —
   nothing pending is a warning, and a class whose name disagrees with its colour is how the
   next person reintroduces the bug. */
.tone-done .sumcount { color: var(--done); }
.tone-flight .sumcount { color: var(--cursor); }
.tone-muted .sumcount { color: var(--muted); }
/* Inside a phase, where the project-level table above is the one read first. */
.sumtable.compact { margin-top: 8px; background: transparent; }
.sumtable.compact .sumcol { padding: 9px 11px 11px; }
.sumtable.compact .sumcount { font-size: 17px; }

/* Three columns need real width. Below it they stack, and each column gets a rule above it
   instead of beside it so the grouping survives the reflow. */
@media (max-width: 760px) {
  .sumcols { grid-template-columns: 1fr; }
  .sumcol { border-left: 0; border-top: 1px solid var(--rule); }
  .sumcol:first-child { border-top: 0; }
}

/* "Done when" folded away — set once, consulted rarely, and a whole paragraph tall. */
.dod { margin-top: 6px; }
.dod > summary {
  cursor: pointer;
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font: 500 10.5px/1 var(--font-mono);
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted);
}
.dod > summary::-webkit-details-marker { display: none; }
.dod > summary::before { content: '▸'; font-size: 9px; }
.dod[open] > summary::before { content: '▾'; }
.dod > summary:hover { color: var(--ink); }
.dod > .next { margin-top: 5px; }
.dod > .btn { margin-top: 6px; }

/* The one line above a feature list: what you are looking at, and what changes it. */
.listbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 7px; }

/* Adding and drafting are occasional acts. Two permanent buttons trailing every phase's list
   is two buttons of noise per phase, six times down the page. */
.addfold { margin-top: 10px; }
.addfold > summary {
  cursor: pointer;
  list-style: none;
  font: 11.5px/1.4 var(--font-mono);
  color: var(--muted);
  width: fit-content;
}
.addfold > summary::-webkit-details-marker { display: none; }
.addfold > summary:hover { color: var(--ink); }

/* A maintenance action that has to exist but must not compete with the content. */
.footact { margin-top: 18px; text-align: right; }
.linkbtn {
  background: none;
  border: 0;
  padding: 0;
  font: 11.5px/1.4 var(--font-mono);
  color: var(--muted);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--rule);
}
.linkbtn:hover { color: var(--ink); text-decoration-color: currentColor; }
.linkbtn:disabled { opacity: 0.5; cursor: default; }

.feat { display: flex; gap: 10px; align-items: flex-start; padding: 8px 0; border-top: 1px solid var(--rule); }
.feat:first-of-type { border-top: 0; }
/* A row you just restaged. It is held in its position rather than re-sorted or hidden, so it
   gets a quiet marker: the change registered, and the row is staying put on purpose. */
.feat.touched { box-shadow: inset 2px 0 0 var(--done); padding-left: 9px; margin-left: -9px; }
/* A REPORTED item reads differently from a planned one. Something that came back from the
   world was sitting in the same list, in the same styling, as work someone chose to schedule.
   A left accent and a kind-coloured ref separate a defect from a milestone without a word of
   explanation — and the accent is a 2px rule, not a filled row, because six tinted rows under
   a feature would shout louder than the feature itself. */
.item.kind-b { box-shadow: inset 2px 0 0 var(--danger); }
.item.kind-e { box-shadow: inset 2px 0 0 var(--focus); }
.item.kind-f { box-shadow: inset 2px 0 0 var(--warn); }
.item[class*='kind-'] { padding-left: 9px; }
.ref-b { color: var(--danger); background: #fbefee; }
.ref-e { color: var(--focus); background: #eef2fd; }
.ref-f { color: var(--warn); background: #fbf7ec; }

/* An attached report. The title takes the slack so status and age line up down the column
   rather than landing wherever each title happens to end. */
.item {
  display: flex;
  align-items: baseline;
  gap: 7px;
  font: 11.5px/1.6 var(--font-mono);
  color: var(--muted);
  margin-left: 2px;
}
.item-t { flex: 1; min-width: 0; }
.item > .meta { white-space: nowrap; }
.phase { border-top: 1px solid var(--rule); padding-top: 12px; margin-top: 12px; }
.phase:first-of-type { border-top: 0; padding-top: 0; margin-top: 0; }
/* Groups are a badge on the row, not a header above a run of rows — a heading plus its own
   counter, repeated per group, broke one list into several and spent a line saying "0/1". */
.chip.group {
  color: var(--muted);
  background: #f0efec;
  border-color: #e2e0da;
  font-size: 10px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.stage { font: 11.5px/1.4 var(--font-mono); padding: 3px 6px; flex: none; cursor: pointer; }
.stage-planned { color: var(--muted); }
.stage-in_progress { color: var(--cursor); border-color: #f2c3a8; background: #fdf1ea; }
.stage-built { color: var(--done); border-color: #bcd8c6; background: #eef6f1; }
.stage-dropped { color: var(--muted); text-decoration: line-through; }

.suggest {
  display: block; margin-top: 6px; border: 1px dashed var(--rule); background: var(--surface);
  color: var(--ink); border-radius: var(--r); padding: 5px 9px;
  font: 11.5px/1.4 var(--font-mono); cursor: pointer; text-align: left;
}
.suggest:hover { background: #efefea; }
.unlink { border: 0; background: none; color: var(--muted); cursor: pointer; font-size: 11px; padding: 0 3px; }
.unlink:hover { color: var(--danger); }
.onhover { visibility: hidden; }
.feat:hover .onhover { visibility: visible; }

/* --- report status / severity --------------------------------------------------------------- */
.st-open { color: var(--muted); }
.st-acknowledged, .st-in_progress { color: var(--cursor); border-color: #f2c3a8; background: #fdf1ea; }
.sev-blocker { color: var(--danger); border-color: #eec4c1; background: #fbefee; }
.sev-high { color: var(--warn); border-color: #e6d5a8; background: #fbf6e8; }
.sev-medium { color: var(--muted); }
.sev-low { color: var(--muted); }

/* --- gate ------------------------------------------------------------------------------------ */
#gate { max-width: 380px; margin: 90px auto; text-align: center; }
#gate h1 { font-size: 21px; }

/* The version block: label, release, build commit, build date + age — the same four facts
   every app in this workspace shows, in the same order. */
.verblock { border: 1px solid var(--rule); border-radius: var(--r); padding: 11px 13px;
            margin: 18px 0 4px; display: inline-block; min-width: 190px; background: var(--surface); }
.verblock .v { font: 600 25px/1.15 var(--font-mono); letter-spacing: -0.02em; margin-top: 5px; }
.verblock .sha { font: 11.5px/1.5 var(--font-mono); color: var(--muted); }
.verblock .built { font: 11.5px/1.5 var(--font-mono); color: var(--muted); margin-top: 3px; }

/* --- document pages (about / setup) ---------------------------------------------------------- */
.doc { max-width: 660px; margin: 0 auto; }
.doc p { color: var(--body); }
.doc h2 { margin-top: 30px; font-size: 16px; }
.doc pre {
  background: var(--ink); color: #e7e7e2; padding: 15px; border-radius: var(--r);
  overflow-x: auto; font: 12.5px/1.6 var(--font-mono);
}
.doc code { font-family: var(--font-mono); font-size: 0.92em; }
.doc a { color: var(--focus); }
nav.top { display: flex; gap: 15px; font: 12px/1 var(--font-ui); margin-bottom: 24px; flex-wrap: wrap; }
nav.top a { color: var(--muted); text-decoration: none; }
nav.top a:hover { color: var(--ink); }

@media (max-width: 600px) {
  body { padding: 20px 14px 48px; }
  h1 { font-size: 22px; }
  .nums { gap: 16px; }
  .nums b { font-size: 18px; }
}
