/* ============================================================================
   Control Freak — production stylesheet
   ----------------------------------------------------------------------------
   Adopted from the styling-phase design handoff (Y1,
   docs/superpowers/plans/2026-07-24-styling.md) as the web UI's single
   global stylesheet, replacing the earlier structural-only placeholder.
   Styles the existing markup by the class names in the design brief
   (§7). No external assets, no web fonts, no network calls — system
   font stacks plus an inline-SVG data-URI caret only. Light and dark
   via prefers-color-scheme; prefers-reduced-motion disables animation.

   This task (Y1) lands the stylesheet only — no markup changes, so the
   additions it targets (dashboard-logo, environment-cost-mtd, and the
   rest listed in the plan's Y2) are not yet present in the markup and
   render as no-ops until Y2 adds them. Every value below is the
   literal value from the approved design reference.
   ============================================================================ */

/* ---------- Design tokens ---------- */
:root {
  --cf-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --cf-mono: ui-monospace, "SF Mono", "SFMono-Regular", "Cascadia Code", "Roboto Mono", Menlo, Consolas, monospace;

  --cf-bg: #eceef2;
  --cf-panel: #ffffff;
  --cf-panel-inset: #f5f6f9;
  --cf-border: #dde1e8;
  --cf-border-strong: #c6ccd6;
  --cf-fg: #1a1f28;
  --cf-fg-dim: #5a6472;
  --cf-fg-faint: #8b93a1;

  --cf-accent: #2f66e0;      --cf-accent-fg: #ffffff;
  --cf-on: #1c8a4c;          --cf-on-soft: #e8f4ec;
  --cf-off: #77808e;         --cf-off-soft: #eef0f4;
  --cf-drift: #a86400;       --cf-drift-soft: #f9eed9;
  --cf-danger: #c1362a;      --cf-danger-soft: #fbe9e6;

  --cf-shadow: 0 1px 2px rgba(20,26,35,.05), 0 1px 3px rgba(20,26,35,.04);
  --cf-radius: 12px;

  /* Density — override the two vars to switch to compact */
  --cf-card-pad: 18px;
  --cf-row-gap: 15px;
  --cf-card-w: 340px;

  /* Swim-lane edge-scroll shadow (plan N3) — a dark, low-opacity mark in
     light mode; overridden to a light one in dark mode below, since a
     dark shadow reads as no shadow at all against a near-black panel. */
  --cf-lane-edge: rgba(20,26,35,.22);

  /* Burn-chart group identity palette (plan N5) — the plan's own
     ΔE-validated table, LIGHT values, in this exact order (never
     cycled, never reused for the on/off/drift/danger/accent status
     palette above). A group beyond the 5th slot never gets a generated
     hue — see style.css's own BURN CHART section and `crate::charts`'
     module documentation for the fold-to-`Other` rule this neutral
     6th value exists for. */
  --cf-group-1: #1baf7a;
  --cf-group-2: #4a3aa7;
  --cf-group-3: #e87ba4;
  --cf-group-4: #2a78d6;
  --cf-group-5: #eb6834;
  --cf-group-other: var(--cf-fg-faint);
}

@media (prefers-color-scheme: dark) {
  :root {
    --cf-bg: #0b0f15;
    --cf-panel: #151b24;
    --cf-panel-inset: #101620;
    --cf-border: #232c39;
    --cf-border-strong: #33404f;
    --cf-fg: #e6edf5;
    --cf-fg-dim: #98a4b3;
    --cf-fg-faint: #68727f;

    --cf-accent: #4d87ff;    --cf-accent-fg: #0b0f15;
    --cf-on: #42b95a;        --cf-on-soft: #122a1b;
    --cf-off: #7d8898;       --cf-off-soft: #1a212b;
    --cf-drift: #d99320;     --cf-drift-soft: #2a2110;
    --cf-danger: #f0554c;    --cf-danger-soft: #2c1512;

    --cf-shadow: 0 1px 2px rgba(0,0,0,.45), 0 2px 8px rgba(0,0,0,.3);
    --cf-lane-edge: rgba(255,255,255,.14);

    /* Dark values from the plan's own table — separately stepped, not
       an automatic flip of the light values (plan N5: "Dark is
       separately stepped, not an automatic flip"). */
    --cf-group-1: #199e70;
    --cf-group-2: #9085e9;
    --cf-group-3: #d55181;
    --cf-group-4: #3987e5;
    --cf-group-5: #d95926;
    --cf-group-other: var(--cf-fg-faint);
  }
}

/* ---------- Base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; }
body {
  background: var(--cf-bg);
  color: var(--cf-fg);
  font-family: var(--cf-sans);
  font-size: 14px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
}
a { color: var(--cf-accent); text-decoration: none; }
a:hover { text-decoration: underline; }

@keyframes cf-pulse { 0%,100% { opacity: .5; } 50% { opacity: 1; } }
@keyframes cf-fade { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
@keyframes cf-progress { 0% { transform: translateX(-100%); } 100% { transform: translateX(280%); } }
@keyframes cf-body { from { opacity: .4; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { * { animation: none !important; } }

/* ============================================================================
   LOGIN (§6.1) — bare elements styled by descendant selectors
   ============================================================================ */
.login-page {
  min-height: 100vh;
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
}
.login-page form {
  width: 100%; max-width: 360px;
  display: flex; flex-direction: column; gap: 16px;
  background: var(--cf-panel);
  border: 1px solid var(--cf-border);
  border-radius: 14px;
  box-shadow: var(--cf-shadow);
  padding: 28px 26px;
}
.login-page .login-header {
  display: flex; align-items: center; gap: 11px;
}
.login-page h1 {
  margin: 0;
  font-family: var(--cf-mono);
  font-size: 19px; font-weight: 650; letter-spacing: .01em;
}
.login-page .login-subtitle {
  font-size: 12.5px; color: var(--cf-fg-faint); margin-top: -6px;
}
.login-page input {
  width: 100%;
  font-family: var(--cf-sans); font-size: 14px;
  color: var(--cf-fg);
  background: var(--cf-panel-inset);
  border: 1px solid var(--cf-border-strong);
  border-radius: 8px;
  padding: 11px 13px;
  outline: none;
}
.login-page input:focus { border-color: var(--cf-accent); }
.login-page button[type="submit"] {
  width: 100%;
  font-family: var(--cf-sans); font-size: 14px; font-weight: 650;
  padding: 11px 14px;
  border: 1px solid transparent; border-radius: 8px;
  background: var(--cf-accent); color: var(--cf-accent-fg);
  cursor: pointer;
}
/* Proposed submitting state (see README §Behavior) */
.login-page input:disabled,
.login-page button[type="submit"]:disabled { opacity: .55; cursor: progress; }

