/* Asset-stamp cache repair for this file: sys_deployment.md § "The same hook carries a SECOND
   guard" states the rule this earned. */
/* The OKR surface: header band, signal panel, objective list, portfolio grid.

   Loaded after tokens.css and base.css, before the page's own <style>. Every colour here
   is a token — the six health states are the --okr-* aliases, which follow the palette
   into light mode without a second definition.

   One state class everywhere: `.st-behind`, `.st-slightly_behind`, `.st-on_track`,
   `.st-ahead`, `.st-completed`, `.st-not_started` are set from OKR_STATUS values verbatim, so
   a dot, a pill, a bar segment and a card all take their colour from the same string.

   `.st-not_scored` is deliberately not one of the six health states above, and gets no bar
   segment — see OKR_STATUS_ORDER's own comment in JS/services/okr-view-model.js. An objective
   whose key results all sit in a quarter other than the one on screen is not being scored
   against this quarter at all, so it takes no place in a health distribution or its own
   status-filter column, but still needs a dot, a pill and a group of its own. */

/* ---------- header band ---------- */
/* ---------- the pinnable header ----------
   Pinned is `position:sticky`, not a scroll container — that changes one box and leaves the
   document scrolling exactly as it does today, so unpinned is the absence of a class rather
   than a second layout to keep working.

   The padding is always there and the margin cancels it, since sticky has no "is it stuck" in
   CSS: 10px of padding with -10px of margin is the same layout at rest, and 10px of page
   background above the card once it reaches the top edge.

   The max-height is for short windows, not tall headers — capped at 60% of the viewport it
   scrolls within itself instead, so the thing being pinned can never take the screen away from
   the thing it is a header for. */
.okr-pinhead{ padding:10px 0 2px; margin:-10px 0 0; }
.okr-pinhead.pinned{
  position:sticky; top:0; z-index:var(--z-sticky);
  background:var(--bg);
  max-height:60vh; overflow-y:auto; overflow-x:clip;
}
/* And it must not clip a popover it is the anchor for: the Filters disclosure lives in the
   toolbar inside this box, so `max-height` plus a non-visible `overflow` cuts the panel off at
   the header's bottom edge — reads as a z-index fault and is not one, since no z-index lifts
   content out of a clipping ancestor. While the panel is open the cap and clip are lifted. */
.okr-pinhead.pinned:has(.okr-filters[open]){ max-height:none; overflow:visible; }
/* A guard can go dark without being edited: this selector matches markup `.okr-filters[open]`
   that no longer exists on the live popover, which now escapes this ancestor through JS
   instead (`okrWireChrome()`, JS/pages/okrs.js — moved to `<body>` once at wiring time, the
   way `okrOutsideHost()` already does for `#okrOutsidePop`). Left standing rather than deleted:
   it still protects any OTHER `.okr-filters[open]` element this box might anchor, and deleting
   a guard nobody has re-derived a need for is how the next one goes dark too. Adding a new
   anchored panel inside `.okr-pinhead.pinned` — check what this selector literally matches
   rather than assuming it already covers the new shape. */
/* On an engine that cannot ask the `:has()` question, the safe default is not to clip: the
   rule is dropped whole there, so the clipping itself is lifted separately for that case. Only
   the overflow is lifted, not `max-height` — that cap is CSS/okr-suite.css's one declaration
   on okrs.html and this must not start a second race with it, the same category as a vh/dvh
   fallback pair rather than a second answer. */
@supports not selector(:has(*)){
  .okr-pinhead.pinned{ overflow:visible; }
}
/* Only once it is actually holding position — at the top of the page there is nothing
   underneath it to separate from, and a shadow there reads as a rendering fault. The class is
   set by an IntersectionObserver on the sentinel above it. */
.okr-pinhead.pinned.stuck{
  box-shadow:0 6px 18px rgba(0,0,0,.22);
  border-bottom:1px solid var(--border-soft);
}
/* Zero-height and invisible: it exists only to be watched, so that "stuck" is observed rather
   than computed from a scroll offset that every layout change would invalidate. */
.okr-pin-sentinel{height:0; margin:0; padding:0;}
/* Pressed is the pin engaged. `.btn.active` is the accent treatment every toggle on this page
   already uses; aria-pressed is what says so to a screen reader. */
.okr-pin-btn{flex:0 0 auto;}
.okr-pin-btn[aria-pressed="true"]{
  border-color:var(--accent); color:var(--accent-text); background:var(--accent-soft);
}

/* The details button says whether its panel is open. Owner, with a screenshot:
   *"when expanded clicking check-ins the button is not glowing indicating its expanded."*
   The state was already there and only the drawing was missing — okrMarkToggle() sets both
   `.active` and `aria-expanded` from okrState.expandedKrs, and nothing was reading either.
   `aria-expanded` rather than `.active` is the hook, since it already has to be right for a
   screen reader, so styling it means the two can never disagree.

   This rule used to also carry a halo matching the check-in chip's glow, on the reasoning that
   "open" and "there is a check-in here" should read as one family — backwards, since they are
   different facts and one treatment just makes a reader ask which one a glowing button means.
   A lit Details and a lit Linked work resolve to the identical colour; put to the owner, who
   chose *"same blue is correct"*: both buttons mean "this control's panel is open", one state,
   one meaning. The check-in chip's own glow is unaffected — it is keyed on the chip existing,
   not on this rule. */
/* THE :hover VARIANTS CARRY .alt-app DELIBERATELY, to reach (0,5,0) and beat
   `.alt-app .btn:hover:not(:disabled)` at (0,4,0). Without them the expanded Details button
   showed its idle border and text while the pointer rested on it — see the note on
   `.btn.active` in CSS/okr-suite.css, which is the same defect on the shared toggle. */
.alt-app .okr-kr-actions [data-open-kr][aria-expanded="true"]:hover:not(:disabled),
.alt-app [data-open-kr][aria-expanded="true"]:hover:not(:disabled),
.okr-kr-actions [data-open-kr][aria-expanded="true"],
[data-open-kr][aria-expanded="true"]{
  border-color:var(--accent); color:var(--accent-text); background:var(--accent-soft);
}
/* Unpinned, the pin lies over; pinned, it stands upright. The rotation is the whole state
   change, and --dur-micro is the token for it: the reference calls that band "hover, chevron,
   badge, selected state — response, not motion", which is exactly what a toggle reporting its
   own new state is. The longer bands are for surfaces arriving. */
/* LYING FLAT WHEN IT IS NOT HOLDING ANYTHING, UPRIGHT WHEN IT IS. A quarter turn either
   way, so the two states are told apart across the room rather than by comparing angles —
   -40deg was a tilt, and a tilt reads as the same pin drawn slightly wrong. */
.okr-pin-btn svg{transform:rotate(-90deg); transition:transform var(--dur-micro) var(--ease-out);}
.okr-pin-btn[aria-pressed="true"] svg{transform:rotate(0deg);}
@media (prefers-reduced-motion: reduce){
  .okr-pin-btn svg{transition:none;}
}

.okr-band{
  background:linear-gradient(135deg, var(--panel-2), var(--panel));
  border:1px solid var(--border); border-radius:var(--radius);
  padding:18px 20px; margin-bottom:14px; position:relative; overflow:hidden;
}
.okr-band h1{font-size:26px; font-weight:700; margin:0 0 4px; letter-spacing:-.01em;}
/* The one-line model of the page. 11px is the floor for --text-faint (§ typography), and the
   bold words are the three nouns everything below uses. */
.okr-band .okr-band-ladder{
  font-size:11px; color:var(--text-faint); margin-top:5px; line-height:1.5;
  display:flex; flex-wrap:wrap; gap:6px; align-items:baseline;
}
.okr-band .okr-band-ladder b{ color:var(--text-dim); font-weight:600; }
.okr-spacer{flex:1 1 auto;}

/* ---------- summary / signal panel ---------- */
.okr-summary{
  display:grid; grid-template-columns:auto 1fr; gap:22px; align-items:center;
  background:var(--panel); border:1px solid var(--border); border-radius:var(--radius);
  padding:18px 20px; margin-bottom:14px;
}
.okr-donut-wrap{display:flex; align-items:center; gap:16px;}
.okr-donut{width:104px; height:104px; flex-shrink:0;}
/* ---------- the donut is a control ----------
   Every arc filters to its status and the middle clears the status filter. The affordance has
   to be visible before the pointer arrives, or it reads as a picture people happen to be able
   to click. */
.okr-arc, .okr-donut-all{cursor:pointer;}
.okr-arc-ink{
  transition:stroke-width var(--dur-micro) var(--ease-out), opacity var(--dur-micro) var(--ease-out);
}
/* THICKER, NOT BRIGHTER. The arc colours ARE the status vocabulary — brightening one would
   make it read as a different status. Growing it says "this one" without saying anything about
   health. */
.okr-arc:hover .okr-arc-ink,
.okr-arc:focus-visible .okr-arc-ink,
.okr-arc.on .okr-arc-ink{stroke-width:17;}
/* AND THE OTHERS STEP BACK, so a selected segment is legible as a selection rather than as a
   slightly fatter arc. Only while something IS selected. */
.okr-donut:has(.okr-arc.on) .okr-arc:not(.on) .okr-arc-ink{opacity:.35;}
.okr-arc:focus-visible, .okr-donut-all:focus-visible{outline:2px solid var(--accent); outline-offset:2px;}
/* The middle reads as pressable on hover and says so when the filter is already clear. */
.okr-donut-all .okr-donut-num{transition:fill var(--dur-micro) var(--ease-out);}
.okr-donut-all:hover .okr-donut-num,
.okr-donut-all:focus-visible .okr-donut-num{fill:var(--accent-text);}
@media (prefers-reduced-motion: reduce){
  .okr-arc-ink, .okr-donut-all .okr-donut-num{transition:none;}
}
.okr-donut-num{font-size:26px; font-weight:700; fill:var(--text);}
/* A ROW, BECAUSE IT CARRIES AN AFFORDANCE NOW. The uppercase treatment moves onto the text
   itself: `letter-spacing` on the row would push the icon away from the last letter by a tenth
   of an em, and `text-transform` on the row is inherited by the button's accessible name in no
   useful way while making any future text child shout. */
.okr-donut-label{display:flex; align-items:center; gap:6px;}
.okr-donut-label-t{font-size:11px; font-weight:700; letter-spacing:.1em; text-transform:uppercase; color:var(--text-dim);}
/* The "what this counts" button, sized off the 11px label rather than the 26px icon buttons
   elsewhere on the page: it is an annotation on a caption, and a control the same height as
   the number beside it would read as a second action. */
.okr-donut-info{
  flex:0 0 auto; width:18px; height:18px; padding:0; display:flex; align-items:center;
  justify-content:center; border:0; background:none; border-radius:50%;
  color:var(--text-faint); cursor:pointer;
  transition:color var(--dur-micro) var(--ease-out), background var(--dur-micro) var(--ease-out);
}
.okr-donut-info svg{width:14px; height:14px;}
.okr-donut-info:hover{color:var(--accent-text); background:var(--panel-2);}
.okr-donut-info:focus-visible{outline:2px solid var(--accent); outline-offset:2px;}
/* Open reads as pressed, the same soft wash `.repeat-info[aria-expanded="true"]` uses for the
   one other icon-sized disclosure in this application. */
.okr-donut-info[aria-expanded="true"]{color:var(--accent-text); background:var(--accent-soft);}
@media (prefers-reduced-motion: reduce){ .okr-donut-info{transition:none;} }
/* THE PANEL IT OPENS IS NOT STYLED HERE. `#okrInViewPop` is appended to <body>, outside this
   page's content, and CSS/okr-suite.css carries it under `body.alt-app` for the two reasons its
   own `.okr-outside-pop` block states: the --a-* role tokens, and the measured contrast the app
   palette's quietest tier fails on that surface. Same arrangement, same place. */
/* Only rendered while a drill-down (status, Hide completed or the glance chip) is actually
   removing rows the headline total still counts — see okrRenderSummary()'s `narrowed`. A
   readiness scope is not one of these: the ring follows it directly. Sits between the
   uppercase label and the health percentage, so the honest "showing fewer than this" reading
   lands before the good news does. */
.okr-donut-narrowed{font-size:12px; color:var(--text-dim); margin-top:1px;}
.okr-donut-pct{font-size:13px; color:var(--accent-text); font-weight:600; margin-top:2px;}

.okr-stats{display:grid; grid-template-columns:repeat(6, minmax(0,1fr)); gap:8px;}
/* Each card is a filter toggle, so it is a real button and shows selection as state. */
.okr-stat{
  background:var(--panel-2); border:1px solid var(--border); border-radius:var(--radius-sm);
  padding:9px 11px; text-align:left; display:flex; flex-direction:column; gap:2px;
}
.okr-stat:hover{border-color:var(--border-strong);}
.okr-stat.active{border-color:var(--accent); background:var(--accent-soft);}
.okr-stat-n{font-size:21px; font-weight:700; line-height:1; font-variant-numeric:tabular-nums;}
.okr-stat-l{
  font-size:11px; font-weight:700; letter-spacing:.07em; text-transform:uppercase;
  color:var(--text-dim); display:flex; align-items:center; gap:5px;
}
.okr-krbar-head{
  display:flex; justify-content:space-between; align-items:baseline;
  font-size:11px; letter-spacing:.07em; text-transform:uppercase;
  color:var(--text-dim); margin:14px 0 6px; font-weight:700;
}
.okr-krbar{display:flex; gap:3px; height:8px;}
.okr-krbar span{border-radius:999px; min-width:3px; transition:flex-grow var(--dur-progress) var(--ease-out);}