/* ============================================================================
   DASHBOARD SHELL (§6.2)
   ============================================================================ */
.dashboard-page { min-height: 100vh; }

.dashboard-header {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 14px 24px;
  background: var(--cf-bg);
  border-bottom: 1px solid var(--cf-border);
}
.dashboard-title {
  font-family: var(--cf-mono);
  font-size: 15px; font-weight: 650; letter-spacing: .01em;
}
/* Optional status LED before the title — add <span class="dashboard-logo"> (see README) */
.dashboard-logo {
  width: 11px; height: 11px; border-radius: 3px;
  background: var(--cf-on); box-shadow: 0 0 0 3px var(--cf-on-soft);
  flex: none;
}
.dashboard-brand { display: flex; align-items: center; gap: 11px; }
.dashboard-actions { display: flex; align-items: center; gap: 14px; }
.dashboard-user {
  font-family: var(--cf-mono); font-size: 12.5px; color: var(--cf-fg-dim);
  white-space: nowrap;
}
/* Guards the "Signed in as " momentary gap (§6.2): username width never
   shifts the layout because the block is left-of-fixed order, not right-anchored. */
.dashboard-user strong,
.dashboard-user .dashboard-user-name { color: var(--cf-fg); font-weight: 600; }

.dashboard-body { display: flex; flex-direction: column; gap: 22px; animation: cf-body .35s ease; }

/* Content column */
.dashboard-page > main,
.dashboard-page .dashboard-main {
  max-width: 1160px; margin: 0 auto; padding: 22px 24px 40px;
  display: flex; flex-direction: column; gap: 22px;
}

/* ============================================================================
   BANNERS + EMPTY (§5.1, §5.2)
   ============================================================================ */
.banner {
  padding: 11px 15px; border-radius: 9px;
  font-size: 13px; display: flex; align-items: center; gap: 10px;
}
.banner.loading {
  background: var(--cf-panel-inset);
  border: 1px solid var(--cf-border);
  color: var(--cf-fg-dim);
  font-family: var(--cf-mono);
  animation: cf-pulse 1.4s ease-in-out infinite;
}
.banner.loading::before {
  content: ""; width: 8px; height: 8px; border-radius: 50%;
  background: var(--cf-fg-faint); flex: none;
}
.banner.error {
  background: var(--cf-danger-soft);
  border: 1px solid var(--cf-danger);
  color: var(--cf-danger);
}
.banner.error::before { content: "\26A0"; font-weight: 700; } /* ⚠ */
/* Y5 addition: the delivered `.banner` family only ships `.loading`/`.error`;
   the history panel's partial-read note (malformed log entries, skipped
   server-side but never silent) needed a third, less severe register —
   extended from the existing family using the drift token already defined
   for "state is indeterminate/incomplete", not a new colour. */
.banner.warning {
  background: var(--cf-drift-soft);
  border: 1px solid var(--cf-drift);
  color: var(--cf-drift);
}
.banner.warning::before { content: "\26A0"; font-weight: 700; } /* ⚠ */

.empty-state {
  padding: 22px; text-align: center;
  border: 1px dashed var(--cf-border-strong); border-radius: 9px;
  color: var(--cf-fg-dim); font-size: 13px;
}

/* ============================================================================
   BURN-RATE PANEL (§6.3)
   ============================================================================ */
.burn-rate-panel {
  background: var(--cf-panel); border: 1px solid var(--cf-border);
  border-radius: var(--cf-radius); box-shadow: var(--cf-shadow);
  padding: 20px 22px;
  display: flex; flex-direction: column; gap: 16px;
}
.burn-rate-totals {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 14px;
}
.burn-rate-total {
  display: flex; flex-direction: column; gap: 4px;
  padding: 12px 14px; background: var(--cf-panel-inset); border-radius: 9px;
}
/* Cumulative "Month to date" total is visually distinguished from the rate totals */
.burn-rate-total-mtd { box-shadow: inset 3px 0 0 var(--cf-accent); }
.burn-rate-total-label {
  font-size: 11px; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--cf-fg-faint);
}
.burn-rate-total-value {
  font-family: var(--cf-mono); font-size: 26px; font-weight: 650;
  color: var(--cf-fg); font-variant-numeric: tabular-nums; line-height: 1.1;
}
.burn-rate-split {
  display: flex; gap: 18px; font-family: var(--cf-mono); font-size: 13px;
  padding-top: 14px; border-top: 1px solid var(--cf-border);
}
.burn-rate-split-owned, .burn-rate-split-shared { color: var(--cf-fg-dim); }
.burn-rate-split-owned strong, .burn-rate-split-shared strong { color: var(--cf-fg); font-weight: 600; }
/* `Total` (plan C3) joins Owned/Shared on the same line so a reader can
   check `owned + shared = total` without looking back up at the headline
   row — full-strength foreground and the same weight as the headline
   values, distinct from the two dimmer components either side of it. */
.burn-rate-split-total { color: var(--cf-fg); font-weight: 650; }

.environment-counts { display: flex; gap: 8px; }
.environment-count {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 10px; border-radius: 999px;
  font-size: 12px; font-weight: 650; font-variant-numeric: tabular-nums;
}
.environment-count-on      { color: var(--cf-on);    background: var(--cf-on-soft); }
.environment-count-off     { color: var(--cf-off);   background: var(--cf-off-soft); }
.environment-count-partial { color: var(--cf-drift); background: var(--cf-drift-soft); }
/* Redundant-with-color shape markers (§4) — prepend via ::before if the counts
   render as bare "2 on" text with no glyph in markup. */
.environment-count-on::before      { content: "\25CF "; }  /* ● */
.environment-count-off::before     { content: "\25CB "; }  /* ○ */
.environment-count-partial::before { content: "\25B2 "; }  /* ▲ */

.org-next-expiry { font-family: var(--cf-mono); font-size: 12.5px; color: var(--cf-fg-dim); }
.org-next-expiry strong,
.org-next-expiry .org-next-expiry-value { color: var(--cf-fg); }