/* ---------- signal settings ---------- */
.okr-signal{
  border-top:1px solid var(--border-soft); margin-top:14px; padding-top:14px;
  grid-column:1 / -1;
}
.okr-signal p{font-size:13px; color:var(--text-dim); margin:0 0 14px;}
.okr-track{position:relative; height:10px; border-radius:999px; margin:26px 8px 30px; background:var(--panel-2);}
.okr-track-fill{position:absolute; top:0; bottom:0; border-radius:999px;}
.okr-handle{
  position:absolute; top:50%; width:18px; height:18px; margin:-9px 0 0 -9px;
  border-radius:50%; background:var(--panel); border:2px solid var(--text);
  cursor:ew-resize; touch-action:none;
}
.okr-handle:focus-visible{outline:2px solid var(--focus-ring); outline-offset:2px;}
.okr-handle-val{
  position:absolute; top:-24px; left:50%; transform:translateX(-50%);
  font-size:11px; font-weight:700; color:var(--text); font-variant-numeric:tabular-nums;
}
.okr-track-legend{
  position:absolute; top:20px; font-size:11px; color:var(--text-dim); white-space:nowrap;
  transform:translateX(-50%);
}

/* ---------- the readiness scope banner ----------
   THE ONLY VISIBLE TRACE OF okrState.scope, and it has to be: a list quietly narrowed to
   "objectives without a key result" with no reason shown and no way out is worse than the
   defect this exists to fix — see okrs.html's readiness tiles and okr-board.js's
   okrScopeBannerHtml(). Styled like the matrix's own "in scope" wash (`--accent-soft` /
   `--accent`) rather than a new colour, so a reader who has already learned that vocabulary
   from the Overview grid recognises it here. */
.okr-scope-banner{
  display:flex; align-items:center; justify-content:space-between; gap:12px;
  background:var(--accent-soft); border:1px solid var(--accent); border-radius:var(--radius);
  padding:9px 14px; margin:0 0 10px; font-size:13px; font-weight:600; color:var(--accent-text);
}
.okr-scope-banner .btn{flex:none;}

/* ---------- grouped objective list ---------- */
.okr-listhead{
  display:flex; align-items:center; gap:10px; flex-wrap:wrap;
  font-size:11px; font-weight:700; letter-spacing:.09em; text-transform:uppercase;
  /* 10px ABOVE, NOT 18. This line describes the list; the row above it acts on the list. They
     are one block, and 18px on top of the control row's own 8px bottom margin read as two
     separate things with a gap between them — reported as "too much space".

     Not zero, and not collapsed into the row above: they ARE two different kinds of thing, and
     the 10px is what keeps a caption from touching the controls it sits under. That is the
     same distance the summary tiles keep from the band above them. */
  color:var(--text-dim); margin:10px 0 8px;
}
/* ---------- ROW: the full-width group ----------
   The default layout, and the one a user with no preference gets — Kanban is an alternative,
   never a replacement for it. Column lives at the foot of this file. */
.okr-group{
  background:var(--panel); border:1px solid var(--border); border-radius:var(--radius);
  margin-bottom:12px; overflow:hidden;
}
.okr-group-head{
  display:flex; align-items:center; gap:10px; width:100%; text-align:left;
  background:none; border:none; padding:14px 16px; color:var(--text);
}
.okr-group-head:hover{background:var(--panel-2);}
.okr-group-title{font-size:16px; font-weight:700;}
.okr-group-meta{font-size:12px; color:var(--text-dim); font-weight:400;}
.okr-group-bar{height:3px; display:flex; gap:2px; margin:0 16px 12px;}
.okr-group-bar span{border-radius:999px;}
/* What a status group gets instead: a soft line break. Grouped by status the distribution bar
   is one flat colour the width of the group, sitting above objective bars whose width IS a
   percentage — so it read as "100%". A hairline in the divider tier cannot be mistaken for a
   measurement, and occupies the same space so nothing shifts between the two groupings. */
.okr-group-rule{height:1px; background:var(--border-soft); margin:0 16px 12px;}
.okr-group-body{border-top:1px solid var(--border-soft);}
.okr-group.collapsed .okr-group-body,
.okr-group.collapsed .okr-group-rule,
.okr-group.collapsed .okr-group-bar{display:none;}
.okr-caret{color:var(--text-faint); flex-shrink:0;}
/* One rule for every collapsible caret. Three things on this board disclose in place — a
   status/area band, a Kanban area column and a List objective row — and all three draw the
   identical down-chevron SVG and rotate it identically to point right while shut, so this is
   one selector list rather than three copies of the same fact. A fourth collapsible caret in
   future needs only a new selector added here, not a new rule. */
.okr-group.collapsed .okr-caret,
.okr-area.collapsed .okr-caret,
.okr-obj.collapsed .okr-caret{transform:rotate(-90deg);}

/* ---------- objective row ---------- */
.okr-obj{border-bottom:1px solid var(--border-soft);}
.okr-obj:last-child{border-bottom:none;}
/* The outline is the system border, not the objective's status. This block used to colour the
   whole rectangle by status, one rule per OKR_STATUS value, added on the request *"the outline colour of the objective should be consistent with the state of the objective"*.
   The owner reversed it on sight of the rendered list: *"the coloured outline is colour overload and is not helpful in the view."*
   On a list where nearly every row is behind, a per-row coloured rectangle is a wall of red that
   distinguishes nothing — the signal is already carried once, by the status chip in the row,
   which is retained unchanged.

   The shorthand stays, which is the point of keeping a rule here at all: `border` replaces
   `.okr-obj`'s `border-bottom` on every side, so a row remains a full quiet rectangle rather
   than reverting to a bare divider — only the colour changes.

   `[data-obj]` is deliberately gone: it existed to out-specify CSS/okr-suite.css's own border
   rule while status colour had to win. Now the opposite is wanted, so this ties with that rule
   instead and the later-loading file takes the colour — the system border wins on each host by
   its own reckoning rather than being restated. The `-soft` head wash below is untouched: it
   tints only an open row's header and was never part of the complaint. */
.okr-obj[data-status]{border:1px solid var(--border-soft);}
/* AND ONLY WHILE IT IS OPEN — a fourth loud statement of the same fact is exactly what the
   objective progress bar was removed for (see the long comment at `.okr-obj-title` below);
   a shut row must read exactly as it did before this change, and the tint should arrive with
   the content it is commenting on, not before. The `-soft` wash is the same token the pill
   and stat colour already use for "this state, but quiet". */
.okr-obj[data-status="behind"] .okr-obj-head{background:var(--okr-behind-soft);}
.okr-obj[data-status="slightly_behind"] .okr-obj-head{background:var(--okr-slightly-soft);}
.okr-obj[data-status="on_track"] .okr-obj-head{background:var(--okr-ontrack-soft);}
.okr-obj[data-status="ahead"] .okr-obj-head{background:var(--okr-ahead-soft);}
.okr-obj[data-status="completed"] .okr-obj-head{background:var(--okr-done-soft);}
.okr-obj[data-status="not_started"] .okr-obj-head{background:var(--okr-idle-soft);}
/* `data-status="not_scored"` deliberately has no wash here — it is not a health colour (see
   the file-header comment), and `.okr-obj-head`'s own base rule already answers with
   `background:none`, so this row opens exactly as plain as it looks shut. */
/* The reset for shut rows: one rule for every state, at higher specificity than every wash
   above regardless of source order, so a collapsed row never carries one whichever status it
   holds. `.okr-obj-head:hover` still wins on top of this at run time. */
.okr-obj.collapsed[data-status] .okr-obj-head{background:none;}
.okr-obj-head{
  display:grid; grid-template-columns:22px 14px minmax(0,1fr) auto; gap:10px;
  align-items:start; width:100%; text-align:left;
  background:none; border:none; padding:13px 16px; color:var(--text);
}
.okr-obj-head:hover{background:var(--panel-2);}
/* A MEASURE ON THE TEXT, NOT ON THE PAGE. With main.okr-main uncapped an objective
   title on a 2560px screen would be one 2400px line, which is unreadable for the ordinary
   reason — the eye loses the row on the way back. Capping the sentence costs nothing;
   capping the page cost the key-result tiles and the cycle grid their columns. */
.okr-obj-title{font-size:14px; font-weight:600; line-height:1.35; max-width:78ch;}
.okr-obj-sub{font-size:12px; color:var(--text-dim); margin-top:3px; display:flex; flex-wrap:wrap; gap:6px; align-items:center;}
/* WHEN, in the subline, given the weight the count used to have on its own. Not a pill —
   the row already carries a status pill and a second one would compete with it. */
.okr-obj-period{color:var(--text); font-weight:600;}
/* The objective row no longer draws a progress bar: it already carries a status dot, a status
   pill and a percentage, with a distribution band above the group and a bar under every
   measure — a full-width bar of its own was the fourth statement of one fact and the loudest.
   See okrObjectiveHtml(). The Kanban card keeps its own, since one objective in its own box
   has the room and nothing beside it competes. */
/* Sits in the page's control row beside New objective, between two vertical rules. 11px is
   the floor for --text-faint, and the label is faint while the control is not. */
.okr-sort{display:flex; align-items:center; gap:6px; flex:0 0 auto;}
/* Matched to `.btn.small` at 27px total, measured rather than reasoned — a `<select>` with the
   same padding measures taller on its own, since the control adds internal metrics of its own
   for the arrow. Height is set explicitly as well as via padding, because a select's intrinsic
   height varies by platform and this row has to be the same on all of them. */
.okr-list-head .okr-sort select{padding:4px 8px; font-size:12px; height:27px;}
/* The same 27px every other control in this row is, stated explicitly: a label with a
   checkbox in it has no height of its own and would otherwise take the line's. */
.okr-list-head .okr-hide-done{
  display:inline-flex; align-items:center; gap:6px; height:27px;
  font-size:12px; color:var(--text-dim); white-space:nowrap; cursor:pointer;
}
.okr-list-head .okr-hide-done:hover{color:var(--text);}
.okr-list-head .okr-hide-done input{margin:0; cursor:pointer; accent-color:var(--accent);}
.okr-sort > span{font-size:11px; color:var(--text-faint); text-transform:uppercase;
  letter-spacing:.5px; font-weight:600; white-space:nowrap;}
.okr-sort select{width:auto; font-size:12px; padding:3px 8px;}
/* The panel the Details button opens says what the button said. */
.okr-detail-title{
  font-size:13px; margin:0 0 10px; display:flex; flex-wrap:wrap; gap:8px; align-items:baseline;
}
.okr-detail-title > span{font-size:12px; font-weight:400; color:var(--text-faint); min-width:0;
  overflow-wrap:anywhere;}
/* The band legend in Settings — see okrBandLegendHtml(). */
.okr-band-legend{list-style:none; margin:10px 0 0; padding:0; display:flex;
  flex-direction:column; gap:5px;}
.okr-band-legend li{display:flex; align-items:baseline; gap:8px; font-size:12px;}
.okr-band-legend b{min-width:110px; color:var(--text);}
.okr-band-legend span{color:var(--text-dim); min-width:0;}
.okr-band-dot{width:10px; height:10px; border-radius:3px; flex:0 0 auto; align-self:center;}
.okr-signal-scale{font-size:11px; color:var(--text-faint); margin:6px 0 0;}
/* A roster you can type into — see okrOwnerFieldHtml(). The native select is kept; the
   search narrows its options. */
/* `.okr-owner-pick` / `.okr-owner-search` / `.okr-owner-count` went with the search-box-
   above-a-select they styled. The owner field is the shared `.person-select` combobox now —
   CSS/components.css — which is the same control the team board and the task panel use. */
.okr-obj-right{display:flex; align-items:center; gap:12px; white-space:nowrap;}
/* The warning, said out loud — a row of the head grid, under the badges it explains and
   pushed to the same right edge. Not a wrapped flex item inside `.okr-obj-right`: that group
   is an `auto` grid track that sizes to max-content and grows to fit the sentence rather than
   wrapping it, so spanning the head is what fixes it. `justify-self:end` with a measure keeps
   the block against the right edge instead of stretching across the row. */
.okr-obj-head .okr-hidden-note{
  grid-column:1 / -1; justify-self:end;
  margin-top:-4px; text-align:right;
  /* One line, not two: a caption that wraps takes a whole second row from every affected
     objective. Hidden below 1080px anyway (see the responsive section). */
  white-space:nowrap; max-width:100%; overflow:hidden; text-overflow:ellipsis;
  font-size:11px; font-weight:400; line-height:1.45; letter-spacing:0;
  color:var(--text-dim);
}
.okr-obj-pct{font-size:14px; font-weight:700; font-variant-numeric:tabular-nums; min-width:44px; text-align:right;}
/* The check-in indicator — okrCheckinChipHtml(), drawn beside both the objective's own numbers
   and a key result's, one rule for both since it is the same fact at two levels.

   Resting subtle, pressable unmistakable — the owner's own word ("subtle") for the resting
   state, and a control still has to read as one. No border and no tinted ground at rest, since
   those belong to `.okr-pill` and the health chip, which say what the measure IS DOING, where
   this only says somebody has reported since. `--text-dim` matches `.okr-kr-nums`'s own figure
   colour; button-reset properties strip the native chrome so it still reads as quiet text.
   Hover and focus borrow `.okr-kr-linkcount`'s own dotted-underline treatment and the
   `--accent` focus ring every other pressable control on this page draws — no new colour, no
   new pill shape, no new token. */
.okr-checkin-chip{
  display:inline-flex; align-items:center; border:none; background:none; padding:0; margin:0;
  font:inherit; font-size:11px; font-weight:600; white-space:nowrap;
  font-variant-numeric:tabular-nums; cursor:pointer; border-radius:var(--radius-sm);
  /* It glows whenever it exists, which is the whole of the rule — okrCheckinChipHtml() returns
     an empty string for a count of zero, so this chip is only in the document when there IS a
     check-in to see. Owner: *"the check in label should permanently glow when there is a checkin"*,
     to draw the eye to a measure somebody has actually moved.

     Permanent, not animated: "glow" is the accent colour plus a soft halo, held, not a pulse —
     a looping animation beside a figure a reader is trying to read is the thing
     `prefers-reduced-motion` exists to switch off. Both tokens are defined in light and dark,
     so the halo thickens the glyph rather than tinting the row — no new colour, no new token. */
  color:var(--accent-text);
  text-shadow:0 0 6px var(--accent-soft);
}
.okr-checkin-chip:hover{ text-decoration:underline dotted; text-underline-offset:2px; }
.okr-checkin-chip:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }
/* The 0fr→1fr row trick needs the collapsing box to hold EXACTLY ONE child — the explicit
   `1fr` defines a single row and `min-height:0` lets that first child be crushed below its own
   content, so a body with several children collapses the first measure into the ones under it.
   This body now holds exactly one child, `.okr-obj-inner` (see okrObjectiveHtml()), which is
   the primitive's requirement (sys_design-system.md §2b). This IS `.disclosure` from
   CSS/components.css, written out rather than borrowed because the open/shut state is
   `.okr-obj.collapsed` on the ancestor article rather than a class on the box itself. */
.okr-obj-body{
  display:grid; grid-template-rows:1fr;
  transition:grid-template-rows var(--dur-quick) var(--ease-out);
  background:var(--panel-2);
}
.okr-obj-body > *{min-height:0; overflow:hidden;}
.okr-obj.collapsed .okr-obj-body{grid-template-rows:0fr;}
/* The clip carries no padding, and that is the whole reason it exists: padding on the box
   being clipped cannot shrink with it, so the padded box lives inside the clip instead. */
.okr-obj-clip{min-height:0; overflow:hidden;}
/* The ghost hit-box: `overflow:hidden` above clips PAINT, never LAYOUT. `.okr-obj-clip` is
   squeezed to 0px tall by the collapsing grid row, but its child `.okr-obj-inner` keeps its own
   full natural height and simply overflows the 0px box unseen — so every control inside it
   still reports a real, non-zero `getBoundingClientRect()` sitting where its content would
   have painted, overlapping the next visible objective's header. A pointer click or
   `elementFromPoint` still correctly resolves to that real header, never the ghost, but
   anything that locates a control by attribute rather than by what is on screen can still
   reach it.

   The fix is a transform, not a second `overflow` or a `z-index`. `visibility:hidden` was
   tried first and rejected: it stops paint and hit-testing but never changes
   `getBoundingClientRect()`, so the phantom box survives unchanged. `scale(0)` collapses a
   descendant's measured geometry down to the transformed ancestor's own already-zero-height
   box, which is what removes the phantom rect entirely.

   Costs nothing visually: `.okr-obj-clip` is already invisible while collapsed, so scaling its
   own invisible box to a point touches nothing anyone can see, including the open/close
   animation this rule does not touch — no transition is declared here, since the ancestor's
   existing `grid-template-rows` transition already carries 100% of what is visible. This only
   corrects what a descendant REPORTS about its own geometry once that animation has finished
   hiding it. */
.okr-obj.collapsed .okr-obj-clip{transform:scale(0);}
.okr-obj-inner{padding:2px 16px 16px 62px;}
/* One clock for the section and its arrow. */
.okr-caret{transition:transform var(--dur-quick) var(--ease-out);}
@media (prefers-reduced-motion: reduce){
  .okr-obj-body, .okr-caret{transition-duration:1ms;}
}

/* ---------- key result ---------- */
.okr-kr{
  border:1px solid var(--border-soft); border-radius:var(--radius-sm);
  background:var(--panel); padding:11px 13px; margin-bottom:8px;
}
.okr-kr:last-child{margin-bottom:0;}
.okr-kr-head{display:flex; align-items:start; gap:9px;}
.okr-kr-title{font-size:14px; font-weight:600; flex:1 1 auto; line-height:1.35;}
.okr-kr-meta{font-size:12px; color:var(--text-dim); margin-top:3px; display:flex; flex-wrap:wrap; gap:8px;}
.okr-kr-nums{font-size:12px; font-variant-numeric:tabular-nums; color:var(--text-dim); white-space:nowrap;}
.okr-kr-nums b{color:var(--text); font-size:13px;}
.okr-progress{height:6px; border-radius:999px; background:var(--panel-2); margin-top:9px; overflow:hidden;}
/* The fill takes canonical timing from the design system rather than a literal — see the
   motion primitives in CSS/components.css. The reveal runs once, when a board's data lands:
   `.okr-progress-reveal` on the host puts every fill at zero, then okrRevealProgress()
   releases them a frame later with a capped stagger, so the eye follows the order rather than
   watching a screen of bars twitch at once. A later re-render does not replay it — a bar that
   redraws because a filter changed is not a value that moved. */
.okr-progress i{display:block; height:100%; border-radius:999px;
  transition:width var(--dur-progress) var(--ease-out);}
.okr-progress-reveal .okr-progress i{width:0 !important;}
@media (prefers-reduced-motion: reduce){
  /* Arrives at the value instead of travelling to it. The number is the information. */
  .okr-progress i{transition:none;}
}
/* The expected-position marker. Without it a bar at 40% tells you nothing — the whole
   point is 40% against where the quarter clock says you should be. */
.okr-progress-wrap{position:relative;}
.okr-tick{
  position:absolute; top:-3px; width:2px; height:12px; border-radius:1px;
  background:var(--text-faint); opacity:.85;
}
.okr-kr-actions{display:flex; gap:6px; flex-wrap:wrap; margin-top:10px;}
.okr-linked{margin-top:9px; padding-top:9px; border-top:1px dashed var(--border-soft);}
.okr-linked-h{font-size:11px; font-weight:700; letter-spacing:.07em; text-transform:uppercase; color:var(--text-faint); margin-bottom:5px;}
.okr-task{display:flex; align-items:center; gap:7px; font-size:13px; padding:3px 0; color:var(--text-dim);}
.okr-task a{color:var(--accent-text); text-decoration:none;}
.okr-task a:hover{text-decoration:underline;}
.okr-task.done{text-decoration:line-through; opacity:.65;}

/* ---------- objective actions panel ----------
   Reported: *"the objective actions are not obvious and get a bit lost under the key results"*
   — a bare row of four small buttons under the last key-result card read as one more piece of
   key-result chrome. `okrObjectiveActionsHtml()` now wraps that same row in one bordered,
   tinted `<section class="okr-objactions">` that also carries the icon mark, heading and the
   "Created"/"Insight" meta blocks, so the whole thing reads as "these controls act on the
   OBJECTIVE" once.

   One markup, both presentations: okrRenderObjectiveDialog() reuses okrObjectiveHtml()
   wholesale, so this panel renders identically inside the Kanban "objective edit" dialog — see
   the `.okr-detail-pane` reconciliation further down this file for the adjustments that host
   needs. */
.okr-objactions{
  margin-top:14px;
  border:1px solid var(--border);
  border-radius:var(--radius-sm);
  /* One rung off `.okr-obj-body`'s own `--panel-2`, the same `--panel` every key-result card
     sits on, so this reads as raised rather than recessed — distinguished from a key-result
     card by its content, not by inventing a third surface tone. */
  background:var(--panel);
  padding:12px 14px 14px;
}
.okr-objactions-main{display:flex; flex-direction:column; gap:10px;}
.okr-objactions-intro{display:flex; align-items:flex-start; gap:10px; min-width:0;}
.okr-objactions-mark{
  flex:0 0 auto; width:26px; height:26px; border-radius:50%;
  display:flex; align-items:center; justify-content:center;
  background:var(--accent-soft); color:var(--accent-text);
}
.okr-objactions-mark svg{width:14px; height:14px;}
.okr-objactions-heading{display:flex; flex-direction:column; gap:2px; min-width:0;}
.okr-objactions-title{font-size:13px; font-weight:700; color:var(--text);}
.okr-objactions-sub{font-size:12px; color:var(--text-dim); line-height:1.4;}
/* The button row keeps `.okr-kr-actions` (see okr-objective-actions.js on why the class was
   not renamed), so its base `margin-top:10px` is now redundant with this column's own gap and
   would double the space above the buttons. Qualified four levels deep so it outranks both
   `.okr-detail-pane .okr-kr-actions` rules below regardless of source order. */
.okr-obj .okr-objactions .okr-objactions-main .okr-kr-actions{margin-top:0;}
/* The buttons become icon-and-label controls: `.btn` is already inline-flex with its own gap,
   what is missing is sizing the icon itself, since altIcon() returns a bare `<svg>` with no
   width or height of its own. Scoped to this panel rather than to `.okr-kr-actions` generally,
   since the per-key-result actions carry no icon today and a broader selector would make an
   unrelated future icon there inherit this sizing by accident. */
.okr-objactions .okr-kr-actions .btn svg{flex:0 0 auto; width:13px; height:13px;}

/* The meta block's own separation from the button row above it: okrObjectiveDetailHtml() is
   this section's only child and returns one wrapper holding the two real columns, so the
   two-column layout is styled on that class below — this rule is only the hairline that reads
   "this is a new group of facts". */
.okr-objactions-meta{margin-top:12px; padding-top:12px; border-top:1px solid var(--border-soft);}

/* The two meta columns themselves — "Created by" and "Insight" — carrying the shared
   `.okr-objmeta-col` class. The icon column is new this wave and rendered as a bare, unsized
   `<svg>` until these five rules gave it one. */
.okr-objmeta-cols{display:flex; gap:20px;}
.okr-objmeta-col{display:flex; align-items:flex-start; gap:8px; flex:1 1 0; min-width:0;}
.okr-objmeta-icon{flex:0 0 auto; margin-top:1px; color:var(--text-faint);}
.okr-objmeta-icon svg{width:14px; height:14px;}
.okr-objmeta-fact{min-width:0; flex:1 1 auto;}
/* A vertical hairline between the two where there is room, as a modifier rather than a
   sibling combinator: Insight carries a "Write insight" action Created does not, so the two
   need to be reachable on their own rather than by "whichever one comes second". */
.okr-objmeta-col--insight{border-left:1px solid var(--border-soft); padding-left:20px;}
/* …and a horizontal one instead, stacked, where there is not — a plain width query for a
   component-level breakpoint, this sheet's own convention, rather than a container query. */
@media (max-width:620px){
  .okr-objmeta-cols{flex-direction:column; gap:12px;}
  .okr-objmeta-col--insight{
    border-left:none; padding-left:0;
    border-top:1px solid var(--border-soft); padding-top:12px;
  }
}

/* ---------- status dot / pill ----------
   An objective and a key result are not the same shape: both were the diamond, so a review of
   an objective with six measures under it was seven identical markers read only by indent. The
   diamond stays with the objective — the glyph the status tiles and group headers already use
   for the roll-up — and a key result is a circle: a measure, one reading.

   A key result only carries colour when it needs attention. Reported: *"one OKR does not have 4 KRs with every colour, feels distracting"* — six measures under one objective in six status
   colours drowned out the objective's own verdict. So `behind` and `slightly behind` keep
   their colour, since a measure that late is exactly what a reviewer must not miss, and every
   other state on a KEY RESULT renders muted. The objective keeps full colour in every state. */
.okr-dot{width:10px; height:10px; border-radius:2px; transform:rotate(45deg); flex-shrink:0; margin-top:4px;}
/* A measure. No rotation, so a circle rather than a diamond. */
.okr-dot.is-kr{border-radius:50%; transform:none;}
/* And a task, in a Linked work list, is neither — on the diamond it read as an objective. */
.okr-dot.is-task{border-radius:2px; transform:none; width:9px; height:9px;}
.okr-pill{
  display:inline-flex; align-items:center; gap:5px; font-size:11px; font-weight:700;
  letter-spacing:.04em; padding:2px 7px; border-radius:999px; white-space:nowrap;
  border:1px solid transparent;
}
.st-behind         .okr-dot, .okr-dot.st-behind         {background:var(--okr-behind);}
.st-slightly_behind .okr-dot, .okr-dot.st-slightly_behind{background:var(--okr-slightly);}
.st-on_track       .okr-dot, .okr-dot.st-on_track       {background:var(--okr-ontrack);}
.st-ahead          .okr-dot, .okr-dot.st-ahead          {background:var(--okr-ahead);}
.st-completed      .okr-dot, .okr-dot.st-completed      {background:var(--okr-done);}
.st-not_started    .okr-dot, .okr-dot.st-not_started    {background:var(--okr-idle);}
/* `not_scored` is not a seventh health colour — it is the one status this board deliberately
   never scores, so it borrows the quiet ramp already reserved for "this doesn't need a
   colour" rather than a dedicated --okr-* pair. It reads plainer than even Not Started's idle
   grey on purpose: that one is a real health verdict, this one is excluded from the quarter
   entirely. No `.okr-stat` or `.fill-` counterpart exists for it and none should be added —
   see the file-header comment above and OKR_STATUS_ORDER. */
.okr-dot.st-not_scored{background:var(--okr-quiet);}

.okr-pill.st-behind{background:var(--okr-behind-soft); color:var(--okr-behind-text); border-color:var(--okr-behind);}
.okr-pill.st-slightly_behind{background:var(--okr-slightly-soft); color:var(--okr-slightly-text); border-color:var(--okr-slightly);}
.okr-pill.st-on_track{background:var(--okr-ontrack-soft); color:var(--okr-ontrack-text); border-color:var(--okr-ontrack);}
.okr-pill.st-ahead{background:var(--okr-ahead-soft); color:var(--okr-ahead-text); border-color:var(--okr-ahead);}
.okr-pill.st-completed{background:var(--okr-done-soft); color:var(--okr-done-text); border-color:var(--okr-done);}
.okr-pill.st-not_started{background:var(--okr-idle-soft); color:var(--okr-idle-text); border-color:var(--okr-idle);}
/* Hollow, not filled: a first cut used the same "muted" tokens an idle key result dot uses for
   its fill and text, but those alias to the identical values `not_started` already uses, so the
   two pills came out pixel-identical apart from the border — and a 1px border is not what a
   reader's eye catches. Borrowed `.okr-cell.empty`'s own idiom instead — transparent, not
   soft-filled, for "nothing to report here" — a stronger signal than a fill this pale can give. */
.okr-pill.st-not_scored{background:transparent; color:var(--okr-quiet); border-color:var(--border-soft);}

.okr-stat.st-behind .okr-stat-n{color:var(--okr-behind-text);}
.okr-stat.st-slightly_behind .okr-stat-n{color:var(--okr-slightly-text);}
.okr-stat.st-on_track .okr-stat-n{color:var(--okr-ontrack-text);}
.okr-stat.st-ahead .okr-stat-n{color:var(--okr-ahead-text);}
.okr-stat.st-completed .okr-stat-n{color:var(--okr-done-text);}
.okr-stat.st-not_started .okr-stat-n{color:var(--okr-idle-text);}