/* ============================================================================
   SHARED RESOURCES — org-wide section (plan C3)
   ----------------------------------------------------------------------------
   Not in the delivered design handoff at all — the wire fields these cards
   render (state/cost/reference-count) landed with this phase's own
   predecessor (plan C2). Built from the delivered system's own primitives
   per Y5's established "extend, don't invent" instruction: the burn-rate
   panel's own label typography, the environment card's own card shape/
   shadow/radius (`.environment-card`), and `.resource-state-badge`
   (already styled above) for each card's live state — no new colour
   vocabulary. Sits directly below the burn-rate panel so the `Shared:`
   split figure has an itemised breakdown right underneath it to check
   against, one card per shared resource, counted exactly once.
   ============================================================================ */
.shared-resources-panel { display: flex; flex-direction: column; gap: 14px; }
.shared-resources-title {
  margin: 0; font-family: var(--cf-sans); font-size: 13px; font-weight: 650;
  color: var(--cf-fg-dim); text-transform: uppercase; letter-spacing: .04em;
}
.shared-resources-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 14px;
}
.shared-resource-card {
  display: flex; flex-direction: column; gap: 8px;
  padding: 14px 16px;
  border: 1px solid var(--cf-border); border-radius: var(--cf-radius);
  background: var(--cf-panel); box-shadow: var(--cf-shadow);
  min-width: 0;
}
.shared-resource-card-header { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.shared-resource-card-name {
  font-family: var(--cf-mono); font-size: 13px; font-weight: 650; color: var(--cf-fg);
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.shared-resource-card-cost {
  font-family: var(--cf-mono); font-size: 13px; font-weight: 600;
  color: var(--cf-fg); font-variant-numeric: tabular-nums;
}
.shared-resource-card-references { font-family: var(--cf-sans); font-size: 11px; color: var(--cf-fg-faint); }

/* ============================================================================
   BURN CHART (plan N5)
   ----------------------------------------------------------------------------
   Not in the delivered design handoff at all (it postdates it) — built
   from this system's own panel/title/note primitives, per the same
   "extend, don't invent" instruction the swim-lanes/history/provenance
   sections above already follow. Inline SVG only, no charting library
   (strict CSP, `crate::charts`' own module documentation).

   One axis, one unit: bars (`.cost-chart-bar`) and lines
   (`.cost-chart-line`) share the SAME `£/day` scale — there is
   deliberately no second colour/position system implying a second axis.
   Gridlines stay SOLID and recessive (`--cf-border`, thin) — dashing is
   reserved for "projected" and must not be spent on the grid.

   Solid = observed, dashed = projected, stated once in the legend
   (`.cost-chart-legend-note`) rather than repeated per mark. The
   `--chart-color` custom property, set by whichever `.cost-chart-color-*`
   modifier a mark also carries (assigned by `crate::charts::
   group_color_slot` in fixed order — see this file's own `--cf-group-*`
   design tokens), is what a mark's own base class reads its stroke/fill
   from; the SAME six modifier classes also colour a swim-lane's own
   sparkline (`.environment-lane-sparkline-line`), so a lane and its
   headline line always match.
   ============================================================================ */
.cost-chart-panel {
  background: var(--cf-panel); border: 1px solid var(--cf-border);
  border-radius: var(--cf-radius); box-shadow: var(--cf-shadow);
  padding: 18px 20px;
  display: flex; flex-direction: column; gap: 12px;
}
.cost-chart-title {
  margin: 0; font-family: var(--cf-sans); font-size: 13px; font-weight: 650;
  color: var(--cf-fg-dim); text-transform: uppercase; letter-spacing: .04em;
}
.cost-chart-frame { position: relative; }
.cost-chart-svg { display: block; width: 100%; height: 200px; }

/* Structural grouping only — no rule of their own needed beyond keeping
   the static marks out of the pointer's way, so the hover-target rects
   layered on top (last, so they win hit-testing) are what the mouse
   actually reaches. */
.cost-chart-gridlines, .cost-chart-bars, .cost-chart-lines, .cost-chart-day-labels {
  pointer-events: none;
}
/* The hover-target rects layered last, on top of the static marks above
   — the one group in this chart that DOES want the pointer. */
.cost-chart-hover-targets { pointer-events: auto; }

.cost-chart-gridline { stroke: var(--cf-border); stroke-width: 1; }
.cost-chart-axis-label {
  font-family: var(--cf-mono); font-size: 9px; fill: var(--cf-fg-faint); text-anchor: end;
}
.cost-chart-day-label { font-family: var(--cf-mono); font-size: 9px; fill: var(--cf-fg-faint); text-anchor: start; }
.cost-chart-day-label-last { text-anchor: end; }

/* Bars dominate, recessive against the thin identity lines drawn over
   them (plan N5: "thin against dominant, recessive bars"). */
.cost-chart-bar { fill: var(--cf-border-strong); }
.cost-chart-bar-projected { fill: none; stroke: var(--cf-border-strong); stroke-width: 1; stroke-dasharray: 3 2; }

.cost-chart-line { fill: none; stroke: var(--chart-color); stroke-width: 1.75; }
.cost-chart-line-dashed { fill: none; stroke: var(--chart-color); stroke-width: 1.75; stroke-dasharray: 4 3; }

/* Focusable as well as hoverable (`tabindex` in `crate::charts`), so the
   crosshair and its figures are reachable without a pointer exactly as
   each swim-lane's own scroll strip is — with the same explicit outline,
   since a browser's own default on an SVG rect is inconsistent at best. */
.cost-chart-hover-target { fill: transparent; cursor: crosshair; }
.cost-chart-hover-target:focus-visible {
  outline: 2px solid var(--cf-accent); outline-offset: -2px;
}
.cost-chart-crosshair { stroke: var(--cf-fg-faint); stroke-width: 1; pointer-events: none; }

.cost-chart-tooltip-anchor {
  position: absolute; top: 4px; transform: translateX(-50%);
  pointer-events: none; z-index: 5;
}
.cost-chart-tooltip {
  min-width: 150px; padding: 8px 10px;
  background: var(--cf-panel); border: 1px solid var(--cf-border-strong); border-radius: 8px;
  box-shadow: var(--cf-shadow); font-size: 11.5px;
}
.cost-chart-tooltip-date {
  margin: 0 0 4px; font-family: var(--cf-mono); font-weight: 650; color: var(--cf-fg);
}
.cost-chart-tooltip-row {
  margin: 0; display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
}
.cost-chart-tooltip-label { color: var(--cf-fg-dim); }
.cost-chart-tooltip-value {
  font-family: var(--cf-mono); color: var(--cf-fg); font-variant-numeric: tabular-nums;
}

.cost-chart-legend {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px;
  padding-top: 10px; border-top: 1px solid var(--cf-border);
  font-size: 12px; color: var(--cf-fg-dim);
}
.cost-chart-legend-note { font-family: var(--cf-mono); }
.cost-chart-legend-note-solid { color: var(--cf-fg-dim); }
.cost-chart-legend-note-dashed { color: var(--cf-fg-faint); }
.cost-chart-legend-item {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--cf-sans); font-size: 12px; color: var(--cf-fg-dim);
  background: transparent; border: none; padding: 0; cursor: pointer;
}
.cost-chart-legend-item[aria-pressed="false"] { opacity: .4; text-decoration: line-through; }
.cost-chart-legend-swatch {
  display: inline-block; width: 10px; height: 10px; border-radius: 2px;
  background: var(--chart-color); flex: none;
}
.cost-chart-legend-overflow { font-size: 11px; color: var(--cf-fg-faint); font-style: italic; }
/* The scope note takes a line of its own below the rest of the legend
   (`flex-basis: 100%`): the bars are org-wide while the group lines
   exclude shared resources, and a reader must not have to infer that the
   lines fail to decompose the bars. */
.cost-chart-legend-scope {
  flex-basis: 100%; font-size: 11px; color: var(--cf-fg-faint); font-style: italic;
}

/* The group-identity colour palette (plan N5) — sets `--chart-color` for
   whichever base class (`.cost-chart-line`, `.cost-chart-line-dashed`,
   `.cost-chart-legend-swatch`, `.environment-lane-sparkline-line`) also
   carries it. Fixed order, never cycled; a 6th-plus group's sparkline
   (the headline chart itself never draws one — see `crate::charts`' own
   module documentation) uses the shared neutral `other` value, never a
   generated hue. */
.cost-chart-color-one   { --chart-color: var(--cf-group-1); }
.cost-chart-color-two   { --chart-color: var(--cf-group-2); }
.cost-chart-color-three { --chart-color: var(--cf-group-3); }
.cost-chart-color-four  { --chart-color: var(--cf-group-4); }
.cost-chart-color-five  { --chart-color: var(--cf-group-5); }
.cost-chart-color-other { --chart-color: var(--cf-group-other); }

/* ============================================================================
   ENVIRONMENT LIST + CARD (§6.4, §6.5)
   ============================================================================ */
.environment-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(var(--cf-card-w), 1fr));
  gap: 16px; align-items: stretch;
}