.fill-behind{background:var(--okr-behind);}
.fill-slightly_behind{background:var(--okr-slightly);}
.fill-on_track{background:var(--okr-ontrack);}
.fill-ahead{background:var(--okr-ahead);}
.fill-completed{background:var(--okr-done);}
.fill-not_started{background:var(--okr-idle);}

/* THE QUIET STATES, ON A KEY RESULT ONLY. `.is-kr` is set by the renderer, so one rule pair
   covers the marker and the bar and there is no second idea of which states are loud.
   Specificity: (0,2,0) beats the (0,1,0) rules above, and both are needed — the loud states
   still come from them. */
.okr-dot.is-kr.st-on_track,
.okr-dot.is-kr.st-ahead,
.okr-dot.is-kr.st-completed,
.okr-dot.is-kr.st-not_started{background:var(--okr-quiet);}
.okr-progress.is-kr .fill-on_track,
.okr-progress.is-kr .fill-ahead,
.okr-progress.is-kr .fill-completed,
.okr-progress.is-kr .fill-not_started{background:var(--okr-quiet);}
/* Completed is the one quiet state worth telling apart from "nothing has happened": it is
   done, not idle. A tint of the same neutral rather than a sixth colour. */
.okr-dot.is-kr.st-completed{background:var(--okr-quiet-strong);}
.okr-progress.is-kr .fill-completed{background:var(--okr-quiet-strong);}
/* A linked task is not a measure and carries no pace, so its marker is never a status
   colour — open or done, and the row's strike-through already says which. */
.okr-dot.is-task{background:var(--okr-quiet);}
.okr-dot.is-task.st-completed{background:var(--okr-quiet-strong);}

/* ---------- portfolio grid (Overview) ---------- */
.okr-card{
  background:var(--panel); border:1px solid var(--border); border-radius:var(--radius);
  padding:16px 18px; margin-bottom:14px;
  /* Stated, because some of these cards ARE buttons — a `<button>` with a background and no
     colour inherits the UA's black `buttontext`, which fails contrast in dark mode. Every
     surface in this file that can be a control names its own text colour for that reason. */
  color:var(--text);
}
.okr-card h2{
  font-size:16px; font-weight:700; margin:0 0 3px;
  border-left:3px solid var(--accent); padding-left:9px;
}
.okr-card .okr-card-sub{font-size:13px; color:var(--text-dim); margin:0 0 14px; padding-left:12px;}
.okr-grid-scroll{overflow-x:auto;}
.okr-grid{border-collapse:separate; border-spacing:5px; width:100%; min-width:520px;}
.okr-grid th{
  font-size:11px; font-weight:700; letter-spacing:.07em; text-transform:uppercase;
  color:var(--text-dim); padding:4px 6px; text-align:center; font-weight:700;
}
.okr-grid th.okr-now{color:var(--accent-text);}
.okr-grid td.okr-area-name{
  font-size:13px; font-weight:600; color:var(--text); text-align:left;
  white-space:nowrap; padding-right:10px; width:1%;
}
.okr-cell{
  border:1px solid var(--border-soft); border-radius:var(--radius-sm);
  padding:9px 11px; text-align:center; width:100%;
  background:var(--panel-2); color:var(--text);
  display:flex; align-items:center; justify-content:center; gap:8px;
}
.okr-cell:hover{border-color:var(--accent);}
.okr-cell.empty{background:transparent; border-style:dashed; color:var(--text-faint);}
/* Now is structure, not selection: a fill means "in the filter" and nothing else, so the
   current quarter is marked by its heading and a stronger edge instead of the filter's own
   accent colour. */
.okr-cell.now{border-color:var(--border-strong);}
.okr-cell-pct{font-size:14px; font-weight:700; font-variant-numeric:tabular-nums;}
.okr-mini{width:20px; height:20px; flex-shrink:0;}
.okr-total-row .okr-cell{background:var(--panel); font-weight:700;}

/* ---------- the blue is the status being hunted ----------
   One strength, not two. `.in-scope` is a wash under the existing content, derived in
   okrCellScopeClass() from the filter state — the percentage keeps `--text`, the mini ring
   keeps its status colours, and the rule touches nothing semantic. A second tier, `.in-focus`,
   existed for the intersection of two or more narrowed dimensions; the period filter now
   removes out-of-scope columns and rows rather than washing them, so every drawn cell is in
   scope by construction and nothing emits that class any more.

   Distinct from hover, which is the 1px border going accent and nothing else — selection
   speaks through the surface, hover through the edge. */
.okr-cell.in-scope{background:var(--scope-soft);}
.okr-cell.empty.in-scope{background:var(--scope-soft);}
.okr-total-row .okr-cell.in-scope{background:var(--scope-soft);}
/* The axis. A selected heading and a selected row label carry the narrowing that the cells
   cannot state without washing squares the filter has excluded — which would be the matrix
   disagreeing with the list beneath it. */
.okr-grid th.is-scope{color:var(--accent-text);}
.okr-grid td.okr-area-name.is-scope{color:var(--accent-text);}

/* A bounded number field in a `.pref-row`, beside the switches — narrow because the value is
   two digits and a field sized for a sentence invites one. The selector carries the type
   deliberately: a bare class loses on specificity to the page's own `input[type=number]` rule
   whatever the load order, which otherwise rendered the field full row width. */
input[type=number].okr-pref-num{
  width:76px; flex:0 0 auto; text-align:center;
  font-variant-numeric:tabular-nums;
}

.okr-tiles{display:grid; grid-template-columns:repeat(auto-fit, minmax(150px,1fr)); gap:10px;}
/* The readiness tiles are buttons. The big number used to come out as unstyled black on the
   panel, which passed in light mode by accident and failed contrast in dark. The number takes
   `--text` and the label `--text-dim`, the same hierarchy `.okr-cell` already uses, and
   interactive states match `.okr-cell` too so the two clickable surfaces behave alike. */
.okr-tile{
  background:var(--panel-2); border:1px solid var(--border-soft);
  border-radius:var(--radius-sm); padding:13px 14px;
  color:var(--text); text-align:left; width:100%; cursor:pointer;
}
.okr-tile:hover{border-color:var(--accent);}
.okr-tile:focus-visible{outline:2px solid var(--focus-ring); outline-offset:2px;}
.okr-tile-n{font-size:24px; font-weight:700; line-height:1; font-variant-numeric:tabular-nums; color:var(--text);}
/* A tile flagging a problem overrides the number's colour inline — that stays, and it is a
   status colour on a status token, not a decoration. */
.okr-tile[data-warn="1"] .okr-tile-n{color:var(--okr-slightly-text);}
.okr-tile-l{font-size:11px; font-weight:700; letter-spacing:.07em; text-transform:uppercase; color:var(--text-dim); margin-top:5px;}

.okr-hygiene{display:flex; align-items:center; gap:11px; width:100%; text-align:left;
  background:none; border:none; border-bottom:1px solid var(--border-soft); padding:11px 2px; color:var(--text);}
.okr-hygiene:last-child{border-bottom:none;}
.okr-hygiene:hover{color:var(--accent-text);}
.okr-hygiene-n{
  min-width:26px; height:26px; border-radius:var(--radius-sm); flex-shrink:0;
  background:var(--okr-slightly-soft); color:var(--okr-slightly-text);
  display:flex; align-items:center; justify-content:center; font-size:12px; font-weight:700;
}
.okr-hygiene-t{font-size:13px; flex:1 1 auto;}

.okr-empty{
  text-align:center; padding:44px 20px; color:var(--text-dim);
  border:1px dashed var(--border); border-radius:var(--radius); background:var(--panel);
}
.okr-empty h3{font-size:16px; color:var(--text); margin:0 0 7px;}
.okr-empty p{font-size:13px; margin:0 auto 16px; max-width:420px;}

/* ---------- responsive ---------- */
@media (max-width: 1080px){
  .okr-stats{grid-template-columns:repeat(3, minmax(0,1fr));}
  /* TOO NARROW TO SPEND A LINE ON. Below this the objective row is already tight, and a
     sentence under the badge would push the title off its baseline. The badge keeps its
     tooltip — which is the whole reason the tooltip was kept rather than replaced. */
  .okr-obj-head .okr-hidden-note{display:none;}
}
@media (max-width: 820px){
  .okr-summary{grid-template-columns:1fr; gap:14px;}
  .okr-stats{grid-template-columns:repeat(2, minmax(0,1fr));}
  .okr-obj-inner{padding-left:20px;}
  .okr-obj-head{grid-template-columns:20px 12px minmax(0,1fr); }
  /* The percentage moves under the title rather than being squeezed against it. */
  .okr-obj-right{grid-column:3; margin-top:6px;}
  .okr-band h1{font-size:21px;}
}

/* ---------- settings pane rows ----------
   Shares .weather-loc-row from the Studio's settings so an area row and a weather-location
   row are the same object; only the identity column differs. */
.okr-cfg-row{display:flex; align-items:center; gap:10px;}
.okr-cfg-id{flex:1 1 auto; min-width:0;}
.okr-cfg-id .nm{font-size:13px; font-weight:600; color:var(--text);}
.okr-cfg-id .sub{font-size:12px; color:var(--text-faint); margin-top:2px;}
/* The settings pane is sized by the sizer, not by this rule — okrSizeSettings() calls the
   shared sizeSettingsDialog(), which sets an explicit width and height so the dialog does not
   change size as the reader moves between tabs. The width here is only the fallback and the
   floor a very narrow window gets. */
.okr-settings-pane{width:min(680px, 96vw);}
/* The strip clears the header's rule, which otherwise sat the tab strip hard against the
   border under `.okr-modal-head` so the tabs read as part of the header. The gap is declared
   once, on the strip, not per tab — a `.modal-tab` is a pill inside a padded track, so padding
   a tab moves the label inside its own pill rather than the track. 12px on the 4px scale
   (§14a); the bottom stays 0 since `.okr-modal-body` already has its own padding below. */
.okr-settings-pane .modal-tabs{margin:12px 16px 0;}
/* A fixed height needs something to absorb it, or the pane shows a band of empty panel under
   the last row. Head, tabs and foot are pinned so the body is the only thing that scrolls —
   §12's rule for every tall dialog here. */
.okr-settings-pane .okr-modal-body{flex:1 1 auto; min-height:0;}
.okr-settings-pane .okr-modal-head,
.okr-settings-pane .modal-tabs,
.okr-settings-pane .okr-modal-foot{flex:0 0 auto;}

/* ---------- "Supports" in the task panel ----------
   Loaded by tasks.html, which is why it lives here rather than in that page's own sheet: this
   is the one place the health colours are defined, and this block needs `.okr-dot`, `.fill-*`
   and `.okr-progress`. */
.okr-support{
  margin-top:10px; padding-top:10px; border-top:1px solid var(--border-soft);
}
/* The heading carries the "How this works" link, so it is a row rather than a word: the
   heading on the left, the explanation at the far end where the eye lands last. */
/* The linked-task count on a key result's meta line. It is a button and it looks like the
   text beside it: the row is a summary, and a control that shouts inside one is a control that
   competes with the measure it belongs to. */
.okr-kr-linkcount{
  background:none; border:none; padding:0; font:inherit; color:inherit; cursor:pointer;
  text-decoration:underline dotted; text-underline-offset:2px;
}
.okr-kr-linkcount:hover{ color:var(--accent-text); }
.okr-kr-linkcount:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }

.okr-support-h{
  font-size:11px; font-weight:700; letter-spacing:.07em; text-transform:uppercase;
  color:var(--text-faint); margin-bottom:6px;
  display:flex; align-items:baseline; justify-content:space-between; gap:10px;
}
.okr-support-empty{font-size:12px; color:var(--text-faint); line-height:1.5;}
.okr-support-empty a{color:var(--accent-text);}
.okr-support-item{
  display:flex; align-items:flex-start; gap:9px;
  background:var(--panel-2); border:1px solid var(--border-soft);
  border-radius:var(--radius-sm); padding:9px 10px; margin-bottom:6px;
}
.okr-support-item:last-child{margin-bottom:0;}
.okr-support-body{flex:1 1 auto; min-width:0;}
.okr-support-obj{font-size:13px; font-weight:600; color:var(--text); line-height:1.35;}
.okr-support-kr{font-size:12px; color:var(--text-dim); margin-top:2px; line-height:1.35;}
.okr-support-meta{
  font-size:11px; color:var(--text-faint); margin-top:3px;
  font-variant-numeric:tabular-nums;
}
.okr-support .okr-progress{margin-top:6px; height:4px;}

/* The settings error line. Uses the shared .weather-empty container so a failure sits
   where the empty state would, rather than introducing a second kind of message box. */
.okr-cfg-err{display:block; margin-bottom:8px; color:var(--red-text);}

/* A key result measured in a quarter other than its objective's. Accent-coloured because
   it is the exception, not decoration on every row. */
.okr-kr-cycle{
  color:var(--accent-text); font-weight:700;
  background:var(--accent-soft); border-radius:4px; padding:1px 5px;
}

/* ---------- the OKR workflow launched from a task ----------
   Shared by the task app and the team board — one set of controls, one picker.

   The choices used to sit behind an `+ Add to OKR` button that opened a menu. They are
   ordinary .btn buttons in the panel now: the section only appears because somebody ticked
   `Mark as an OKR`, so a second click to find out what they can do next buys nothing. */

.okr-support-actions{ display:flex; flex-wrap:wrap; gap:6px; margin-top:9px; }

/* Both rungs of the ladder — the key result is the measure, the objective is the point of
   it — so they are two destinations and get two links. */
.okr-support-links{ display:flex; flex-direction:column; gap:5px; flex:0 0 auto; }

/* The searchable picker. Scrolls inside itself so a team with three years of objectives
   does not turn the dialog into a page. */
.task-okr-results{ max-height:320px; overflow-y:auto; margin-top:8px; }
.task-okr-result{
  display:block; width:100%; text-align:left; padding:8px 10px; margin-bottom:5px;
  background:var(--panel-2); border:1px solid var(--border);
  border-radius:var(--radius-sm); cursor:pointer;
}
.task-okr-result:hover,.task-okr-result:focus-visible{ border-color:var(--accent); }
.task-okr-result b{ display:block; font-size:13px; color:var(--text); }
/* The objective and quarter, because key result titles repeat across quarters. */
.task-okr-result span{ display:block; margin-top:2px; font-size:12px; color:var(--text-faint); }