.environment-card {
  position: relative;
  display: flex; flex-direction: column; gap: var(--cf-row-gap);
  padding: var(--cf-card-pad);
  border: 1px solid var(--cf-border);
  border-left: 3px solid var(--cf-border-strong);
  border-radius: var(--cf-radius);
  background: var(--cf-panel);
  box-shadow: var(--cf-shadow);
  /* Grid item: the .environment-list grid sizes the card, filling the row
     in equal columns at least --cf-card-w wide (owner preference over the
     brief's fixed-width cards, so the card row matches the burn-rate panel
     width above it). */
  min-width: 0;
}
/* Card-level state treatment (independent of the badge, §6.5) */
.environment-card-on      { border-left-color: var(--cf-on);    background: var(--cf-on-soft); }
.environment-card-partial { border-left-color: var(--cf-drift); background: var(--cf-drift-soft); }
.environment-card-off     { border-left-color: var(--cf-border-strong); background: var(--cf-panel); }
/* Off cards recede: greyed heading */
.environment-card-off .environment-title { color: var(--cf-fg-faint); }

/* Y5 note: `justify-content: space-between` was correct for the delivered
   2-child header (title, badge); the card's own "History" button (spec
   addendum §1, plan O3/Y2) is a third child the design never anticipated.
   Giving the title `flex: 1 1 auto` so it absorbs the free space keeps the
   badge and the new button tight together at the right edge instead of
   space-between spreading three items evenly across the row. */
.environment-card-header {
  display: flex; align-items: flex-start; gap: 8px;
}
.environment-title {
  flex: 1 1 auto; min-width: 0;
  margin: 0; font-family: var(--cf-mono);
  font-size: 14px; font-weight: 650; color: var(--cf-fg); word-break: break-word;
}

/* -- State badge (§6.5.1) -- */
.environment-state-badge, .resource-state-badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px; border-radius: 999px;
  font-size: 11px; font-weight: 650; line-height: 1.4; white-space: nowrap;
}
.environment-state-badge-on,  .resource-state-badge-on  { color: var(--cf-on);    background: var(--cf-on-soft); }
.environment-state-badge-off, .resource-state-badge-off { color: var(--cf-off);   background: var(--cf-off-soft); }
.environment-state-badge-partial { color: var(--cf-drift); background: var(--cf-drift-soft); white-space: normal; }
/* Shape markers so state survives desaturation (§4). Drift already carries the
   full words "Drift — resources disagree", so no glyph is forced on it. */
.environment-state-badge-on::before,  .resource-state-badge-on::before  { content: "\25CF"; }  /* ● */
.environment-state-badge-off::before, .resource-state-badge-off::before { content: "\25CB"; }  /* ○ */