.task-okr-removing{ margin:8px 0 0; padding-left:18px; }
.task-okr-removing li{ font-size:13px; color:var(--text-dim); line-height:1.6; }

/* A task that supports an objective with no key result between: there is no measure, so
   there is no bar and no colour to report. */
.okr-dot.st-none{ background:var(--border-strong); }

/* ---------- The shared OKR dialog ----------
   One pane, three pages: okrs.html creates and edits objectives with it, and the task app and
   the team board create them from a task through the same component. These rules used to live
   in okrs.html's own `<style>`, so on the other two pages the dialog opened with no position,
   no backdrop and no z-index — an ordinary block at the foot of the document, below
   everything, so "Add to OKR" appeared to do nothing. A dialog shared between pages cannot
   keep its chrome in one of them. */
.okr-modal{
  position:fixed; inset:0; background:rgba(4,10,20,.62);
  /* An ordinary dialog by default, raised above whatever launched it by layers.js when opened
     from inside the task modal — the only thing that can be right, since a shared dialog
     cannot know what it will be opened on top of. */
  z-index:var(--z-dialog);
  display:none; align-items:center; justify-content:center; padding:20px;
}
.okr-modal-pane{
  background:var(--panel); border:1px solid var(--border-strong); border-radius:var(--radius);
  width:min(620px, 96vw); max-height:min(88vh, 900px); display:flex; flex-direction:column;
  box-shadow:0 24px 60px rgba(0,0,0,.5);
  /* The shared launch — sys_design-system.md §2b. This shell is not the `.modal-overlay` /
     `.modal-card` pair the rest of the application uses, so that rule never reached the OKR
     dialogs on its own. The animation is not declared here: `.okr-modal-pane` is named in the `.surface-enter` selector in CSS/components.css, so there is one geometry and one clock
     rather than a second copy that can drift, and its reduced-motion answer comes with it.
     It launches but does not close, deliberately — okrCloseModal() clears the host's
     innerHTML, so by the time a close could animate there is nothing left to move. */
}
.okr-modal-head{
  display:flex; align-items:center; justify-content:space-between; gap:10px;
  padding:14px 16px; border-bottom:1px solid var(--border);
}
.okr-modal-head h2{font-size:16px; margin:0;}
.okr-modal-body{padding:16px; overflow-y:auto;}
.okr-modal-foot{
  display:flex; align-items:center; gap:8px; padding:12px 16px;
  border-top:1px solid var(--border);
}
.okr-modal-msg{flex:1 1 auto; font-size:13px; color:var(--text-dim); min-width:0;}
.okr-modal-msg.err{color:var(--red-text);}
.okr-field{display:block; margin-bottom:13px;}
.okr-field > span{
  display:block; font-size:11px; font-weight:700; letter-spacing:.06em;
  text-transform:uppercase; color:var(--text-dim); margin-bottom:5px;
}
.okr-field > span i{font-style:normal; font-weight:400; text-transform:none; letter-spacing:0; color:var(--text-faint);}
.okr-field-row{display:grid; grid-template-columns:repeat(auto-fit, minmax(140px,1fr)); gap:11px;}

/* The owner-access note — the objective editor, the key-result editor and okr-bulk.js's bulk
   owner-change pane all draw this through one shared okrOwnerAccessNoteHtml(), so there is
   exactly one rule to keep in step with it. Not a new recipe: `.okr-scope-banner` above
   already washes this page's accent-soft/accent combination for an informational strip; this
   is the same tokens, in the softer shape used for a note beside a field — dim body text,
   only the icon carrying the accent colour, because a banner announces and this note informs.
   *"Soft"* is the owner's own word for it. */
.okr-owner-note{
  display:flex; align-items:flex-start; gap:8px;
  margin-top:8px; padding:8px 10px;
  border:1px solid var(--accent); background:var(--accent-soft); border-radius:var(--radius);
  font-size:11px; line-height:1.45; color:var(--text-dim);
}
.okr-owner-note svg{flex:0 0 auto; margin-top:1px; color:var(--accent-text);}
.okr-hint{font-size:13px; color:var(--text-dim); margin:0 0 13px; line-height:1.5;}
.okr-danger{
  display:flex; align-items:center; gap:10px; flex-wrap:wrap;
  border-top:1px solid var(--border-soft); margin-top:6px; padding-top:13px;
}
.okr-danger span{font-size:12px; color:var(--text-faint);}
.okr-history{margin:0 0 13px; max-height:230px; overflow-y:auto;}
.okr-history-row{
  border-bottom:1px solid var(--border-soft); padding:8px 0;
  display:flex; flex-wrap:wrap; gap:8px; align-items:baseline; font-size:13px; color:var(--text-dim);
}
.okr-history-row:last-child{border-bottom:none;}
.okr-history-row b{color:var(--text); font-size:14px;}
.okr-history-row p{flex:1 1 100%; margin:3px 0 0; color:var(--text);}

/* Arrived here from a task's "View" button. Marked until the next click rather than on a
   timer, so it is still highlighted when the reader finishes reading it. */
.okr-arrived{
  outline:2px solid var(--accent); outline-offset:3px; border-radius:var(--radius-sm);
}

/* ---------- Carryover, hygiene findings and the digest ----------

   The three panels that turn the overview from a report into a list of decisions. Built
   from the same card, chip, dot and button the rest of this page uses — the reference's
   look comes from density and hierarchy, not from a second visual language. */

.okr-card-head{
  display:flex; align-items:baseline; gap:10px; flex-wrap:wrap; margin-bottom:10px;
}
.okr-card-head h2{margin:0;}
/* Inside a head the sub is a caption beside the title, not the block under it. */
.okr-card-head .okr-card-sub{margin:0; padding:0;}
.okr-card-note{font-size:12px; color:var(--text-faint); line-height:1.5; margin:0 0 10px; padding-left:12px;}

/* ---------- carryover ---------- */

/* TWO CONTROLS IN ONE ROW: the row itself edits the measure, the chevron shows it in the
   objectives list. The `<li>` is the frame and holds the border; neither of its buttons draws
   one, so the pair still reads as a single row rather than as two chips. `:focus-within`
   rather than `:focus-visible` on the row, because the thing being focused is now a child. */
.okr-carry-list{list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:6px;}
.okr-carry-row{
  display:flex; align-items:stretch;
  border:1px solid var(--border); border-radius:var(--radius-sm);
  background:var(--panel-2); overflow:hidden;
}
.okr-carry-row:hover,.okr-carry-row:focus-within{border-color:var(--accent);}
.okr-carry-open{
  flex:1 1 auto; min-width:0;
  display:flex; align-items:center; gap:10px; cursor:pointer; text-align:left;
  padding:9px 11px; background:none; border:0;
  /* A <button> inherits neither the page font nor its colour from an ancestor — the UA
     supplies both, and its `buttontext` is black on --panel-2 in dark mode. Every control
     surface in this file names its own for that reason. */
  font:inherit; color:var(--text);
}
.okr-carry-main{flex:1 1 auto; min-width:0;}
.okr-carry-kr{display:block; font-size:13px; color:var(--text);}
.okr-carry-obj{
  display:block; font-size:12px; color:var(--text-faint);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.okr-carry-meta{display:flex; align-items:center; gap:8px; flex:0 0 auto;}
/* How long it has been sitting is the number that turns a list into an ordering, so it is
   the one that reads as a warning. */
.okr-carry-days{font-size:12px; color:var(--warn-text); white-space:nowrap;}
.okr-carry-pct{font-size:12px; font-weight:700; color:var(--text-dim); min-width:38px; text-align:right;}

/* ---------- hygiene ---------- */

.okr-hyg-list{list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:6px;}
.okr-hyg-row{
  display:flex; align-items:center; gap:12px; cursor:pointer;
  padding:9px 11px; border:1px solid var(--border); border-radius:var(--radius-sm);
  background:var(--panel-2);
}
.okr-hyg-row:hover,.okr-hyg-row:focus-visible{border-color:var(--accent);}
.okr-hyg-n{
  flex:0 0 auto; min-width:28px; text-align:center;
  font-size:15px; font-weight:700; color:var(--warn-text);
}
.okr-hyg-body{flex:1 1 auto; min-width:0;}
.okr-hyg-title{display:block; font-size:13px; color:var(--text);}
.okr-hyg-why{display:block; font-size:12px; color:var(--text-faint); line-height:1.45;}
.okr-hyg-go{flex:0 0 auto; color:var(--text-faint); font-size:17px;}
.okr-hyg-row:hover .okr-hyg-go{color:var(--accent-text);}

.okr-hyg-items{list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:5px;}
/* Same pair as a carryover row, same reason — see .okr-carry-row above. */
.okr-hyg-item-row{
  display:flex; align-items:stretch;
  border:1px solid var(--border); border-radius:var(--radius-sm);
  background:var(--panel-2); overflow:hidden;
}
.okr-hyg-item-row:hover,.okr-hyg-item-row:focus-within{border-color:var(--accent);}
.okr-hyg-item{
  flex:1 1 auto; min-width:0;
  display:block; text-align:left; cursor:pointer;
  padding:8px 10px; border:0; background:none; color:var(--text); font-family:inherit;
}
.okr-hyg-item b{display:block; font-size:13px;}
.okr-hyg-item span{display:block; font-size:12px; color:var(--text-faint);}

/* ---------- the square controls at the end of a carryover or finding row ----------
   One appearance for the slot, one glyph per action: `.okr-signal-side` is the chrome — the
   30px square, the dividing rule, the muted colour, the hover — and `.okr-signal-goto` (a
   chevron) and `.okr-signal-parent` (a ring) are the two actions that wear it, with the
   per-panel classes existing only so a handler can tell the panels apart. Splitting the slot
   from the action this way means a second action in the same slot costs one selector rather
   than a second copy of the chrome rules, or a button inheriting a class named after somebody
   else's action. */
.okr-signal-side{
  flex:0 0 auto; width:30px;
  display:flex; align-items:center; justify-content:center;
  padding:0; border:0; border-left:1px solid var(--border); background:none;
  color:var(--text-faint); font-size:17px; line-height:1; cursor:pointer;
}
.okr-signal-side:hover,.okr-signal-side:focus-visible{color:var(--accent-text); background:var(--panel);}
/* A RING READS SMALLER THAN A CHEVRON AT THE SAME SIZE. Nudged so the two controls sit on one
   optical line rather than one measured one. */
.okr-signal-parent{font-size:15px;}
/* The focus ring belongs to the button, not to the row that borders it — a reader tabbing
   between the controls has to see which one they are on. */
.okr-carry-open:focus-visible,.okr-hyg-item:focus-visible,.okr-signal-side:focus-visible{
  outline:2px solid var(--accent); outline-offset:-2px;
}

/* ---------- digest ---------- */

.okr-digest-actions{margin-left:auto; display:flex; gap:6px; flex:0 0 auto;}
.okr-digest-tiles{
  display:grid; grid-template-columns:repeat(auto-fit, minmax(104px, 1fr));
  gap:8px; margin-bottom:12px;
}
.okr-digest-tile{
  background:var(--panel-2); border:1px solid var(--border-soft);
  border-radius:var(--radius-sm); padding:9px 11px;
}
.okr-digest-n{display:block; font-size:18px; font-weight:700; color:var(--text); line-height:1.2;}
.okr-digest-l{
  display:block; font-size:11px; font-weight:700; letter-spacing:.05em;
  text-transform:uppercase; color:var(--text-faint); margin-top:2px;
}
.okr-digest-text{
  font-size:13px; line-height:1.6; color:var(--text); margin:0 0 8px;
  /* A quoted band, so a paragraph a model wrote is visibly not a figure this app computed —
     the tiles above it are the numbers, this is the reading of them. */
  border-left:3px solid var(--border-strong); padding-left:11px;
}
.okr-digest-prov{font-size:11px; color:var(--text-faint); margin:0; padding-left:14px;}
.okr-digest-stale{color:var(--warn-text);}
.okr-digest-working{margin:0 0 8px; padding-left:14px;}

/* ---------- The progress control ----------

   The bar IS the control. Same shape it had as a read-only indicator, so nothing moved on
   the page — it simply became draggable, with a number beside it for measures whose units
   are not a percentage ("21 signups" is what somebody types). */

.okr-progress-row{display:flex; align-items:center; gap:10px; margin-top:9px;}
.okr-progress-row .okr-progress-wrap{flex:1 1 auto; min-width:0;}
.okr-progress-row .okr-progress{margin-top:0;}

/* A hit area a finger can find: the bar itself is 6px, fine to look at and unusable to grab, so
   padding grows the target and a negative margin gives the space back to the layout, leaving
   the drawing untouched. 9px makes the target exactly the 24px pointer floor (§18) — this
   control is a drag, the one kind where a near-miss starts a gesture somewhere else rather than
   simply doing nothing. Vertical only: the bar is already full width, and side padding would
   put the grab zone outside the track it represents. */
.okr-progress-live{cursor:ew-resize; padding:9px 0; margin:-9px 0;}
.okr-progress-live:focus-visible{outline:2px solid var(--focus-ring); outline-offset:3px; border-radius:4px;}
.okr-progress-live:hover .okr-progress{background:var(--panel);}

.okr-prog-num{display:flex; align-items:baseline; gap:5px; flex:0 0 auto;}
.okr-prog-num input{width:74px; text-align:right; padding:4px 7px; font-size:13px;}
.okr-prog-unit{font-size:12px; color:var(--text-faint); white-space:nowrap;}

/* A control measure is not a journey, so it gets a verdict rather than a bar — and the
   WORD, never the colour alone. */
.okr-band-readout{
  flex:1 1 auto; font-size:12px; font-weight:600;
  padding:4px 9px; border-radius:999px; border:1px solid var(--border);
}
.okr-band-readout.ok{background:var(--green-soft); color:var(--green-text); border-color:var(--green);}
.okr-band-readout.out{background:var(--red-soft); color:var(--red-text); border-color:var(--red);}
/* AND THE THIRD STATE. A control measure with neither bound stated is not in breach — there is
   no band to breach — so it is quiet rather than red. Added when the readout was found calling
   an unconfigured measure "Outside the band" beside a label reading "no band set". */
.okr-band-readout.none{ color:var(--text-dim); background:transparent; border-color:var(--border); }

/* ---------- the check-in that follows a change ---------- */

.okr-checkin-prompt{
  margin-top:9px; padding:10px 11px;
  background:var(--panel-2); border:1px solid var(--accent);
  border-radius:var(--radius-sm);
}
.okr-checkin-h{display:flex; align-items:center; gap:9px; margin-bottom:7px;}
.okr-checkin-h b{font-size:13px; color:var(--accent-text);}
.okr-checkin-h span{font-size:12px; color:var(--text-dim); flex:1 1 auto;}
.okr-checkin-prompt textarea{width:100%; font-size:13px;}
.okr-checkin-actions{display:flex; align-items:center; gap:10px; margin-top:7px; flex-wrap:wrap;}
/* The sentence that stops somebody thinking dismissal undoes their edit. */
.okr-checkin-note{font-size:11px; color:var(--text-faint); flex:1 1 160px;}
.okr-checkin-note.err{color:var(--red-text);}

/* `.sr-only-okr` — visible to a screen reader, not to the eye: the number box's label, which
   the unit beside it already conveys visually. The rule is in CSS/components.css, listed with
   every other name for the same thing; every page that loads this file loads that one too. */

/* Link an existing task, or make one. Two verbs, one row. */
.okr-linked-actions{display:flex; gap:6px; margin-top:8px; flex-wrap:wrap;}

/* ---------- The detail behind a key result ----------

   The row stays the summary; this is the workspace behind it. Built from the same card
   surface, disclosure headers and buttons the rest of the page uses. */

.okr-kr-detail-slot{margin-top:10px;}
.okr-kr-detail{
  background:var(--panel-2); border:1px solid var(--border-soft);
  border-radius:var(--radius-sm); padding:2px 12px 10px;
}

/* Facts read as a grid rather than a form: nothing here is typed, so labelled boxes would
   be pretending otherwise. */
.okr-detail-grid{
  display:grid; grid-template-columns:repeat(auto-fit, minmax(128px, 1fr));
  gap:9px; padding:4px 0 8px;
}
.okr-fact{min-width:0;}
.okr-fact-l{
  display:block; font-size:11px; font-weight:700; letter-spacing:.05em;
  text-transform:uppercase; color:var(--text-faint);
}
.okr-fact-v{display:block; font-size:13px; color:var(--text); margin-top:2px; overflow-wrap:anywhere;}

.okr-detail-notes{font-size:13px; color:var(--text-dim); line-height:1.55; margin:0 0 9px;}
.okr-detail-empty{font-size:12px; color:var(--text-faint); margin:4px 0 8px;}

/* ---------- check-in history ---------- */

.okr-checkin-history{display:flex; flex-direction:column; gap:5px; padding-bottom:6px;}
.okr-ci-row{
  display:flex; align-items:baseline; gap:9px;
  padding:6px 9px; background:var(--panel); border:1px solid var(--border-soft);
  border-radius:var(--radius-sm);
}
.okr-ci-val{font-size:13px; color:var(--accent-text); flex:0 0 auto;}
.okr-ci-note{flex:1 1 auto; min-width:0; font-size:13px; color:var(--text-dim);}
.okr-ci-when{flex:0 0 auto; font-size:11px; color:var(--text-faint);}

/* ---------- the insight panel ----------

   The same panel for a key result, an objective and the quarter digest — one provenance
   model, one staleness rule, one failure behaviour. */

.okr-insight{padding:2px 0 6px;}
.okr-insight-text{
  font-size:13px; line-height:1.6; color:var(--text); margin:0 0 7px;
  /* A quoted band, so a paragraph a model wrote is visibly not a figure this app computed. */
  border-left:3px solid var(--border-strong); padding-left:11px;
}
.okr-insight-prov{font-size:11px; color:var(--text-faint); margin:0 0 8px; padding-left:14px;}
.okr-insight-stale{color:var(--warn-text);}
.okr-insight-none{font-size:12px; color:var(--text-faint); margin:0 0 8px; line-height:1.5;}
.okr-insight-working{margin:0 0 8px;}

/* The vocabulary pane groups its three rungs, because a flat list of departments, areas and
   products mixed together does not read as a hierarchy — which is the only reason all three
   exist rather than one. */
.okr-cfg-group{
  font-size:11px; font-weight:700; letter-spacing:.06em; text-transform:uppercase;
  color:var(--text-faint); margin:12px 0 5px;
}
.okr-cfg-group:first-child{margin-top:0;}
/* Retired rows stay legible — they are still on historic objectives — but read as past. */
.okr-cfg-row.retired .nm{color:var(--text-faint);}

/* The head of the objectives list: its title on the left, the expand/collapse pair on the
   right. These controls used to sit in the filter band above, where they read as page-level
   and gave no clue what they would open. Wraps to two rows on a narrow viewport rather than
   letting the buttons overflow — see the responsive-controls rule in CLAUDE.md. */
.okr-list-head{
  /* The controls are the same height, so aligning them is not a question of picking an
     alignment property. Bottom-aligning was tried first and looked wrong, since boxes of
     different heights sharing a baseline still stagger at the top. Make them one height and
     `align-items:center` is exact — see `.okr-list-head .okr-sort select` below for the pixels
     a `<select>` adds over a `.btn.small` with the same padding. */
  display:flex; align-items:center; gap:10px; flex-wrap:wrap;
  margin:18px 0 8px;
}
.okr-list-title{
  margin:0; font-size:13px; font-weight:700; letter-spacing:.4px;
  text-transform:uppercase; color:var(--text-dim);
}
@media (max-width:640px){
  .okr-list-head{ align-items:stretch; }
  .okr-list-head .btn{ flex:1 1 auto; }
}

/* A one-line explanation under a field, for the cases where the control alone cannot say
   what blank means. */
.okr-field-hint{ display:block; margin-top:4px; font-size:11px; color:var(--text-faint); line-height:1.4; }

/* Team switcher. It sits in the TOPBAR now, immediately after the Team button, because
   which team you are looking at is the page's context rather than a filter on the snapshot
   below it. Only drawn for an account with more than one team.

   min-width:0 and a max: the topbar wraps through .control-row, and a 150px floor on a
   select holding a long team name is what pushes a row past the right edge. */
.okr-team-switch{ display:inline-flex; align-items:center; gap:6px; margin-left:6px; min-width:0; }
/* The neighbouring .btn.small controls measure 25px; a select left at its own intrinsic
   34px reads as a heavier control than the buttons it sits beside. Middles already agreed —
   the topbar centres its line — so this is about weight, not alignment. */
.okr-team-switch select{ width:auto; min-width:0; max-width:190px; height:25px; padding-top:0; padding-bottom:0; }

/* ---------- Compact objectives ----------
   Density, not a second view — the same markup with less room given to what people read once,
   so more key results fit on a screen. Nothing hidden carries meaning: the status pill, the
   progress bar and the quarter stay; what goes is breathing room and descriptive prose, which
   is available the moment an objective is opened. This is simply how the board looks now,
   rather than one state behind a toggle — one spacing means nothing to drift and nothing for
   a reader to discover by trying it. */
.okr-group{ margin-bottom:10px; }
.okr-group-head{ padding:5px 8px; }
.okr-obj{ margin-bottom:6px; }
.okr-obj-head{ padding:7px 10px; gap:8px; }
.okr-obj-title{ font-size:13px; }
.okr-obj-desc{ display:none; }
.okr-kr{ padding:5px 10px; gap:8px; }
.okr-kr-title{ font-size:12px; }
/* Contributors sit in the meta line with the owner and the pace, one shade quieter: the
   owner is who answers for the number, the rest are who is helping. */
.okr-kr-contribs{ color:var(--text-dim); }

/* "+2 outside" beside an objective's percentage: the measures the quarter filter is hiding.
   A caution, not an error — work landing in a later quarter is normal, and the badge exists
   so the reader knows what the number covers. */
.okr-hidden-krs{
  display:inline-flex; align-items:center; gap:4px; flex:0 0 auto;
  font-size:11px; font-weight:700; letter-spacing:.02em; white-space:nowrap;
  /* The real tokens: --warn-text is the one that exists for exactly this — warning text on
     a --yellow-soft wash, and it is the opposite end of the ramp in each theme (bright in
     dark, deep amber in light) so the contrast holds both ways. */
  color:var(--warn-text);
  background:var(--yellow-soft);
  border:1px solid var(--yellow-soft);
  border-radius:999px; padding:2px 8px; cursor:default;
}
.okr-hidden-krs svg{ flex:0 0 auto; }

/* A row in "Outside the selected quarters" is a button now — click a key result there to open
   the canonical editor directly. `.okr-outside-row` itself, its border and padding, are
   untouched (CSS/okr-suite.css, shared with tasks.html/team_board.html); this is a brand new
   class on the `<button>` nested one level inside it, so there is no cascade to fight. The
   button replaces the flex arrangement the row used to apply directly to its three children —
   restated here one level down so they read identically to before. */
.okr-outside-row-btn{
  display:flex; align-items:flex-start; gap:8px;
  width:100%; align-self:stretch;
  background:none; border:0; margin:0; padding:0;
  font:inherit; color:inherit; text-align:left; cursor:pointer;
}
.okr-outside-row-btn:hover .okr-outside-kr-title{ color:var(--accent-text); }
.okr-outside-row-btn:focus-visible{
  outline:2px solid var(--accent); outline-offset:2px; border-radius:4px;
}

/* Re-evaluate, and its ONE status line. Replaced in place rather than appended to — a line
   per item is a wall of text nobody reads and a scroll position that will not stay still. */
/* No margin — a spacing rule left over from when this was a band on its own line sat its
   button above the rest of the control row once it moved inline. A spacing rule that outlives
   the layout it was written for is the commonest way a moved control ends up misaligned. */
.okr-reeval{ margin:0; }
.okr-reeval-status{
  font-size:12px; color:var(--text-dim); min-width:0;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.okr-reeval-status.ok{ color:var(--green-text, var(--text-dim)); }
.okr-reeval-status.warn{ color:var(--warn-text); }
.okr-reeval-status.err{ color:var(--red-text); }
/* While the one request is in flight: the whole board goes to the assistant in a single call,
   so there is no per-item progress to show and the line can sit on one sentence for minutes,
   which is what a hung page looks like. The text carries ticking elapsed seconds
   (okrReevalTickStart); this adds a second, wordless signal for anyone not reading the number.
   Colour is not the signal — the dot moves. */
.okr-reeval-status.busy{ color:var(--text); }
.okr-reeval-status.busy::before{
  content:''; display:inline-block; width:6px; height:6px; margin-right:6px;
  border-radius:50%; background:var(--accent, currentColor); vertical-align:middle;
  /* `--dur-dots`, not a literal duration: this dot makes the same statement `.proc-dots` does
     — an operation in flight, wordless — at one dot instead of three, so it shares the working
     indicator's own pulse-cycle duration rather than inventing a second one off it. The curve
     stays local since character is this component's own; only the clock is shared. */
  animation:okrReevalPulse var(--dur-dots) ease-in-out infinite;
}
@keyframes okrReevalPulse{ 0%,100%{ opacity:.25; } 50%{ opacity:1; } }
/* A pulse nobody asked for is a distraction for the readers who switched motion off; the
   dot stays, so the state is still legible without it. */
@media (prefers-reduced-motion: reduce){
  .okr-reeval-status.busy::before{ animation:none; opacity:.8; }
}

/* The Contributors field in the key-result editor: a summary and a button, not the roster.
   The roster used to render inline in this ~140px column with no search and names cut to
   "dominic.alvarez@e…"; it opens the shared people picker now. */
.okr-contrib-field{ display:flex; align-items:center; gap:8px; min-width:0; }
.okr-contrib-summary{
  flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  font-size:13px; color:var(--text);
}
/* "None" is the ordinary state for a key result, so it reads as quiet rather than missing. */
.okr-contrib-summary.empty{ color:var(--text-faint); }
/* The button carries the same share mark the note editor's does, ahead of its label. */
.okr-contrib-field .btn{ flex:0 0 auto; display:inline-flex; align-items:center; gap:6px; }
.okr-contrib-field .btn svg{ flex:0 0 auto; }
.okr-kr-notes{ display:none; }

/* ---------- COLUMN: THE PORTFOLIO AREA GRID ----------
   A grid, not a scrolling strip: another card should move up into the space when a column
   fits, so the count comes from `auto-fill` plus a minimum usable card width rather than
   hard-coded breakpoints. The minimum is chosen from content, not a device — below it the
   objective card's own foot stops fitting on one line. `align-items:start` is the other half
   of the point: an area with one objective is one objective tall, so stretching every card to
   the tallest would be the wasted vertical space Column exists to remove. */
.okr-areagrid{
  /* Flex, not grid, because of the collapsed card: two areas take half the page each, three a
     third, until a column falls below the minimum and the next area wraps — `flex:1 1 <min>`
     with wrap is exactly that. Grid could not do the second half: `auto-fill` leaves empty
     tracks and `auto-fit` makes every track equal, so a folded card would still occupy a full
     column and give nothing back, when folding is supposed to hand its width to its
     neighbours and let a row below move up into the space. */
  display:flex; flex-wrap:wrap; align-items:flex-start; gap:12px;
}

.okr-area{
  /* 400px, measured, constrained by the status row rather than the objective cards: the
     tallies are what an area card is for, and a narrower row wrapped onto two lines. */
  flex:1 1 400px; min-width:400px;
  display:flex; flex-direction:column;
  background:var(--panel); border:1px solid var(--border-soft); border-radius:var(--radius);
  /* THE CARD IS THE QUERY CONTAINER. How wide a card ends up depends on how many areas are
     on the page, not on the viewport — three areas on a laptop are wider than seven on a
     large monitor — so the tally row's own breakpoint has to be asked of the CARD. A media
     query would get it wrong in both directions. */
  container-type:inline-size;
}
.okr-area-head{padding:11px 12px 8px; display:flex; flex-wrap:wrap; align-items:center; gap:6px;}
.okr-area-toggle{
  flex:1 1 auto; min-width:0; display:flex; align-items:center; gap:7px;
  background:none; border:none; padding:0; margin:0; cursor:pointer;
  color:var(--text); text-align:left; font:inherit;
}
.okr-area-toggle:hover .okr-area-title{color:var(--accent-text);}
.okr-area-toggle:focus-visible{outline:2px solid var(--accent); outline-offset:3px; border-radius:var(--radius-sm);}
.okr-area-title{font-size:15px; font-weight:700; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
.okr-area-sub{flex:1 0 100%; font-size:11px; color:var(--text-faint);}

/* The area indicators, above the objectives, are buttons: the count sits beside the question
   it answers and pressing it is what somebody does next. Zeroes are not drawn — "0 ahead · 0
   completed · 0 not started" is three quarters of a header spent saying nothing. One row,
   always: `nowrap` is the instruction, and the container query below is what keeps that
   possible on a narrow card by dropping labels rather than wrapping. */
.okr-area-tallies,
.okr-area-aggs{
  flex:1 0 100%; display:flex; flex-wrap:nowrap; gap:6px; margin-top:4px;
  /* Without this none of the shrinking below happens — a flex item defaults to
     `min-width:auto`, so this row refuses to go below its content and the pills push through
     the side of the card. */
  min-width:0;
}
.okr-area-tally{
  display:inline-flex; align-items:center; gap:5px; cursor:pointer; font:inherit;
  background:var(--panel-2); border:1px solid var(--border-soft); border-radius:999px;
  padding:2px 9px 2px 7px; color:var(--text-faint); font-size:11px;
}
/* They shrink before they push: `flex:0 0 auto` in a nowrap row overflows the card the moment
   the labels do not fit. Shrinking truncates the label, the least important part — the dot and
   count never move, and the full name is on the title. */
.okr-area-tally{white-space:nowrap; flex:0 1 auto; min-width:0; overflow:hidden;}
.okr-area-tally .okr-dot{margin-top:0; align-self:center; flex:0 0 auto;}
.okr-area-tally b{flex:0 0 auto;}
.okr-area-tally-l{overflow:hidden; text-overflow:ellipsis;}
/* And below a certain width they go entirely, rather than truncating to three characters — a
   minimum wide enough for every label would defeat the layout on a large screen, so the label
   drops instead; the name stays on the button's title and aria-label. A browser without
   container queries simply keeps the labels, which is the old behaviour, not a broken one. */
@container (max-width: 470px){
  .okr-area-tally-l{
    position:absolute; width:1px; height:1px; overflow:hidden;
    clip-path:inset(50%); white-space:nowrap;
  }
  .okr-area-tally{padding:2px 8px;}
}
.okr-area-tally b{font-size:12px; color:var(--text); font-variant-numeric:tabular-nums;}
.okr-area-tally:hover{border-color:var(--accent); color:var(--text);}
.okr-area-tally:focus-visible{outline:2px solid var(--accent); outline-offset:2px;}
/* Pressed is not colour-only: the border and the weight carry it too. */
.okr-area-tally.is-on{
  border-color:var(--accent); background:var(--accent-soft); color:var(--accent-text); font-weight:600;
}
/* Grouped by status there is nothing to tally — every card is one status — so the header
   shows what work sits under it instead. */
.okr-area-agg{display:inline-flex; align-items:baseline; gap:4px; font-size:11px; color:var(--text-faint);}
.okr-area-agg b{font-size:12px; color:var(--text); font-variant-numeric:tabular-nums;}

.okr-area-bar{display:flex; height:3px; margin:0 12px 8px; border-radius:999px; overflow:hidden; background:var(--panel-2);}
.okr-area-body{display:flex; flex-direction:column; gap:8px; padding:0 12px 12px;}
.okr-area-body:empty{padding:0;}

/* "View all N objectives". Full width at the foot of the card, so it reads as the end of that
   area's list rather than as an action on the last objective in it. */
.okr-area-more{
  margin:0 12px 12px; padding:7px 10px; font:inherit; font-size:12px; cursor:pointer;
  background:var(--panel-2); border:1px solid var(--border-soft); border-radius:var(--radius-sm);
  color:var(--text-dim);
}
.okr-area-more:hover{border-color:var(--accent); color:var(--text);}
.okr-area-more:focus-visible{outline:2px solid var(--accent); outline-offset:2px;}
/* How much is behind it, so the offer is worth weighing before it is pressed. */
.okr-area-more-n{color:var(--accent-text); font-weight:600;}

/* A folded card gives back its width — the team board's collapsed swim lane, in a wrapping
   row. It stops growing and shrinks to a strip, the cards beside it absorb the space, and a
   card from the row below moves up into it: not to save vertical space, but to make room for
   the areas still being read. The name turns with the strip rather than being dropped, since a
   44px column showing only a chevron and a count is not identifiable — same reasoning, same
   treatment, same 44px as `.lane-col.collapsed` on the team board. `align-self:stretch` so the
   strip is as tall as its row, reading as a folded column rather than a stray button. */
.okr-area.collapsed{
  flex:0 0 44px; min-width:44px; width:44px; align-self:stretch; min-height:130px;
}
.okr-area.collapsed .okr-area-body,
.okr-area.collapsed .okr-area-bar,
.okr-area.collapsed .okr-area-tallies,
.okr-area.collapsed .okr-area-aggs,
.okr-area.collapsed .okr-area-more{display:none;}
.okr-area.collapsed .okr-area-head{
  writing-mode:vertical-rl; height:100%; padding:10px 8px; gap:9px;
  flex-wrap:nowrap; align-items:center; justify-content:flex-start;
}
.okr-area.collapsed .okr-area-toggle{flex:0 1 auto; min-width:0;}
.okr-area.collapsed .okr-area-title{white-space:nowrap; overflow:hidden; text-overflow:ellipsis;}
/* The count stays — it is what makes a folded strip worth looking at. */
.okr-area.collapsed .okr-area-sub{flex:0 0 auto; writing-mode:vertical-rl;}
/* The caret's own rotation is the ONE shared rule near .okr-caret's definition above (line
   ~259), covering `.okr-group`, `.okr-area` and `.okr-obj` together — not restated here. */

/* ---------- an objective card ---------- */
.okr-card-obj{
  display:flex; flex-direction:column; gap:7px; width:100%; text-align:left; min-width:0;
  background:var(--panel-2); border:1px solid var(--border-soft); border-radius:var(--radius-sm);
  padding:10px 11px; cursor:pointer; font:inherit; color:var(--text);
}
/* The card's outline is the system border too, reversed with the row: these rules existed only
   to make the Kanban card match the List row, which at the time outlined every objective in
   its status colour on the request *"the outline colour of the objective should be consistent with the state of the objective"*.
   The owner has since reversed the row — *"the coloured outline is colour overload and is not helpful in the view"* — so these go with it; they were never an independent decision.

   Removing them here is what KEEPS the two consistent, not what breaks it — leaving the card
   coloured would read as a red rectangle in Kanban and a neutral one in List. `.okr-card-obj`'s
   own border above already supplies the resting edge, and the status is still on the card
   once: the diamond and the shared status pill. `data-status` remains on the element and is
   still asserted elsewhere — this removes a colour, not a hook. */
.okr-card-obj:hover{border-color:var(--accent);}
.okr-card-obj:focus-visible{outline:2px solid var(--accent); outline-offset:2px;}
/* The selected card, so the panel below is unambiguously about THIS one. Not colour alone —
   the ring is a shape change as well. */
.okr-card-obj.is-open{border-color:var(--accent); box-shadow:inset 0 0 0 1px var(--accent);}
/* THE AVATAR IS .comment-avatar, the one in CSS/components.css — same 26px circle, same
   white 10px bold initials, and the same reason the colour is a literal rather than a token:
   the background is one of seven fixed palette entries from avatarColorFor(), so the text
   must NOT follow the theme. All this rule adds is where it sits on the card. */
.okr-card-who{ flex:0 0 auto; margin-left:auto; }
/* Three lines of title, then ellipsis. An objective is a sentence and the card is a summary;
   a six-line card stops being scannable, which is the whole reason this view exists. */
.okr-card-title{
  font-size:14px; font-weight:600; line-height:1.35;
  display:-webkit-box; -webkit-line-clamp:3; -webkit-box-orient:vertical; overflow:hidden;
}
/* ---------- A CARD BECOMES THE LIST ROW WHEN IT HAS THE ROOM ----------
   A Kanban card is now anything from 400px to the whole page, and at narrow widths the
   stacked card was a status pill, a title and "3 KRs" in an ocean of space while the List row
   beside it showed the full objective in one line. So it is the same shape: wide, the card
   lays out as that row; as the column tightens the sub-line sheds its parts, and below the
   second breakpoint the card falls back to the stack.

   ONE SET OF NODES, LAID OUT TWO WAYS. The markup is identical at every width and the template
   does the work, so nothing re-renders when the column count changes and the two shapes cannot
   drift apart. It is a container query because the same viewport holds one wide card or seven
   narrow ones — a media query cannot tell those apart. */
/* An element cannot be styled by its own container query, so the container is the wrapper and
   the card is its child — with container-type on the button itself the field toggles still
   worked (they are on its children) while its own grid-template silently did not. */
.okr-card-wrap{container-type:inline-size; container-name:okrcard; min-width:0;}
.okr-card-obj{width:100%;}

/* Narrow — three lines, not four. Reported: *"Adjust the card progress bars. They are too busy and make the card bigger than necessary."*
   The pill collapses into the diamond that now leads the title, the percentage moves onto the
   bar's line where it labels the thing it measures, and the sub-line stays where a sub-line
   goes — one band comes out and the card reads top-down as name, progress, detail:

     "dot  title side"    the status diamond, the objective, the owner (and any warning badge)
     "bar  bar   pct"     the bar takes the width; the figure is right-aligned against it
     "meta meta  meta"    the sub-line — at this width, the status word and the measure count

   The status word in the sub-line is not optional: removing the pill removes the only text
   statement of status on a narrow card, and "never colour alone" does not accept a glyph that
   is the same diamond in every state. `.okr-card-status` is rendered at every width and
   displayed only here, so the pill and the word are never both on screen or in the
   accessibility tree. The bar and the sub-line start at the card's edge; only the title is
   indented, by the diamond in front of it. */
.okr-card-obj{
  display:grid; align-items:center; gap:6px 9px;
  grid-template-columns:auto minmax(0, 1fr) auto;
  grid-template-areas:
    "dot   title side"
    "bar   bar   pct"
    "meta  meta  meta";
}
/* THE TITLE AND ITS SUB-LINE ARE ONE BOX AT 520 AND TWO GRID CELLS BELOW IT, so `display:
   contents` — the wrapper stops generating a box and its two children become items of the
   card's own grid. The alternative was a second set of nodes for the narrow card, which is
   what the container query exists to avoid; `.okr-card-titles` carries no semantics to lose. */
.okr-card-titles{display:contents;}
.okr-card-title{grid-area:title; min-width:0;}
.okr-card-meta{grid-area:meta; min-width:0;}
/* `align-self:start` and the 5px, so the marker sits on the FIRST line of a title that clamps
   to three — the same offset the wide row gives it. */
.okr-card-dot{grid-area:dot; display:inline-flex; align-self:start; margin-top:5px;}
.okr-card-health{grid-area:health; display:none;}
/* Wraps, because of the hidden-measures badge: it is `flex:0 0 auto` and `nowrap` by design (a
   broken badge is worse than a wrapped row), so on a narrow column it is the one item that can
   push this group past its track. Wrapping is what that should do; overflowing a card is not.

   It carries no width cap, which was tried and measured and was worse: this group shares the
   title's row, and an `auto` grid column takes its content's max-content width. A percentage
   max-width looked like the answer and is a trap — it is indefinite while the track is being
   sized, so the column still grows to its full natural width and the percentage then resolves
   against THAT, wrapping the badge above the avatar instead of preventing the growth. A px cap
   is no better: above the group's natural width it does nothing, below it the same wrap is
   forced deliberately.

   So the badge squeezes the title, and that is the right trade: the title clamps to three
   lines and ellipsizes, degrading rather than overflowing, and the badge is the one thing on
   this card that says the percentage beside it does not cover every measure.

   The check-in chip joined this group rather than opening a grid cell of its own, for exactly
   this wrapping behaviour — it carries no width cap either, and draws nothing at all when an
   objective has no check-ins this quarter, so a board with nothing to report costs this group
   no width. */
.okr-card-side{
  grid-area:side; display:flex; flex-wrap:wrap; align-items:center; justify-content:flex-end;
  gap:8px; min-width:0; align-self:start;
}
.okr-card-pct{grid-area:pct;}
/* `margin-top:0` because `.okr-progress` carries 9px for the contexts where it follows text
   directly. Here the grid's own 6px row gap is the spacing, and the two compounded. */
.okr-card-progress{grid-area:bar; margin-top:0;}
/* THE PILL IS THE WIDE CARD'S. Here the diamond carries the colour and `.okr-card-status`
   carries the word; `display:none` takes it out of the accessibility tree too, so the status
   is announced exactly once. */
.okr-card-obj .okr-pill{display:none;}
/* The hidden-measures badge loses its word, not its warning: at narrow widths the sentence was
   clamping the title. The triangle and count are what the badge is for; the sentence moves to
   its `title`, the same treatment `.okr-area-tally-l` gets. Scoped to the card, so the row and
   every other host of this badge keep the word. */
.okr-card-obj .okr-hidden-krs-l{display:none;}
/* Pushed to the far edge of its row, which is where the stacked card has always put it. */
.okr-card-who{margin-left:auto;}

/* THE SUB-LINE, in the List row's own order and with its own separators. Each part carries
   the "·" that precedes it, so hiding a part hides its separator too — the alternative is a
   dangling dot whenever a field is absent or dropped. */
.okr-card-meta{
  display:flex; flex-wrap:wrap; align-items:baseline; gap:0 6px; min-width:0;
  font-size:11px; color:var(--text-faint);
}
.okr-card-meta > span{min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
.okr-card-meta > span + span::before{content:'· '; color:var(--text-faint);}
.okr-card-owner{color:var(--text-dim);}
/* The measure count is the reason to open the objective, so it is the last thing to go. */
.okr-card-krs{color:var(--accent-text); flex:0 0 auto;}
/* The status word. Something visible precedes it at every width now, so an earlier
   `content:none` exception for a dangling separator is gone — the general rule is correct on
   its own. Not `--text-faint` like the rest of the line: this is the card's only text
   statement of status once the pill drops out, so it takes the same step the owner's name
   does. The colour is still the diamond's job — this is deliberately not tinted per status, or
   a six-colour sub-line would be busier than the pill it replaced. */
.okr-card-status{color:var(--text-dim); font-weight:600; flex:0 0 auto;}
.okr-card-area, .okr-card-owner, .okr-card-period{display:none;}

.okr-card-health{flex-wrap:wrap; gap:4px 8px; min-width:0; font-size:11px;}
.okr-card-h{
  display:inline-flex; align-items:center; gap:4px; white-space:nowrap;
  color:var(--text-dim); font-variant-numeric:tabular-nums;
}
.okr-card-h .okr-dot{margin-top:0;}
.okr-card-h-l{color:var(--text-faint);}
.okr-card-contrib{color:var(--text-faint); white-space:nowrap;}

/* WIDE — the List row. Measured against this board's own content: the sub-line needs about
   250px beside a title that still has to be readable, which is where 520 comes from. */
@container okrcard (min-width: 520px){
  .okr-card-obj{
    grid-template-columns:auto minmax(0, 1fr) auto auto;
    grid-template-areas:
      "dot title side pct"
      "bar bar   bar  bar";
    align-items:start; gap:0 10px;
  }
  /* The title and its sub-line become one box again in the `title` cell — the narrow card
     unwraps them into the grid with `display:contents` and this is where that is undone. */
  .okr-card-titles{
    grid-area:title; display:flex; flex-direction:column; gap:3px; min-width:0;
  }
  .okr-card-area, .okr-card-owner, .okr-card-period{display:inline;}
  /* The pill is back and the word in the sub-line goes, so the status is stated once — there
     is room for the pill on a row this wide, and it is what the List row draws. */
  .okr-card-obj .okr-pill{display:inline-flex;}
  .okr-card-status{display:none;}
  /* And whatever follows it loses its separator, since `display:none` hides an element from
     the page and not from `span + span` — otherwise the sub-line gets a dangling dot in front
     of nothing. `+ span`, not `+ .okr-card-area`: area, owner and quarter each render only
     when the objective has one, so the element that actually follows the status is whichever
     of the four comes first. */
  .okr-card-meta > .okr-card-status + span::before{content:none;}
  /* The word comes back with the room for it. */
  .okr-card-obj .okr-hidden-krs-l{display:inline;}
  /* The row states the owner by NAME, so the avatar would be the same fact twice. */
  .okr-card-who{display:none;}
  /* The bar stays on the wide card, and is now the only place an objective's progress is
     drawn as a bar — the List row's was removed for being the fourth statement of one fact on
     a crowded row, but a card is one objective in its own box with room for it. Deliberately
     not re-hidden to match List. */
  .okr-card-progress{display:block; margin-top:8px;}
  .okr-card-side{justify-content:flex-end;}
  .okr-card-pct{align-self:start;}
}

/* WIDEST — the one thing the card says that the List row does not: what the measures
   underneath actually are. Another ~230px, hence 760. */
@container okrcard (min-width: 760px){
  .okr-card-obj{
    grid-template-columns:auto minmax(0, 1fr) auto auto auto;
    grid-template-areas:
      "dot title health side pct"
      "bar bar   bar    bar  bar";
  }
  .okr-card-health{display:flex;}
}

.okr-card-pct{flex:0 0 auto; font-size:13px; font-weight:700; font-variant-numeric:tabular-nums;}
.okr-card-krs{flex:0 0 auto; font-size:11px; color:var(--text-faint); white-space:nowrap;}

/* ---------- the selected objective, as a dialog ----------
   It used to be a full-width strip under the grid, below the fold on a long board. It is now
   the same shell the task editors use — `.modal-overlay` / `.modal-card.panes` from
   CSS/components.css, sized by sizeModalToViewport() — so it inherits the design instead of
   restating it. Everything here is the two adjustments that shell does not cover. */
.okr-detail-card{ padding:16px 18px; }
/* The one scroll region: `.modal-card.panes` is overflow:hidden and pins the title row, so
   this pane is the only thing in the dialog that scrolls. `auto`, never `scroll` — a bar that
   is always there on an objective with two measures is the dead space this change is about.
   `scrollbar-gutter:stable` reserves the channel so the content does not jump sideways when an
   insight expands past the limit. */
.okr-detail-pane{ overflow-y:auto; scrollbar-gutter:stable; padding-right:4px; }
/* The objective inside loses its own card chrome — it is already inside one. */
.okr-detail-pane .okr-obj{border:none; background:none; padding:0; margin:0;}
/* And the second, qualified copy stays, because `.okr-obj[data-status]{border:1px solid
   var(--border-soft)}` ties with the unqualified rule above and is declared later in this
   file — so without this qualified copy at higher specificity an objective opened in the
   detail pane would get its card chrome back. One dialog holds exactly one objective, already
   inside the shell's own card. `data-obj` is on every objective article exactly as
   `data-status` is, so requiring it is a real qualifier rather than a specificity trick. */
.okr-detail-pane .okr-obj[data-obj]{border:none; background:none; padding:0; margin:0;}
/* Its measures are the content of this dialog, so they are never hidden behind the
   objective's own disclosure when it opens: okrObjectiveHtml(o, cycle, {forceOpen:true})
   renders the article without `collapsed`. The inert CSS that once tried to do this through
   `.okr-obj-krs{display:flex}` is gone — that class is never emitted by the renderer, and a
   child cannot undo `display:none` on its parent anyway. Recorded here so it is not re-added. */
/* The objective's own head stays put while its measures scroll under it — the title, the
   area/owner/quarter line and the percentage are the context you are reading the measures
   against. Only the head: making the action row sticky too would be a second bar competing
   with the dialog's own. */
.okr-detail-pane .okr-obj-head{
  /* `--z-sticky`, not a bare 1: it is a pinned header inside a page region, which is exactly
     what that token names. */
  position:sticky; top:0; z-index:var(--z-sticky);
  background:var(--panel); padding-bottom:12px;
}
/* And it stays solid even on a status that would otherwise wash it, since this sticky head is
   pinned OVER the measures scrolling underneath it and a semi-transparent wash would let them
   show through while it holds position. `[data-status]` matches the attribute's presence, not
   one status's value, so one rule answers all six unconditionally. */
.okr-detail-pane .okr-obj[data-status] .okr-obj-head{background:var(--panel);}

/* The dialog is a reading surface, not the list: the compact density further up this file is
   right for a screen of objectives, but wrong here where there is exactly one objective and
   no shortage of room. These restore the file's own uncompacted values inside the dialog only
   — the list is untouched. */
.okr-detail-pane .okr-obj-inner{ padding:16px 0 8px; }
.okr-detail-pane .okr-kr{ padding:11px 13px; margin-bottom:10px; }
.okr-detail-pane .okr-kr-title{ font-size:14px; }
/* A no-op against the file's own base value, left rather than deleted because it is what the
   objective actions panel's own reset has to outrank at higher specificity. */
.okr-detail-pane .okr-kr-actions{ margin-top:10px; }

/* Below the minimum there is one card and it uses the width it has, rather than a 400px card
   overflowing a 360px viewport. */
@media (max-width:430px){
  .okr-area{flex-basis:100%; min-width:0;}
}

/* ---------- The objective's History dialog ----------
   Owner: *"make the iframe vertically taller so the list of history events allows the user to see more before scrolling… There should be a visual indicator when the date has changed."*
   The list used to sit in `.okr-history`'s flat ceiling, which is right for the other surfaces
   that class serves — short lists inside a form — and wrong for the only surface whose entire
   purpose is a long list. So `.okr-history` is left as it was and `.okr-audit-pane` overrides
   it for this dialog alone.

   What makes a taller frame honest rather than clipping — sys_design-system.md rule 8b: the
   head and foot are frozen, the body becomes a column that does not scroll, and the list is
   the one scroller in the dialog, rather than two nested scrollers fighting each other. No
   `min-height` on the scroller, per rule 8b's own warning: the body is `overflow:hidden`, so a
   proportional floor that exceeds what the chrome leaves wins the fight and clips the chrome.

   The pane's ceiling keeps its 88vh share and raises only the pixel cap — the share was
   already right, the constant was the half that did not scale, the same argument rule 8
   records for the permissions-by-role dialog's taller ratio: a data-dense list spends extra
   height on visible rows where a moderate form would only pad it with whitespace. */
.okr-modal-pane.okr-audit-pane{ max-height:min(88vh, 1100px); }
.okr-audit-pane .okr-modal-head,
.okr-audit-pane .okr-modal-foot{ flex:0 0 auto; }
.okr-audit-pane .okr-modal-body{
  flex:1 1 auto; min-height:0;
  display:flex; flex-direction:column; overflow:hidden;
  /* Spends a share of the window, not a constant — 8b again. The floor is px, since text does
     not get more readable on a bigger monitor; horizontal padding is untouched. */
  padding:clamp(10px, 1.6vh, 16px) 16px;
}
.okr-audit-pane .okr-audit-subject,
.okr-audit-pane .okr-audit-status{ flex:0 0 auto; }
.okr-audit-pane .okr-audit-status{ margin-top:clamp(4px, .8vh, 8px); }
.okr-audit-pane .okr-history{
  flex:1 1 auto; min-height:0; max-height:none;
  margin:clamp(6px, 1vh, 10px) 0 0;
}

/* What is pinned is what decodes the list: the dialog head says only "History", so without
   this line a reader cannot tell whose trail they are looking at. Nothing else is frozen —
   every sentence, heading and stamp scrolls, since a pinned item and the scroller's first
   screenful are the same budget. */
.okr-audit-subject{
  display:flex; align-items:baseline; justify-content:space-between; gap:10px; flex-wrap:wrap;
  padding-bottom:clamp(6px, 1vh, 11px); border-bottom:1px solid var(--border-soft);
}
.okr-audit-subject-title{
  flex:1 1 200px; min-width:0;
  font-size:14px; font-weight:600; line-height:1.4; color:var(--text);
}
/* The summary pill — the words are okrPushMoveLabel()'s, never spelled out in CSS. Hidden
   until it has something to say: an objective whose period has not moved draws no empty pill
   (DoD 4f). Amber is the default and not the only state: this is a signed measure, a period
   that ended up later is a warning and keeps this treatment, one that ended up earlier is a
   credit and must not wear it — the owner asked for the credit so that *"people get credit for bringing things in ahead of time"*,
   and a pill that looks like a complaint takes that back. */
.okr-audit-pushes{
  flex:0 0 auto;
  font-size:11px; font-weight:600; letter-spacing:.02em; white-space:nowrap;
  color:var(--warn-text); background:var(--yellow-soft);
  border:1px solid var(--yellow); border-radius:999px; padding:2px 9px;
}
/* The credit — the same pill in the page's own positive colours, the trio tokens.css already
   defines for exactly this meaning on other surfaces. No green invented here; only the
   colours change. The class name is shared with the board's own chip (`.okr-push-chip.is-credit`,
   CSS/okr-suite.css §9) on purpose, so the two surfaces cannot disagree about what a credit is. */
.okr-audit-pushes.is-credit{
  color:var(--green-text); background:var(--green-soft); border-color:var(--green);
}

/* Why there is no pill when the list below plainly shows dates moving: this sentence stops a
   reader concluding the indicator is broken — the period came back to where it started, or the
   objective is inside its first ten business days. A sentence rather than a pill, since a pill
   would break mid-phrase on a narrow screen. Hidden until it has something to say, and never
   shown at the same time as the pill (DoD 4f). */
.okr-audit-push-note{
  flex:1 1 100%; margin:4px 0 0;
  font-size:11px; line-height:1.45; color:var(--text-dim);
}

/* The day heading, sticky, so it answers "which day am I looking at" after fifty rows have
   gone past at no cost to the first screenful. Its ground is the pane's own `--panel`, or the
   rows would scroll through it. */
.okr-audit-day{
  position:sticky; top:0; z-index:var(--z-sticky);
  background:var(--panel); padding:7px 0 5px;
}
.okr-audit-day-label{
  display:inline-block;
  font-size:11px; font-weight:700; letter-spacing:.06em; text-transform:uppercase;
  color:var(--text-dim);
}

/* The date indicator, two signals not one: the leading-edge rule makes a date move findable
   while scrolling past it, the chip names it once the reader has stopped — colour is never
   the only signal. */
.okr-audit-event--push{
  border-left:3px solid var(--yellow); padding-left:8px;
  background:var(--yellow-soft);
}
.okr-audit-flag{
  display:inline-block; margin-left:6px;
  font-size:10px; font-weight:700; letter-spacing:.05em; text-transform:uppercase;
  white-space:nowrap;
  color:var(--warn-text); background:var(--panel);
  border:1px solid var(--yellow); border-radius:999px; padding:1px 7px;
}

/* Which measure this row is about, only present when the subject IS a measure. Above the
   sentence rather than beside it, so a long measure title cannot push the sentence off its own
   line — it ellipses instead, and the full text is one row down. */
.okr-audit-scope{
  font-size:11px; font-weight:600; letter-spacing:.03em; color:var(--text-dim);
  margin-bottom:3px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
/* A check-in's own words, the one place in this list where somebody wrote prose rather than
   the system recording a fact. `pre-wrap` keeps the line breaks they typed; `anywhere` stops a
   pasted URL widening the dialog. */
.okr-audit-note{
  font-size:12px; line-height:1.5; color:var(--text-dim); margin-top:3px;
  white-space:pre-wrap; overflow-wrap:anywhere;
}