/* -- Session row (§6.5.2) -- */
.environment-session-row { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.environment-countdown {
  font-family: var(--cf-mono); font-variant-numeric: tabular-nums;
  font-size: 15px; font-weight: 600; color: var(--cf-fg);
}
.environment-countdown-indefinite {
  font-family: var(--cf-mono); font-size: 14px; font-weight: 500; color: var(--cf-fg-dim);
}
/* Resolve the Indefinite ambiguity (§6.5.2) purely in CSS: on an OFF card the
   row is irrelevant, so it recedes; it only draws the eye on an ON card. */
.environment-card-off .environment-countdown-indefinite {
  font-size: 13px; font-weight: 400; font-style: italic; color: var(--cf-fg-faint);
}
.environment-countdown-flagged {
  color: var(--cf-drift); font-weight: 600; font-size: 14px;
}
.environment-countdown-flagged::before { content: "\2691 "; } /* ⚑ */
.environment-attribution { font-family: var(--cf-mono); font-size: 12px; color: var(--cf-fg-faint); }

/* -- Cost block (§6.5 item 3) -- */
.environment-cost {
  display: flex; flex-direction: column; gap: 3px;
  padding: 11px 12px; background: var(--cf-panel-inset); border-radius: 8px;
}
.environment-cost-row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.environment-cost-label { font-size: 12.5px; color: var(--cf-fg-dim); }
.environment-cost-value {
  font-family: var(--cf-mono); font-size: 13px; font-weight: 600;
  color: var(--cf-fg); font-variant-numeric: tabular-nums;
}
/* Cumulative "Spent this month" row (NEW — needs a data field, see README) */
.environment-cost-mtd { margin-top: 6px; padding-top: 9px; border-top: 1px solid var(--cf-border); }
.environment-cost-mtd .environment-cost-label { font-weight: 600; }
.environment-cost-mtd .environment-cost-value { font-size: 14.5px; font-weight: 700; }

/* -- Shared resources (§6.5 item 4) -- */
.shared-resource-list { display: flex; flex-direction: column; gap: 6px; }
.shared-resource-item {
  display: flex; align-items: center; flex-wrap: wrap; gap: 4px 10px;
  padding: 7px 10px; background: var(--cf-panel-inset);
  border: 1px solid var(--cf-border); border-radius: 7px;
}
.shared-resource-name {
  font-family: var(--cf-mono); font-size: 12.5px; color: var(--cf-fg);
  flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis;
}
.shared-resource-cost {
  font-family: var(--cf-mono); font-size: 12.5px; font-weight: 600;
  color: var(--cf-fg-dim); font-variant-numeric: tabular-nums;
}
.shared-resource-state-unknown {
  padding: 3px 9px; border-radius: 999px; font-size: 11px; font-weight: 650;
  color: var(--cf-fg-faint); background: var(--cf-panel);
  border: 1px dashed var(--cf-border-strong); white-space: nowrap;
}
.shared-resource-state-unknown::before { content: "? "; }
/* "shared with N environments (M on)" (plan C3) — a full-width caption
   line under the name/state/cost row rather than crowding onto it, since
   it is prose, not a number to align with the others. */
.shared-resource-references {
  flex-basis: 100%;
  font-family: var(--cf-sans); font-size: 10.5px; color: var(--cf-fg-faint);
}

/* -- Expandable resource section (plan R5, owner decision 4) --
   Not in the delivered design handoff at all (it predates this phase) —
   built entirely from the system's own primitives rather than a new
   visual language, the same instruction plan Y5 already applied to the
   history panel and cost provenance below: a plain <details>/<summary>
   disclosure (native browser affordance, no JS state to manage), styled
   as a slim inset strip that opens into `.shared-resource-item`'s own
   flex-row card-inset row shape, and `.resource-state-badge` (already
   styled above) for each row's live state — no new colour vocabulary. */
.environment-resource-panel {
  padding: 9px 12px; background: var(--cf-panel-inset); border-radius: 8px;
}
.environment-resource-summary {
  font-family: var(--cf-sans); font-size: 12.5px; font-weight: 600; color: var(--cf-fg-dim);
  cursor: pointer; list-style: none;                 /* the marker below replaces the native triangle */
}
.environment-resource-summary::-webkit-details-marker { display: none; }
.environment-resource-summary::before {
  content: "\25B8"; display: inline-block; margin-right: 6px;   /* ▸ */
  transition: transform .15s ease;
}
.environment-resource-panel[open] > .environment-resource-summary::before { transform: rotate(90deg); }
.resource-detail-list {
  list-style: none; margin: 9px 0 0; padding: 0;
  display: flex; flex-direction: column; gap: 6px;
}
/* Two lines, deliberately: the kind takes the first row on its own and the
   name, any shared tag, and the state badge share the second. On one row
   the kind and a fully-qualified service name crowded each other out and
   the name ellipsised almost immediately (owner feedback, 2026-07-26). */
.resource-detail-item {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px;
  padding: 7px 10px; background: var(--cf-panel);
  border: 1px solid var(--cf-border); border-radius: 7px;
}
.resource-detail-kind {
  flex: 0 0 100%;
  font-family: var(--cf-sans); font-size: 11px; color: var(--cf-fg-faint); white-space: nowrap;
}
.resource-detail-name {
  font-family: var(--cf-mono); font-size: 12.5px; color: var(--cf-fg);
  flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis;
}
.resource-detail-shared-tag {
  font-family: var(--cf-sans); font-size: 10.5px; font-weight: 650;
  text-transform: uppercase; letter-spacing: .04em;
  padding: 2px 7px; border-radius: 999px;
  color: var(--cf-fg-dim); background: var(--cf-panel-inset); border: 1px solid var(--cf-border-strong);
}

/* ============================================================================
   SWIMLANES (plan N3)
   ----------------------------------------------------------------------------
   Not in the delivered design handoff at all (it postdates it) — built
   from the system's own primitives per the same "extend, don't invent"
   instruction the history/provenance section above already follows: the
   card-row's own panel chrome, `.burn-rate-unpriced`'s own "floor, not
   the whole picture" warning (reused verbatim for a lane's own unpriced
   note), and `.environment-card`'s own shape for the cards themselves.

   One lane per group, toggled in from the flat `.environment-list` by the
   header's `.dashboard-grouping-toggle`. Each lane is a flex ROW: a
   non-scrolling summary panel (`.environment-lane-summary`) on the left,
   and the group's own cards in a horizontally scrolling strip
   (`.environment-lane-scroll` → `.environment-lane-cards`) on the right.

   The summary panel needs no `position: sticky` of its own: it is a
   plain flex SIBLING of the scroll strip, not a descendant of it, so it
   is never inside the region that scrolls and is always on screen
   regardless of horizontal scroll offset — simpler than sticky
   positioning and correct by construction.

   -- Full-bleed scroll track --
   `.environment-lane-scroll` starts flush with the lane's own left edge
   (the same page gutter every other panel on this page starts at — see
   `.environment-lane`'s own zero horizontal padding below, which is what
   keeps the maths exact) and its RIGHT edge bleeds out to the actual
   browser viewport edge, past the centred `.dashboard-main` column,
   using the standard "break out of a centred, max-width container on one
   side only" calc: `margin-right: calc(50% - 50vw)` pulls the box out by
   exactly the gap between the lane's own right edge and the viewport
   edge (percentages resolve against `.environment-lane`'s own
   content-box width, which — because that box carries zero horizontal
   padding of its own — equals `.dashboard-main`'s content width exactly,
   which is what makes the maths land on the real viewport edge rather
   than an approximation). `padding-right: calc(50vw - 50%)` — the exact
   inverse — is applied to the SAME scrolling box (padding on a scroll
   container's trailing edge is itself part of the scrollable area, per
   the CSS Overflow spec) so that scrolling all the way to the end brings
   the last card back to rest at the ordinary page edge every other panel
   uses, rather than flush against the raw viewport edge. An estate with
   only two or three environments in a lane never overflows its own
   (very wide, full-bleed) scroll track at all, so nothing above ever
   triggers for it — exactly the plan's own worked example.

   -- Scroll affordances (plan N3: "a trap without them") --
   Keyboard: `tabindex="0"` + `role="region"` + `aria-label` on the
   markup side is all that is needed — every evergreen browser already
   scrolls a focused, overflowing region with the arrow keys, so no
   `keydown` handler is written here. `:focus-visible` below gives that
   focus an explicit, visible outline rather than relying on the
   browser's own default (inconsistent across browsers on a `div`).
   Edge fade: the classic CSS-only "scrolling shadows" technique (two
   `local`-attached linear-gradients, matched to `--cf-panel`, that mask
   a shadow near either edge WHILE there is still content behind them to
   reveal; two `scroll`-attached radial-gradients, in `--cf-lane-edge`,
   that supply the shadow itself) — it needs no JavaScript scroll
   listener and, because it is driven by the actual scrollable overflow,
   it disappears on its own the moment a lane's content fits without
   scrolling.
   ============================================================================ */
.environment-lanes { display: flex; flex-direction: column; gap: 16px; }

.environment-lane {
  display: flex; align-items: stretch;
  padding: 16px 0;                          /* zero horizontal — see this section's own header comment */
  border: 1px solid var(--cf-border); border-radius: var(--cf-radius);
  background: var(--cf-panel); box-shadow: var(--cf-shadow);
}
.environment-lane-summary {
  flex: 0 0 220px; min-width: 0;
  display: flex; flex-direction: column; gap: 6px;
  padding: 0 18px;
  border-right: 1px solid var(--cf-border);
}
.environment-lane-title {
  margin: 0; font-family: var(--cf-mono);
  font-size: 14px; font-weight: 650; color: var(--cf-fg); word-break: break-word;
}
.environment-lane-stats {
  margin: 0; font-family: var(--cf-mono); font-size: 12.5px; color: var(--cf-fg-dim);
  font-variant-numeric: tabular-nums;
}
/* Per-group sparkline (plan N5): that group's daily series, single line,
   no legend, self-scaled — landed into the exact space this section's
   own summary column already reserved for it. */
.environment-lane-sparkline { margin-top: 2px; }
.environment-lane-sparkline-svg { display: block; width: 100%; height: 28px; }
.environment-lane-sparkline-line { fill: none; stroke: var(--chart-color); stroke-width: 1.5; }
.environment-lane-sparkline-empty {
  margin: 2px 0 0; font-size: 11px; color: var(--cf-fg-faint); font-style: italic;
}

.environment-lane-scroll {
  flex: 1 1 auto; min-width: 0;
  overflow-x: auto; overflow-y: hidden;
  margin-right: calc(50% - 50vw);
  padding-right: calc(50vw - 50%);

  background-color: var(--cf-panel);
  background-image:
    linear-gradient(to right, var(--cf-panel) 30%, rgba(0,0,0,0)),
    linear-gradient(to left,  var(--cf-panel) 30%, rgba(0,0,0,0)),
    radial-gradient(farthest-side at 0 50%,   var(--cf-lane-edge), rgba(0,0,0,0)),
    radial-gradient(farthest-side at 100% 50%, var(--cf-lane-edge), rgba(0,0,0,0));
  background-repeat: no-repeat;
  background-size: 40px 100%, 40px 100%, 12px 100%, 12px 100%;
  background-position: left center, right center, left center, right center;
  background-attachment: local, local, scroll, scroll;
}
.environment-lane-scroll:focus-visible {
  outline: 2px solid var(--cf-accent); outline-offset: -2px;
}
.environment-lane-cards {
  display: flex; align-items: stretch; gap: 16px;
  padding-left: 18px;
}
.environment-lane-cards .environment-card { flex: 0 0 var(--cf-card-w); }

/* ============================================================================
   ACTION PANEL (§6.6)
   ============================================================================ */
.environment-actions {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  justify-content: flex-end;                 /* single control (On / Refresh) sits right */
  margin-top: auto;                          /* pin to card bottom, aligning across cards */
  padding-top: 13px; border-top: 1px solid var(--cf-border);
}
/* Read-only environments: the actions row still exists (it carries the
   card's bottom rule and the margin-top:auto that aligns every card's
   footer), but holds a note where the controls would be — so a read-only
   card stays the same shape as its neighbours instead of collapsing and
   breaking the swim-lane's alignment. */
.environment-actions-read-only {
  margin: 0; font-size: 12px; color: var(--cf-fg-dim); text-align: right;
}

.environment-action { display: flex; align-items: center; gap: 6px; }
.environment-action-extend { margin-right: auto; }  /* Extend left, Off right on ON cards */

/* Duration dropdowns — never disabled during in-flight (§6.6) */
.action-duration-select {
  font-family: var(--cf-mono); font-size: 12.5px; color: var(--cf-fg);
  background-color: var(--cf-panel-inset);
  border: 1px solid var(--cf-border-strong); border-radius: 6px;
  padding: 6px 26px 6px 10px; cursor: pointer;
  appearance: none; -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%238b93a1' stroke-width='1.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 9px center;
}

/* Buttons */
.environment-action-button {
  font-family: var(--cf-sans); font-size: 13px; font-weight: 600;
  padding: 7px 14px; border-radius: 7px; border: 1px solid transparent;
  line-height: 1; cursor: pointer; transition: filter .12s, opacity .12s;
}
.environment-action-on-button      { background: var(--cf-on);     color: #fff; }
.environment-action-extend-button  { background: var(--cf-accent); color: var(--cf-accent-fg); }
/* Green reads as "start this up", which is only what the control does on an
   environment that is actually off. On a running one it sets an auto-off
   timer, and on a drifted one it forces a state — both adjustments to
   something already running, so they take the accent colour that Extend
   (the other adjust-in-place action) already uses. */
.environment-action-on-button.environment-action-adjust-button {
  background: var(--cf-accent); color: var(--cf-accent-fg);
}
.environment-action-button.danger  { background: var(--cf-danger); color: #fff; }  /* Off + confirm */
.environment-action-off-cancel-button {
  background: transparent; color: var(--cf-fg-dim);
  border-color: var(--cf-border-strong); font-size: 12.5px; padding: 6px 11px;
}
.environment-action-button:hover:not(:disabled) { filter: brightness(1.06); }
/* In-flight disabled (§6.6) — unambiguous */
.environment-action-button:disabled { opacity: .4; cursor: not-allowed; filter: saturate(.4); }

/* Armed off-confirmation (§6.6) */
.environment-action-confirm-group {
  display: flex; align-items: center; gap: 7px;
  padding: 4px 5px 4px 10px;
  background: var(--cf-danger-soft); border: 1px solid var(--cf-danger); border-radius: 8px;
}
.environment-action-confirm-prompt { font-size: 12.5px; font-weight: 650; color: var(--cf-danger); }

/* Per-card in-flight progress bar — needs a <div class="environment-card-progress">
   as the card's first child while a request is in flight (see README). */
.environment-card-progress {
  position: absolute; top: 0; left: 0; right: 0; height: 2px;
  overflow: hidden; border-radius: var(--cf-radius) var(--cf-radius) 0 0;
}
.environment-card-progress::after {
  content: ""; display: block; width: 36%; height: 100%;
  background: var(--cf-accent); animation: cf-progress 1.1s ease-in-out infinite;
}

/* Header buttons */
.dashboard-refresh-button {
  font-family: var(--cf-sans); font-size: 13px; font-weight: 600;
  padding: 7px 14px; border-radius: 7px; border: 1px solid transparent;
  background: var(--cf-accent); color: var(--cf-accent-fg); cursor: pointer;
}
.dashboard-logout-button {
  font-family: var(--cf-sans); font-size: 13px; font-weight: 600;
  padding: 7px 14px; border-radius: 7px;
  background: transparent; color: var(--cf-fg-dim);
  border: 1px solid var(--cf-border-strong); cursor: pointer;
}
/* Y5 addition: the design handoff never mentions history at all (see this
   file's own `HISTORY VIEW AND COST PROVENANCE` section below) — styled
   as a neutral secondary action, the same visual weight as Log out, since
   it is a read-only lookup rather than a mutating or navigational one. */
/* Plan N3's header toggle shares the same neutral secondary-action
   weight — it is a view preference, not a mutating or navigational
   control either. */
.dashboard-history-button,
.dashboard-grouping-toggle {
  font-family: var(--cf-sans); font-size: 13px; font-weight: 600;
  padding: 7px 14px; border-radius: 7px;
  background: transparent; color: var(--cf-fg-dim);
  border: 1px solid var(--cf-border-strong); cursor: pointer;
}
.dashboard-history-button:hover,
.dashboard-grouping-toggle:hover { color: var(--cf-fg); border-color: var(--cf-fg-dim); }

/* ============================================================================
   TOASTS (§5.3)
   ============================================================================ */
.toast-list {
  position: fixed; top: 16px; right: 16px; z-index: 60;
  display: flex; flex-direction: column; gap: 10px;
  width: min(380px, calc(100vw - 32px));
}
.toast {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 12px 13px;
  background: var(--cf-panel); border: 1px solid var(--cf-border);
  border-left: 3px solid var(--cf-danger); border-radius: 9px;
  box-shadow: var(--cf-shadow); animation: cf-fade .18s ease;
}
.toast-message {
  flex: 1; font-size: 13px; line-height: 1.45; color: var(--cf-fg);
  word-break: break-word; white-space: pre-wrap;   /* multi-line refusals wrap, never truncate */
}
.toast-dismiss {
  flex: none; width: 26px; height: 26px;
  display: flex; align-items: center; justify-content: center;
  font-size: 18px; line-height: 1; color: var(--cf-fg-dim);
  background: transparent; border: 1px solid var(--cf-border); border-radius: 6px;
  cursor: pointer;
}
.toast-dismiss:hover { color: var(--cf-fg); border-color: var(--cf-border-strong); }

/* ============================================================================
   HISTORY VIEW AND COST PROVENANCE (plan task Y5)
   ----------------------------------------------------------------------------
   Genuine design gap, not an oversight to second-guess: the delivered
   handoff (control-freak.css / the .dc.html reference / its README) never
   mentions the action-history view, the per-card "History" link, or any
   provenance label at all — no class name, no screen, no token. Everything
   below is built ONLY from primitives the delivered system already
   defines (panel chrome, badge/pill colour+shape semantics, the
   `.banner`/`.empty-state` family, the auto-fit responsive technique
   `.burn-rate-totals` already uses), per plan task Y5's own instruction
   to extend rather than invent a parallel visual language.

   Recorded gap for a design follow-up: the delivered system has no
   genuine multi-column TABLE pattern to map the history list onto (the
   plan's own wording assumes one exists). The closest analogue is
   `.shared-resource-list`/`.shared-resource-item`'s flex-row shape, which
   is what `.history-event` below extends — a real design pass may want a
   purpose-built dense table treatment instead, especially once history
   lists grow long enough to want sortable/sticky column headers.
   ============================================================================ */

/* -- Per-card "History" link (spec addendum §1, plan O3) --
   Sized and pill-shaped to sit beside the state badge in the card header
   as a matching pair, but kept neutral (never on/off/drift-coloured) since
   it carries no state of its own — see the `.environment-card-header`
   layout note above for why the header no longer uses space-between. */
.environment-history-button {
  font-family: var(--cf-sans); font-size: 11px; font-weight: 650;
  padding: 3px 9px; border-radius: 999px; line-height: 1.4; white-space: nowrap;
  background: transparent; color: var(--cf-fg-faint);
  border: 1px solid var(--cf-border-strong); cursor: pointer;
}
.environment-history-button:hover { color: var(--cf-fg-dim); border-color: var(--cf-fg-dim); }

/* -- Cost block: the "no rate at all" case (spec addendum §2) --
   The delivered CSS styles the three known-rate rows and the mtd row but
   never this one — the paragraph that stands in for them all when the
   provenance is unknown. Faint and italic, matching the same "recede,
   don't alarm" treatment the off-card indefinite-session row already uses
   for its own de-emphasised case. */
.environment-cost-unknown {
  margin: 0; font-size: 12.5px; color: var(--cf-fg-faint); font-style: italic;
}

/* -- Cost-provenance caption --
   "Provenance maps onto its badge patterns" (plan Y5): a small coloured
   chip rather than plain text, reusing the exact soft-background/border
   pairing `.environment-state-badge`'s colour tokens already define per
   source, plus `.shared-resource-state-unknown`'s own dashed-border
   "unknown" treatment for the unknown case. Not pill-shaped (`border-
   radius: 999px`) like the state badges — this caption's text is prose
   (it can carry a full observation-window timestamp range), which wraps
   badly inside a fully-rounded pill; a soft rounded box reads as the same
   badge family without that failure mode. */
.environment-cost-provenance {
  margin: 6px 0 0; padding: 4px 8px;
  border-radius: 6px; border: 1px solid var(--cf-border);
  background: var(--cf-panel); font-size: 10.5px; line-height: 1.4;
  color: var(--cf-fg-dim);
}
.environment-cost-provenance-observed { color: var(--cf-fg-dim); }
.environment-cost-provenance-averaged {
  color: var(--cf-drift); background: var(--cf-drift-soft); border-color: var(--cf-drift);
}
.environment-cost-provenance-override {
  color: var(--cf-accent); background: var(--cf-panel-inset); border-color: var(--cf-border-strong);
}
.environment-cost-provenance-unknown {
  color: var(--cf-fg-faint); font-style: italic; background: transparent; border-style: dashed;
}

/* -- Org-wide "some figures have no known cost" note --
   Reuses the drift/amber token already meaning "indeterminate, don't
   trust the total blindly" for `.environment-card-partial`/
   `.environment-count-partial`, plus that badge's own shape-marker
   convention (§4: state is never colour-only) via the same ▲ glyph. */
.burn-rate-unpriced {
  margin: 0; font-size: 12px; color: var(--cf-drift);
}
.burn-rate-unpriced::before { content: "\25B2 "; } /* ▲ */

/* -- History panel --
   A fixed viewport-anchored drawer: not a new idea (`.toast-list` is
   already fixed-positioned chrome floating over the page), just applied
   at panel scale using `.burn-rate-panel`'s own panel/border/shadow look
   instead of inventing a modal/backdrop treatment the delivered system
   has no example of at all. `top: 64px` is an approximation of the
   sticky header's own rendered height, not a measured constant. */
.history-panel {
  position: fixed; top: 64px; right: 16px; bottom: 16px;
  width: min(480px, calc(100vw - 32px));
  z-index: 40; /* below .toast-list (60), above page content */
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--cf-panel); border: 1px solid var(--cf-border);
  border-radius: var(--cf-radius); box-shadow: var(--cf-shadow);
  animation: cf-fade .18s ease;
}
.history-panel-header {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 14px 16px; border-bottom: 1px solid var(--cf-border); flex: none;
}
.history-panel-title {
  margin: 0; font-family: var(--cf-mono); font-size: 14px; font-weight: 650; color: var(--cf-fg);
}
.history-panel-close {
  font-family: var(--cf-sans); font-size: 12.5px; font-weight: 600;
  padding: 6px 11px; border-radius: 6px;
  background: transparent; color: var(--cf-fg-dim);
  border: 1px solid var(--cf-border-strong); cursor: pointer;
}
.history-panel-close:hover { color: var(--cf-fg); border-color: var(--cf-fg-dim); }
.history-panel-body {
  flex: 1; overflow-y: auto; padding: 14px 16px;
  display: flex; flex-direction: column; gap: 10px;
}
/* The partial-read note (malformed log entries) — a `.banner.warning`. */
.history-malformed-note { margin: 0; }

/* -- History event list --
   The delivered system's own closest thing to a table row: extends
   `.shared-resource-item`'s flex row (panel-inset background, bordered,
   rounded) rather than a genuine `<table>` treatment (see this section's
   own header comment for that recorded gap). `flex-wrap` plus giving the
   outcome column `flex-basis: 100%` lets a long refusal/failure detail
   drop to its own line with no breakpoint needed — the same auto-fit-
   without-a-breakpoint idea `.burn-rate-totals` already uses. */
.history-event-list {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 6px;
}
.history-event {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 14px;
  padding: 8px 10px;
  background: var(--cf-panel-inset); border: 1px solid var(--cf-border); border-radius: 7px;
  font-size: 12.5px;
}
.history-event-time {
  font-family: var(--cf-mono); font-size: 11.5px; color: var(--cf-fg-faint); white-space: nowrap;
}
.history-event-actor {
  font-family: var(--cf-mono); font-size: 12px; color: var(--cf-fg-dim);
}
.history-event-action {
  font-family: var(--cf-mono); font-size: 11px; font-weight: 650; color: var(--cf-fg);
  text-transform: uppercase; letter-spacing: .04em;
  padding: 2px 7px; border-radius: 999px;
  background: var(--cf-panel); border: 1px solid var(--cf-border);
}
.history-event-target {
  font-family: var(--cf-mono); font-size: 12px; color: var(--cf-fg);
}
/* Full-width so a long "refused: ..."/"failed: ..." detail wraps on its
   own line rather than squeezing the metadata fields above it. Coloured
   text with a redundant glyph, not a pill — see this section's own header
   comment on why prose content doesn't take the fully-rounded badge
   shape. */
.history-event-outcome {
  flex: 1 1 100%; font-size: 12px; font-weight: 600; word-break: break-word;
}
.history-event-outcome-success { color: var(--cf-on); }
.history-event-outcome-success::before { content: "\25CF "; } /* ● */
.history-event-outcome-refused { color: var(--cf-drift); }
.history-event-outcome-refused::before { content: "\25B2 "; } /* ▲ */
.history-event-outcome-failed { color: var(--cf-danger); }
.history-event-outcome-failed::before { content: "\26A0 "; } /* ⚠ */

/* ============================================================================
   RESPONSIVE (down to tablet, §3)
   ============================================================================ */
@media (max-width: 820px) {
  :root { --cf-card-w: 100%; }
  .environment-card { flex-basis: 100%; }
  .dashboard-header { flex-wrap: wrap; }
  /* Y5: the fixed-width drawer would be cramped or clipped below tablet
     width — pin it edge-to-edge instead of a fixed right-anchored width. */
  .history-panel { left: 16px; right: 16px; width: auto; }
  /* Plan N3: "the sticky summary stacks ABOVE its lane rather than
     beside it — it otherwise eats the width permanently." Stacking the
     lane's own flex row into a column is the whole change; the scroll
     strip's full-bleed maths (`.environment-lane-scroll`) keeps working
     unchanged underneath it. */
  .environment-lane { flex-direction: column; }
  .environment-lane-summary {
    flex-basis: auto; width: auto;
    border-right: none; border-bottom: 1px solid var(--cf-border);
    padding: 0 18px 12px;
  }
}
