/* =====================================================================
   The frame: the rail, the page header, the atoms.

   Everything here reads from tokens-v2.css. No hex values below — the next
   palette decision should be one file, not thirty.
   ===================================================================== */

/* ---------------------------------------------------------------------
   The rail
   ------------------------------------------------------------------ */

/*
 * A fixed rail beside a spacer that keeps the collapsed width.
 *
 * The rail expands over the page rather than pushing it: a nav that reflows
 * the content moves the thing you were about to click, and it moves it just as
 * your pointer arrives, because arriving is what opened the nav.
 */
.rail-spacer {
  width: var(--v2-rail);
  min-width: var(--v2-rail);
  flex-shrink: 0;
}

/*
 * And the second level's width, on the section being worked in.
 *
 * That one panel is part of the page rather than over it: it is where the
 * next click goes, so it stays open, and a panel that stayed open on top of
 * the content would cover the left of every screen. Every *other* panel
 * floats, which reflows nothing — see .rail-panel below.
 */
.rail-spacer[data-pinned="true"] {
  width: calc(var(--v2-rail) + var(--v2-rail-panel));
  min-width: calc(var(--v2-rail) + var(--v2-rail-panel));
}

.rail {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  width: var(--v2-rail);
  z-index: 50;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--v2-accent);
  background-image: var(--v2-accent-gradient);
  box-shadow: var(--v2-shadow-rail);
  transition: width .15s ease;
}

/*
 * Demo mode prepends a banner to <body> and sticks it to the top. The rail is
 * fixed, so it knows nothing about it and would start underneath it — losing
 * its brand behind a bar that is deliberately the loudest thing on the page.
 */
.demo-banner ~ .v2-frame .rail { top: var(--v2-banner); }

.rail:hover,
.rail:focus-within {
  width: var(--v2-rail-open);
  overflow: visible;
}

/*
 * The labels are laid out at the open width and faded, rather than being
 * added on hover: text that appears has to be measured, and measuring on
 * hover is what makes a nav stutter as it opens.
 */
.rail-brand,
.rail-link {
  width: var(--v2-rail-open);
  display: flex;
  align-items: center;
  gap: 14px;
  white-space: nowrap;
  color: var(--c-neutral-100);
  text-decoration: none;
  flex-shrink: 0;
}

.rail-label {
  opacity: 0;
  transition: opacity .1s ease;
}

.rail:hover .rail-label,
.rail:focus-within .rail-label { opacity: 1; }

.rail-brand {
  padding: 20px;
  border-bottom: 1px solid rgba(255, 255, 255, .2);
  font-weight: 800;
  font-size: 13px;
  line-height: 16px;
}

.rail-mark {
  width: 26px;
  height: 26px;
  border-radius: 7px;
  background: var(--c-neutral-100);
  color: var(--v2-accent);
  display: grid;
  place-items: center;
  font-weight: 800;
  font-size: 13px;
  flex-shrink: 0;
}

.rail-list,
.rail-foot {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 12px;
}

.rail-list { flex: 1; overflow-y: auto; overflow-x: hidden; }
.rail-foot { border-top: 1px solid rgba(255, 255, 255, .2); }

/* ---------------------------------------------------------------------
   The groups

   Sixteen entries in one column is a list people scan rather than read. The
   groups break it into the questions somebody arrives with, and they show two
   ways: at 64px as a rule between entries, at 240px as the name instead.

   Both states are laid out identically. The name is always in the DOM, at the
   open width, and the rule is always there too — the name fades in as the rule
   fades out, and neither is added or removed. That is the same reason
   .rail-label fades rather than appears: a nav that measures text as it opens
   is a nav that stutters as it opens.
   ------------------------------------------------------------------ */

/*
 * The divider lives on the group rather than on its name, because the name is
 * faded out when the rail is collapsed and `opacity: 0` takes the whole
 * subtree with it — a rule drawn as the name's own ::before was invisible in
 * exactly the state it existed for.
 *
 * It fades to transparent rather than to none, so the space it holds never
 * changes and the rail does not jump as it opens.
 */
/*
 * One first-level entry, and the panel that belongs to it.
 *
 * `position: static` on purpose: the panel is fixed, so it positions
 * against the viewport rather than against this, which is what lets it
 * start at the rail's edge and run the full height whatever the entry's
 * own height or scroll position is.
 */
.rail-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
}





/*
 * Your own account, at the foot of the rail.
 *
 * Initials rather than a person glyph: it is the one entry here about a
 * particular person, and a rail of nine identical outlines is one where the
 * thing you are looking for looks like everything else. The circle is the
 * same 26px as the brand's mark, so the two ends of the rail agree.
 */
.rail-link[data-account="true"] { padding: 7px 11px; }

.rail-account-mark {
  flex: none;
  width: 28px;
  height: 28px;
  border-radius: 999px;
  display: grid;
  place-items: center;
  background: var(--c-neutral-100);
  color: var(--v2-accent);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .02em;
}

.rail-account-body {
  display: flex;
  flex-direction: column;
  gap: 0;
  min-width: 0;
}

.rail-account-name {
  font-size: 13px;
  font-weight: 600;
  line-height: 16px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The address under the name, quieter: it is how you tell two people of the
   same name apart, not what you read first. */
.rail-account-mail {
  font-size: 10.5px;
  line-height: 14px;
  color: rgba(255, 255, 255, .72);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rail-link[data-account="true"][data-active="true"] .rail-account-mail {
  color: var(--v2-ink-meta);
}
.rail-link[data-account="true"][data-active="true"] .rail-account-mark {
  background: var(--v2-accent);
  color: var(--c-neutral-100);
}

/* Which deploy this is, at the very foot: small, mono, legible on the red. */
/* ---------------------------------------------------------------------
   The palette, at the foot of the rail

   Two controls on the same footer as the version badge, because this is
   where somebody looks for the application rather than for the plan.
   Light or dark is one press; which palette opens a list beside the
   rail, so six can be compared without wearing six of them.

   Shaped like the nav links above them — an icon on the left, a word
   that fades in when the rail opens — so they read as part of the rail
   and not as something bolted to the bottom of it.
   ------------------------------------------------------------------ */

.rail-appearance {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding-bottom: 4px;
}

.rail-foot-btn {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 7px 10px;
  border: 0;
  border-radius: var(--v2-radius);
  background: none;
  cursor: pointer;
  font: 500 12.5px/16px inherit;
  color: rgba(255, 255, 255, .85);
  text-align: left;
  white-space: nowrap;
  overflow: hidden;
}
.rail-foot-btn:hover { background: rgba(255, 255, 255, .14); color: var(--c-neutral-100); }
.rail-foot-btn:focus-visible {
  outline: 2px solid var(--c-neutral-100);
  outline-offset: -2px;
}
.rail-foot-btn .icon { flex: none; }

/* The key, pushed to the right of the word it belongs to. Styled like
   the one in the nav panel's own footer, because they are the same kind
   of thing and there are three of them now. */
.rail-key {
  margin-left: auto;
  padding: 1px 5px;
  border: 1px solid rgba(255, 255, 255, .3);
  border-radius: 4px;
  font-family: var(--v2-mono);
  font-size: 10px;
  line-height: 14px;
  color: rgba(255, 255, 255, .75);
}
/* The sun turns a little as it comes round, so a press that changes
   nothing a 64px rail can show still shows something. */
.rail-foot-btn[data-mode="light"] .icon { transform: rotate(0deg); }
.rail-foot-btn[data-mode="dark"] .icon { transform: rotate(-18deg); }
.rail-foot-btn .icon { transition: transform .18s ease; }
@media (prefers-reduced-motion: reduce) {
  .rail-foot-btn .icon { transition: none; }
}

/*
 * The list, beside the rail rather than inside it.
 *
 * Inside a 64px column it would be six words nobody could read, and
 * opening the rail to see it would mean the rail closing again the
 * moment the pointer left to reach a swatch.
 */
.rail-palettes {
  position: absolute;
  left: calc(100% + 6px);
  bottom: 0;
  z-index: 60;
  width: 196px;
  padding: 6px;
  border: 1px solid var(--v2-hairline);
  border-radius: var(--v2-radius-lg);
  background: var(--v2-surface);
  box-shadow: var(--v2-shadow-rail);
}
.rail-palettes[hidden] { display: none; }

.rail-palette {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  padding: 6px;
  border: 1px solid transparent;
  border-radius: var(--v2-radius);
  background: none;
  cursor: pointer;
  font: 600 12px/1.3 inherit;
  color: var(--v2-ink);
  text-align: left;
}
.rail-palette:hover { background: var(--v2-band); border-color: var(--v2-hairline); }
.rail-palette[data-on="true"] {
  border-color: var(--v2-accent);
  background: var(--v2-accent-soft);
}
.rail-palette:focus-visible {
  outline: 2px solid var(--v2-accent);
  outline-offset: 1px;
}

/* Four chips in the palette the row names, not in the one being worn:
   six pictures of the palette you already have is the one thing a
   picker must not be. */
.rail-swatch {
  display: flex;
  flex: none;
  width: 42px;
  height: 20px;
  border-radius: 5px;
  overflow: hidden;
  border: 1px solid var(--v2-hairline);
}
/* The paper gets the room, because that is what most of a screen is;
   the accent gets a stripe, because that is what a theme changes. */
.rail-chip { flex: 1; }
.rail-chip-page { flex: 2; background: var(--c-neutral-96); }
.rail-chip-surface { flex: 2; background: var(--c-neutral-100); }
.rail-chip-accent { background: var(--c-accent-49a); }
.rail-chip-ink { background: var(--c-neutral-10b); }

.rail-version {
  display: block; text-align: center; padding: 8px 4px 10px;
  font-family: var(--v2-mono); font-size: 10px; font-weight: 700;
  color: rgba(255, 255, 255, .75); letter-spacing: .02em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/*
 * 8px, not 10.
 *
 * The rail carries twenty-four entries in eight groups now — the eight
 * reports are navigation rather than a tab bar on one page — and at the old
 * spacing the last three groups fell below the fold on a 1080p screen. Two
 * pixels a row is ninety pixels of rail, which is three groups' worth of
 * heading.
 */
.rail-link {
  padding: 8px 12px;
  border-radius: var(--v2-radius);
  font-size: 13px;
  font-weight: 500;
  color: rgba(255, 255, 255, .85);
}

.rail-link:hover { background: rgba(255, 255, 255, .14); color: var(--c-neutral-100); }

/*
 * The current screen, marked with an attribute so the state is one selector
 * and cannot be half-applied.
 *
 * A pill rather than a full-width block: the rail is a column of red and
 * the one white shape on it is where you are, so it wants an edge on all
 * four sides. It runs past the rail's right edge by the radius, which is
 * what joins it to the panel beside it — one object, two parts, rather
 * than a marker and a drawer that happen to be adjacent.
 */
.rail-link[data-active="true"] {
  background: var(--c-neutral-100);
  color: var(--v2-accent);
  font-weight: 700;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .18);
}

.rail-link:focus-visible {
  outline: 2px solid var(--c-neutral-100);
  outline-offset: -2px;
}



/*
 * People waiting for access, on the System Settings link.
 *
 * There is no email when somebody applies, so this badge *is* the
 * notification — which is why it sits on the rail, visible from every screen,
 * rather than on the one page an administrator would have to think to open.
 *
 * Positioned against the link rather than placed in the flow, so it reads at
 * the collapsed 64px width too: the label is clipped there, the icon is not,
 * and a count that only appeared on hover would be a notification nobody ever
 * saw.
 */
.rail-link { position: relative; }
.rail-badge {
  position: absolute;
  top: 3px;
  left: 25px;
  min-width: 18px;
  padding: 0 5px;
  border-radius: 999px;
  /* White on the red rail, not red on red. The active link is marked the same
     way for the same reason — on this gradient, white is the only fill that
     reads at every point of it. */
  background: var(--c-neutral-100);
  color: var(--v2-accent);
  font-family: var(--v2-mono);
  font-size: 10px;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .3);
}
/* The active screen inverts the rail, so the badge has to invert back or it
   would be a white pill on a white link. */
.rail-link[data-active="true"] .rail-badge {
  background: var(--v2-accent);
  color: var(--c-neutral-100);
  box-shadow: none;
}

/* ---------------------------------------------------------------------
   The second level

   The rail carries the nine groups. The screens inside one live here, in a
   panel that opens beside the rail rather than below the entry — a rail
   that listed every screen was twenty-four entries that did not fit a
   1080p window, which is why the reports used to be hidden unless you were
   already among them.

   Two states, and the difference is whether the page moves:

   *Pinned* is the section you are in. It holds its width, because the
   second level is where your next click goes and a panel that shut when
   the pointer left would have to be re-opened for every one of them. The
   spacer accounts for it, so nothing is covered.

   *Floating* is every other section, on hover or keyboard focus. It lies
   over the page and reflows nothing: a nav that moved the content each
   time a pointer crossed it would move the thing you were about to click,
   just as you arrived.
   ------------------------------------------------------------------ */

.rail-panel {
  position: fixed;
  top: 0;
  bottom: 0;
  left: var(--v2-rail);
  width: var(--v2-rail-panel);
  z-index: 49;
  display: flex;
  flex-direction: column;
  padding: 10px 0 14px;
  background: var(--v2-surface);
  border-right: 1px solid var(--v2-rule);
  box-shadow: var(--v2-shadow-rail);
  /* Laid out either way and hidden by opacity rather than by display, so
     opening it measures nothing. Text that has to be measured as it appears
     is what makes a nav stutter. */
  opacity: 0;
  visibility: hidden;
  transition: opacity .12s ease, visibility .12s ease, left .15s ease;
}

.demo-banner ~ .v2-frame .rail-panel { top: var(--v2-banner); }

/* The rail widens under the pointer, so the panel steps aside to stay
   beside it rather than under it. */
.rail:hover ~ .rail-panel,
.rail:focus-within ~ .rail-panel,
.rail:hover .rail-panel,
.rail:focus-within .rail-panel { left: var(--v2-rail-open); }

.rail-panel[data-pinned="true"],
.rail-item:hover .rail-panel,
.rail-item:focus-within .rail-panel {
  opacity: 1;
  visibility: visible;
}

/*
 * A head that says what has been opened.
 *
 * The group's mark, MODULE over its name so a reader knows which level of
 * the nav they are looking at, and how many screens are under it. A panel
 * that opened with a list and no heading was a drawer whose label was on
 * the rail behind it, under the pointer that opened it.
 */
.rail-panel-head {
  display: flex;
  align-items: flex-start;
  gap: 11px;
  padding: 16px 14px 14px;
  border-bottom: 1px solid var(--v2-rule);
}

.rail-panel-mark {
  flex: none;
  width: 34px;
  height: 34px;
  border-radius: 10px;
  display: grid;
  place-items: center;
  background: var(--v2-accent);
  background-image: var(--v2-accent-gradient);
  color: var(--c-neutral-100);
}

.rail-panel-titles {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}

.rail-panel-eyebrow {
  font-size: 9.5px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .1em;
  color: var(--v2-accent);
}

.rail-panel-title {
  font-size: 17px;
  font-weight: 800;
  line-height: 1.15;
  color: var(--v2-ink);
  /* Wraps rather than clips: "About Fenix Helper" is wider than the panel,
     and a group's name cut to "About Fenix Hel…" is a name nobody reads. */
  overflow-wrap: anywhere;
}

.rail-panel-count {
  font-size: 11.5px;
  color: var(--v2-ink-meta);
}

/*
 * Only the pinned panel can be shut.
 *
 * A floating one closes when the pointer leaves, so a button on it would
 * be a control that did what was about to happen anyway — and one that
 * could not be reached, because reaching for it is leaving.
 */
.rail-panel-close {
  flex: none;
  margin-left: auto;
  width: 26px;
  height: 26px;
  display: none;
  place-items: center;
  border: 1px solid var(--v2-rule);
  border-radius: 999px;
  background: var(--v2-surface);
  color: var(--v2-ink-soft);
  cursor: pointer;
}
.rail-panel[data-pinned="true"] .rail-panel-close { display: grid; }
.rail-panel-close:hover { background: var(--v2-page); color: var(--v2-ink); }
.rail-panel-close:focus-visible {
  outline: 2px solid var(--v2-accent);
  outline-offset: 1px;
}

.rail-panel-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px 8px;
  /* Eight reports under four headings is taller than a short window.
     The panel scrolls; the rail does not. */
  overflow-y: auto;
  overflow-x: hidden;
}

/*
 * A screen, as a card.
 *
 * The icon is what it is recognised by at a glance, the name is what it is
 * called, and the sentence under it is what it is for — the same sentence
 * the launcher's tile carries, from the same list. A rail of names alone
 * made somebody open a screen to find out what it was.
 */
.rail-sub {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 9px 10px;
  border-radius: var(--v2-radius);
  border-left: 3px solid transparent;
  font-size: 12.5px;
  font-weight: 500;
  line-height: 1.35;
  color: var(--v2-ink-soft);
  text-decoration: none;
}

.rail-sub-mark {
  flex: none;
  width: 28px;
  height: 28px;
  border-radius: 8px;
  display: grid;
  place-items: center;
  background: var(--v2-page);
  color: var(--v2-ink-soft);
}

.rail-sub-body {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}

.rail-sub-name {
  font-size: 13px;
  font-weight: 700;
  color: var(--v2-ink);
}

/* Two lines, clamped. The sentence is there to choose by, not to read in
   full — the screen behind it says the rest. */
.rail-sub-blurb {
  font-size: 11.5px;
  line-height: 1.35;
  color: var(--v2-ink-meta);
  /* Three lines, not two. Two cut every sentence in the panel mid-word
     — "The gaps: requirements nobody is building, storie…" — and a
     description that stops before it says anything is worse than none:
     the reader pays the space and gets no answer. */
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.rail-sub:hover { background: var(--v2-page); color: var(--v2-ink); }
.rail-sub:hover .rail-sub-mark { background: var(--v2-surface); }
.rail-sub:focus-visible { outline: 2px solid var(--v2-accent); outline-offset: -2px; }

/* The screen you are on, in the accent — the one selector, so the state
   cannot be half-applied. */
.rail-sub[data-active="true"] {
  background: var(--v2-accent-soft);
  border-left-color: var(--v2-accent);
  color: var(--v2-accent);
  font-weight: 700;
}
.rail-sub[data-active="true"] .rail-sub-name { color: var(--v2-accent); }
.rail-sub[data-active="true"] .rail-sub-mark {
  background: var(--v2-surface);
  color: var(--v2-accent);
}

/*
 * The shortcut, said once at the foot.
 *
 * On the panel rather than in a tooltip on the close button: a keyboard
 * shortcut nobody is told about is a shortcut nobody uses, and the place
 * to tell them is the thing it works on.
 */
.rail-panel-foot {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  border-top: 1px solid var(--v2-rule);
  font-size: 11.5px;
  color: var(--v2-ink-meta);
}
.rail-panel-foot kbd {
  min-width: 20px;
  padding: 1px 5px;
  border: 1px solid var(--v2-rule);
  border-bottom-width: 2px;
  border-radius: 5px;
  background: var(--v2-surface);
  font-family: var(--v2-mono);
  font-size: 11px;
  text-align: center;
  color: var(--v2-ink-soft);
}

/* Housekeeping's rules are grouped by the kind of record they are about.
   A flat list of twenty is a list nobody reads. */
.rail-panel-heading {
  margin: 10px 0 2px;
  padding: 0 10px;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--v2-ink-meta);
}
.rail-panel-heading:first-child,
.rail-panel-section:first-child .rail-panel-heading { margin-top: 0; }

/* One heading and the entries under it, as one group a screen reader names
   by the heading. Laid out as the body was, so the panel looks as it did. */
.rail-panel-section {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

/*
 * Put away.
 *
 * The pinned panel is 232px of nav on every screen, which somebody who
 * spends the day in one report would rather have as report. Shut, it
 * behaves exactly like every other group's: gone until the pointer or the
 * keyboard asks for it, and back for as long as it is being used. The
 * spacer gives its width back, so the page actually gets it.
 */
body[data-rail-panel="shut"] .rail-spacer[data-pinned="true"] {
  width: var(--v2-rail);
  min-width: var(--v2-rail);
}
body[data-rail-panel="shut"] .rail-panel[data-pinned="true"] {
  opacity: 0;
  visibility: hidden;
}
body[data-rail-panel="shut"] .rail-item:hover .rail-panel[data-pinned="true"],
body[data-rail-panel="shut"] .rail-item:focus-within .rail-panel[data-pinned="true"] {
  opacity: 1;
  visibility: visible;
}

/*
 * Narrow windows have no room for a rail, a panel and a page. The panel
 * covers the page there rather than squeezing it, and only on purpose —
 * a floating panel under a finger that is scrolling is not an opened menu.
 */
@media (max-width: 860px) {
  .rail-spacer[data-pinned="true"] {
    width: var(--v2-rail);
    min-width: var(--v2-rail);
  }
  .rail-panel[data-pinned="true"] { opacity: 0; visibility: hidden; }
  .rail-item:hover .rail-panel,
  .rail-item:focus-within .rail-panel { opacity: 1; visibility: visible; }
  /* On a phone the open rail and a full panel are wider than the screen.
     The panel takes what is left beside the rail, never more, so the
     Backlog's four headings scroll down inside it and nothing scrolls
     sideways. */
  .rail-panel { max-width: calc(100vw - var(--v2-rail)); }
  .rail:hover .rail-panel,
  .rail:focus-within .rail-panel { max-width: calc(100vw - var(--v2-rail-open)); }
}

/* The rail is chrome. Nothing of it belongs on a printed report. */
@media print {
  .rail, .rail-spacer, .rail-panel { display: none; }
}

/* ---------------------------------------------------------------------
   The tab bar

   Screens that are one subject seen several ways, so the rail carries one
   entry and they carry each other. Three bars use it: the business rules, the
   item validator, and every administrator's screen.

   Here rather than in a feature's own stylesheet, which is where it was. The
   settings bar went onto seven pages, four of which do not load that
   stylesheet, and the bar came out as a row of underlined blue links — a
   shared component styled in one feature's file is a component that only
   looks right where it started.
   ------------------------------------------------------------------ */

.sub-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
  border-bottom: 1px solid var(--v2-hairline);
  margin-bottom: -6px;
}
.sub-tab {
  padding: 8px 16px;
  font-size: 13px;
  font-weight: 600;
  color: var(--v2-ink-meta);
  text-decoration: none;
  white-space: nowrap;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.sub-tab:hover { color: var(--v2-ink); }
/* Marked with an attribute rather than a class, so the state is one selector
   and cannot be half-applied. */
.sub-tab[data-active="true"] {
  color: var(--v2-accent);
  border-bottom-color: var(--v2-accent);
  font-weight: 700;
}
.sub-tab:focus-visible { outline: 2px solid var(--v2-accent); outline-offset: -2px; }

/* ---------------------------------------------------------------------
   Two levels of it

   Fifteen settings in one row was a bar somebody read left to right looking
   for a word they half-remembered. The first row names the five areas and
   the second carries the screens inside the one you are in — so finding a
   setting is two choices rather than a scan.

   The two rows are told apart by shape, not only by position: a filled pill
   for the area, an underlined tab for the screen. Two rows of underlined
   tabs would have read as one bar that had wrapped.
   ------------------------------------------------------------------ */

.sub-levels { display: flex; flex-direction: column; }
.sub-nav-groups {
  border-bottom: 0;
  margin-bottom: 0;
  padding-bottom: 8px;
  gap: 4px;
}
.sub-nav-groups .sub-tab {
  padding: 5px 12px;
  margin-bottom: 0;
  border-bottom: 0;
  border-radius: var(--v2-radius-pill);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--v2-ink-mute);
}
.sub-nav-groups .sub-tab:hover { background: var(--v2-page); color: var(--v2-ink); }
.sub-nav-groups .sub-tab[data-active="true"] {
  background: var(--v2-ink);
  color: var(--c-neutral-100);
}

/* ---------------------------------------------------------------------
   The page header
   ------------------------------------------------------------------ */

.v2-header {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  background: var(--v2-surface);
  border: 1px solid var(--v2-hairline);
  border-radius: var(--v2-radius-lg);
  padding: 18px 24px;
  box-shadow: var(--v2-shadow-panel);
}

.v2-header-title {
  display: flex;
  align-items: center;
  gap: 14px;
  min-width: 280px;
}

.v2-header-mark {
  width: 44px;
  height: 44px;
  border-radius: 10px;
  background: var(--v2-accent-deep);
  display: grid;
  place-items: center;
  color: var(--c-neutral-100);
  font-weight: 800;
  font-size: 18px;
  flex-shrink: 0;
}

.v2-header-title h1 {
  margin: 0;
  font-weight: 800;
  font-size: 22px;
  line-height: 28px;
  color: var(--v2-ink);
}

.v2-header-title p {
  margin: 2px 0 0;
  font-size: 12px;
  line-height: 18px;
  font-weight: 500;
  color: var(--v2-ink-meta);
}

.v2-header-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.v2-who {
  font-size: 12px;
  font-weight: 500;
  color: var(--v2-ink-meta);
  white-space: nowrap;
}

.v2-btn {
  padding: 9px 16px;
  border-radius: var(--v2-radius);
  font-family: inherit;
  font-size: 13px;
  font-weight: 700;
  white-space: nowrap;
  cursor: pointer;
  text-decoration: none;
  border: 1px solid transparent;
}

.v2-btn-primary { background: var(--v2-accent); color: var(--c-neutral-100); border: none; }
.v2-btn-dark { background: var(--v2-ink); color: var(--c-neutral-100); border-color: var(--v2-ink-soft); }
.v2-btn-secondary { background: var(--v2-surface); color: var(--v2-ink-soft); border-color: var(--v2-rule); }
.v2-btn:focus-visible { outline: 2px solid var(--v2-accent); outline-offset: 2px; }
.v2-btn:disabled { opacity: .5; cursor: default; }
/* There but not invited: no fill and no border until it is pointed at. */
.v2-btn-ghost { background: transparent; color: var(--v2-ink-soft); border-color: transparent; }
.v2-btn-ghost:hover:not(:disabled) { background: var(--v2-band); color: var(--v2-ink); }

/* A button that carries an icon before its words. The icon sits on the
   text's own line rather than above it: a header button is read as one
   thing, and two lines of it is a card. */
.v2-btn-icon {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

/* ---------------------------------------------------------------------
   The notification bell (HELP-18)

   In the header's top right corner (Steven, 16 Oct 2026). A square button
   carrying the bell, the unread count as a badge on its corner, and the
   list in a popover under it, shadowed like the rail's palette menu.

   The bell is a child of the title row but placed against the header's
   right edge. With no top, an absolutely placed child of a flex row keeps
   the row's vertical centring, so it lines up with the title and the
   actions on one line, and stays on the title's line when the actions
   wrap under it. The header keeps the bell's width free on its right, so
   neither the title nor the actions run under it.
   ------------------------------------------------------------------ */
.v2-header:has(.nb:not([hidden])) { padding-right: calc(24px + 38px + 16px); }
.nb { position: absolute; right: 24px; }
.nb[hidden] { display: none; }
.nb-bell {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; padding: 0;
}
.nb-badge {
  position: absolute; top: -6px; right: -6px;
  min-width: 18px; height: 18px; padding: 0 5px;
  border-radius: 9px;
  background: var(--v2-accent); color: var(--c-neutral-100);
  font-size: 11px; font-weight: 700; line-height: 18px; text-align: center;
  font-variant-numeric: tabular-nums;
}
.nb-badge[hidden] { display: none; }
.nb-pop {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 70;
  width: min(380px, calc(100vw - 32px));
  max-height: min(520px, calc(100vh - 120px));
  display: flex; flex-direction: column;
  border: 1px solid var(--v2-hairline);
  border-radius: var(--v2-radius-lg);
  background: var(--v2-surface);
  box-shadow: var(--v2-shadow-rail);
  color: var(--v2-ink);
}
.nb-pop[hidden] { display: none; }
.nb-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding: 12px 14px 8px; border-bottom: 1px solid var(--v2-hairline);
}
.nb-title { margin: 0; font-size: 14px; font-weight: 700; }
.nb-body { overflow-y: auto; min-height: 0; }
.nb-list { list-style: none; margin: 0; padding: 4px 0; }
.nb-link {
  display: grid; grid-template-columns: 10px 1fr; column-gap: 8px; row-gap: 2px;
  padding: 9px 14px; color: var(--v2-ink-soft); text-decoration: none;
  font-size: 13px; line-height: 18px;
}
.nb-link:hover { background: var(--v2-band); }
.nb-link:focus-visible { outline: 2px solid var(--v2-accent); outline-offset: -2px; }
.nb-line { grid-column: 2; }
.nb-when { grid-column: 2; font-size: 11.5px; color: var(--v2-ink-meta); }
/* Unread: a dot and bold words, and a hidden "Unread" — never colour alone. */
.nb-dot { grid-column: 1; width: 8px; height: 8px; margin-top: 5px; border-radius: 50%; background: var(--v2-accent); }
.nb-item[data-read="false"] .nb-line { font-weight: 700; color: var(--v2-ink); }
/* A decision on the reader's own document (HELP-64): the word in a pill, and
   the administrator's message under the line, clipped to two lines. */
.nb-pill {
  display: inline-block; margin-right: 2px; padding: 0 7px;
  border-radius: var(--v2-radius-pill); border: 1px solid var(--v2-hairline);
  font-size: 11px; font-weight: 700; line-height: 17px; white-space: nowrap;
}
.nb-pill[data-decision="accept"] { background: var(--c-success-93a); color: var(--c-success-11); border-color: var(--c-success-83); }
.nb-pill[data-decision="sendback"] { background: var(--c-warn-97); color: var(--c-warn-21); border-color: var(--c-warn-47b); }
.nb-message {
  grid-column: 2; font-size: 12px; color: var(--v2-ink-soft);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  overflow-wrap: anywhere;
}
.nb-empty, .nb-problem { margin: 0; padding: 12px 14px; font-size: 13px; color: var(--v2-ink-meta); }
.nb-problem { color: var(--v2-ink); }
.nb-more { margin: 4px 14px 10px; }
.nb-textbtn {
  padding: 0; border: 0; background: none; font: inherit; font-size: 13px; font-weight: 600;
  color: var(--v2-accent); text-decoration: underline; text-underline-offset: 2px; cursor: pointer;
}
.nb-textbtn:disabled { color: var(--v2-ink-meta); text-decoration: none; cursor: default; }
.nb-textbtn:focus-visible { outline: 2px solid var(--v2-accent); outline-offset: 2px; border-radius: 2px; }
@media (forced-colors: active) {
  .nb-dot, .nb-badge { forced-color-adjust: none; background: CanvasText; color: Canvas; }
}

@media print {
  .v2-header-actions, .v2-header .nb { display: none; }
  .v2-header, .v2-header:has(.nb:not([hidden])) { border: none; box-shadow: none; padding: 0; }
}

/* ---------------------------------------------------------------------
   The atoms
   ------------------------------------------------------------------ */

.v2-pill {
  display: inline-flex;
  align-items: center;
  font-size: 10px;
  font-weight: 700;
  color: var(--c-neutral-00);
  background: var(--v2-surface);
  border: 1px solid var(--c-neutral-00);
  border-radius: var(--v2-radius-pill);
  padding: 2px 9px;
  white-space: nowrap;
}

.v2-id {
  display: inline-flex;
  align-items: center;
  font-family: var(--v2-mono);
  font-size: 10px;
  font-weight: 700;
  color: var(--c-neutral-100);
  background: var(--c-neutral-00);
  border-radius: var(--v2-radius-pill);
  padding: 2px 9px;
  white-space: nowrap;
}

/* Said, not shown. An icon is never the only label — see icons.js — and a
   relationship drawn as an elbow has to be a word for anybody reading the
   page rather than looking at it. */
.v2-sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.v2-title {
  font-weight: 700;
  font-size: 15px;
  line-height: 21px;
  text-wrap: pretty;
  color: var(--c-neutral-00);
}

.v2-kpi { display: flex; flex-direction: column; gap: 1px; }

.v2-kpi span {
  font-size: 9px;
  font-weight: 700;
  color: var(--v2-ink-mute);
  text-transform: uppercase;
}

.v2-kpi strong { font-size: 12px; color: var(--v2-ink-soft); font-weight: 700; }

.v2-team {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  width: 36px;
  flex-shrink: 0;
}

.v2-team-swatch {
  width: 18px;
  height: 18px;
  border-radius: 4px;
  border: 1px solid var(--v2-rule);
  flex-shrink: 0;
}

.v2-team-hours {
  font-family: var(--v2-mono);
  font-size: 10px;
  font-weight: 700;
  color: var(--v2-ink-soft);
  white-space: nowrap;
}

.v2-team-short {
  font-size: 8px;
  font-weight: 700;
  color: var(--v2-ink-mute);
  text-transform: uppercase;
  white-space: nowrap;
  max-width: 36px;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ---------------------------------------------------------------------
   The page beside the rail
   ------------------------------------------------------------------ */

/*
 * Applied to <body>: the page ground, and nothing else.
 *
 * The frame's layout deliberately does not live here. A body is not only the
 * frame — it also holds the sign-in gate and the toast — so laying the body
 * out as a row makes those two siblings of the rail and squeezes the page
 * into whatever is left. The row belongs to the element that actually holds
 * the rail and the main column.
 */
.v2-shell { background: var(--v2-page); }

/* The row: the rail spacer, then the page. */
.v2-frame {
  display: flex;
  align-items: flex-start;
  min-height: 100vh;
}

.v2-main {
  flex: 1;
  min-width: 0;
  /* Room at the foot for the Report button, which is fixed in the corner and
     was sitting over the last row of whatever page you were on. */
  padding: 24px 24px var(--v2-fab-clear);
  display: flex;
  flex-direction: column;
  gap: var(--v2-stack-gap);
}

@media print {
  .v2-frame { display: block; }
  .v2-main { padding: 0; }
}

/* ---------------------------------------------------------------------
   The freshness banner

   Deliberately large, and above everything on the front door. What it says is
   invisible otherwise — every page reads Firestore, Firestore is filled by a
   nightly job, and nothing talks to Airfocus while you are looking at it — and
   an invisible cache is one people trust as live.
   ------------------------------------------------------------------ */

.sync-banner {
  display: flex;
  align-items: flex-start;
  gap: 16px;
  padding: 18px 22px;
  border-radius: var(--v2-radius-lg);
  border: 1px solid var(--v2-hairline);
  background: var(--v2-surface);
  box-shadow: var(--v2-shadow-panel);
}

.sync-banner-mark { font-size: 24px; line-height: 1.2; flex-shrink: 0; }
.sync-banner-body { flex: 1; min-width: 0; }

.sync-banner-headline {
  margin: 0;
  font-size: 17px;
  font-weight: 700;
  color: var(--v2-ink);
  letter-spacing: -.01em;
}
.sync-banner-detail {
  margin: 5px 0 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--v2-ink-soft);
  max-width: 78ch;
}

/* Fresh is still a warning — the data is a copy either way — so it is stated
   plainly rather than coloured green. Green would say "all correct", and the
   whole point of the sentence is that it is not live. */
.sync-banner[data-level="fresh"] { border-left: 4px solid var(--v2-level-2); }
.sync-banner[data-level="unknown"] { border-left: 4px solid var(--v2-rule); }
.sync-banner[data-level="stale"],
.sync-banner[data-level="partial"] {
  border-left: 4px solid var(--v2-level-3);
  background: var(--c-warn-97);
}
.sync-banner[data-level="very-stale"],
.sync-banner[data-level="failed"] {
  border-left: 4px solid var(--v2-accent);
  background: var(--v2-warn-row);
}

/* The write-back state, on the same banner: it answers the same question —
   how much does this correspond to Airfocus right now. */
.sync-write {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin-top: 12px;
  padding: 4px 12px 4px 9px;
  border-radius: var(--v2-radius-pill);
  border: 1px solid var(--v2-hairline);
  background: var(--v2-band);
  font-size: 12px;
  font-weight: 700;
  color: var(--v2-ink-soft);
  cursor: help;
}
.sync-write-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--v2-ink-mute);
}
.sync-write[data-on="true"] .sync-write-dot { background: var(--v2-accent); }
.sync-write[data-on="true"] { border-color: var(--v2-accent); color: var(--v2-accent); }

@media print { .sync-banner { break-inside: avoid; } }

/* ---------------------------------------------------------------------
   The minimap

   Where you are in a drawing bigger than the window. A scrollbar says how far
   along you are on one axis; it does not say the shape of what you are inside,
   and on a wide graph that is the only question worth answering.

   Shared by the object explorer and the flowchart canvas, so it lives here
   rather than in either page's sheet.
   ------------------------------------------------------------------ */

.minimap {
  position: absolute;
  top: 56px;
  right: 12px;
  width: 140px;
  height: 100px;
  z-index: 6;
  background: var(--v2-surface, var(--c-neutral-100));
  border: 1px solid var(--v2-hairline, var(--c-neutral-91));
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(17, 24, 39, .12);
  overflow: hidden;
  cursor: crosshair;
  /* Not a scroll target and not a tab stop: it is a picture you point at. */
  user-select: none;
  touch-action: none;
}
.minimap-marks { position: absolute; inset: 0; }

/* Colour-coded by what a node is, so the minimap reads as the same graph
   rather than as a grey blur. */
.minimap-node { position: absolute; border-radius: 1px; }

/*
 * What is on screen. Outlined rather than filled solid, so the nodes under it
 * stay readable — the point is seeing where you are *among* them.
 */
.minimap-view {
  position: absolute;
  border: 1.5px solid var(--v2-accent, var(--c-accent-49a));
  background: rgba(250, 0, 0, .10);
  border-radius: 2px;
  pointer-events: none;
}

@media print { .minimap { display: none; } }

/* ---------------------------------------------------------------------
   The Claude notice

   Three features spend Anthropic credits and none of them said so anywhere a
   person about to press would look. One notice, on all three, in the same
   place — and one that can be put away, because a warning that cannot be
   dismissed is one people learn to look past, which is worse than one they
   dismissed on purpose.

   Put away it is the mark alone, still clickable, so the fact that Claude is
   involved never disappears entirely — only the paragraph does.
   ------------------------------------------------------------------ */

.claude-notice {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 14px 16px;
  margin-bottom: 16px;
  background: var(--c-brand-98);
  border: 1px solid var(--c-brand-89);
  border-radius: var(--v2-radius-lg);
}

/* Put away: the mark and nothing else, sitting where the notice was rather
   than reflowing the page around its absence. */
.claude-notice[data-away="true"] {
  padding: 6px;
  background: none;
  border-color: transparent;
  margin-bottom: 8px;
}

.claude-mark {
  flex: none;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 10px 5px 8px;
  border: 1px solid var(--c-brand-83);
  border-radius: var(--v2-radius-pill);
  background: var(--c-neutral-100);
  color: var(--c-brand-50);
  font: inherit; font-size: 11px; font-weight: 800; letter-spacing: .02em;
  cursor: pointer;
}
.claude-mark:hover { border-color: var(--c-brand-50); }
.claude-mark:focus-visible { outline: 2px solid var(--c-brand-50); outline-offset: 2px; }

.claude-notice-body { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.claude-notice-title { margin: 0; font-size: 13px; font-weight: 800; color: var(--v2-ink); }
.claude-notice-text {
  margin: 0; font-size: 12px; line-height: 18px; color: var(--v2-ink-soft); max-width: 78ch;
}
.claude-notice-actions { display: flex; align-items: center; gap: 12px; margin-top: 4px; }
.claude-notice-link { font-size: 12px; font-weight: 700; color: var(--c-brand-50); }
.claude-notice-dismiss { padding: 4px 10px; font-size: 12px; }

/* =====================================================================
   What you are looking at — the badge and its panel

   In shell.css rather than in a page's stylesheet because two pages carry it
   and a component styled beside one of them is a component that renders as
   blue underlined text on the other. That has already happened once here, with
   the settings tab bar.
   ===================================================================== */

.scope-badge {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 6px 12px 6px 8px; border-radius: 999px;
  background: var(--v2-surface); border: 1px solid var(--v2-rule);
  font: inherit; font-size: 12px; font-weight: 600; color: var(--v2-ink-soft);
  cursor: pointer;
}
.scope-badge:hover { border-color: var(--v2-ink-soft); color: var(--v2-ink); }
.scope-badge[data-open="true"] { border-color: var(--v2-ink); color: var(--v2-ink); }

.scope-badge-mark {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--v2-ink); color: var(--c-neutral-100);
  font-size: 11px; font-weight: 800; font-style: italic; line-height: 1;
}
/* The warning badge is its own control, drawn only when there is something to
   warn about — so its presence is the signal, and the badge beside it goes on
   saying the thing it is named after. A count as well as a tint: a colour
   alone is unreadable to anybody who cannot tell the two apart. */
.scope-badge-warn { border-color: var(--v2-accent); color: var(--v2-accent); }
.scope-badge-warn .scope-badge-mark { background: var(--v2-accent); }
.scope-badge-warn:hover { border-color: var(--v2-accent); color: var(--v2-accent); }
.scope-badge-count {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px;
  background: var(--v2-accent); color: var(--c-neutral-100); font-size: 11px; font-weight: 800;
}

.scope-panel {
  position: fixed; top: 0; right: 0; bottom: 0; width: 380px; max-width: 92vw;
  z-index: 30; overflow-y: auto;
  display: flex; flex-direction: column; gap: 10px; padding: 20px;
  background: var(--v2-surface); border-left: 1px solid var(--v2-hairline);
  box-shadow: -8px 0 24px rgba(0, 0, 0, .10);
}
/* Docked, not modal: the main column gives up the width instead of being
   covered, so the charts stay readable with the panel open — which is the
   whole point of a panel that explains them. */
.v2-shell[data-scope="open"] .v2-main { padding-right: 396px; }

.scope-panel-head { display: flex; align-items: center; justify-content: space-between; }
.scope-panel-title { margin: 0; font-weight: 800; font-size: 15px; color: var(--v2-ink); }
.scope-panel-close {
  background: none; border: 0; font-size: 20px; line-height: 1; cursor: pointer;
  color: var(--v2-ink-soft); padding: 0 4px;
}
.scope-panel-close:hover { color: var(--v2-ink); }

.scope-panel-subtitle {
  margin: 0; font-size: 12.5px; font-weight: 700; color: var(--v2-ink);
}
.scope-panel-text {
  margin: 0; font-size: 12.5px; line-height: 19px; color: var(--v2-ink-soft);
}

.scope-facts { margin: 6px 0 0; display: grid; grid-template-columns: 1fr; gap: 0; }
.scope-facts dt {
  font-size: 10px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--v2-ink-soft); margin-top: 8px;
}
.scope-facts dd {
  margin: 2px 0 0; font-size: 12.5px; font-weight: 600; color: var(--v2-ink);
}

.scope-warn-head {
  margin: 14px 0 0; padding-top: 12px; border-top: 1px solid var(--v2-rule);
  font-size: 12px; font-weight: 800; color: var(--v2-accent);
}
.scope-warnings { margin: 6px 0 0; padding-left: 18px; }
.scope-warnings li {
  margin-bottom: 6px; font-size: 12px; line-height: 18px; color: var(--v2-ink);
}
.scope-panel-note {
  margin: 12px 0 0; padding: 8px 10px; border-radius: 6px;
  background: var(--paper); border: 1px solid var(--v2-rule);
  font-size: 12px; line-height: 18px; color: var(--v2-ink);
}

@media (max-width: 900px) {
  .v2-shell[data-scope="open"] .v2-main { padding-right: 0; }
}

/* The panel leads with whichever badge opened it: arriving from "Data
   warnings" at a paragraph about hour fields is arriving in the wrong place. */
.scope-panel[data-lead="warnings"] .scope-warn-head { order: -1; margin-top: 0; border-top: 0; }
.scope-panel[data-lead="warnings"] .scope-warnings { order: -1; }
.scope-panel[data-lead="warnings"] { display: flex; flex-direction: column; }

/* Neither belongs in a print-out: the badges are controls and the panel is a
   drawer. What they say is worth printing, so the panel prints as a block at
   the top of the page instead. */
@media print {
  .scope-badge { display: none; }
  .scope-panel {
    position: static; width: auto; max-width: none; border: 0; box-shadow: none;
    padding: 0 0 16px;
  }
  .scope-panel-close { display: none; }
}

/* =====================================================================
   The Reporting components — Chart Panel, Data Panel, Reporting Panel.

   From the design handoff, rebuilt as lib/chart-panel.js, lib/data-panel.js
   and lib/reporting-panel.js. Styled here rather than in the report's own
   stylesheet because they are shared components: one styled in a feature's
   stylesheet stops working the day a second page mounts it.

   The layout the handoff draws: a chart panel with a shadow falling to its
   right, and a table that emerges from behind it — a negative left margin,
   the chart's corners squared off on that side, and the chart stacked above.
   ===================================================================== */

/*
 * The panel is the container, not the row inside it.
 *
 * A container query styles a container's *descendants*, never the container
 * itself — so `container-type` on `.rp-row` with rules that set
 * `.rp-row { flex-direction: column }` did exactly nothing, and a 457px
 * half-width panel went on trying to hold a chart and a table side by side.
 */
.rp-panel {
  padding: 18px 20px;
  container-type: inline-size;
  container-name: rp-panel;
}
.rp-title { margin: 0 0 4px; }
.rp-note { margin: 0 0 12px; font-size: 12px; color: var(--v2-ink-soft); }
/*
 * A container, not the viewport.
 *
 * These panels sit in a two-column grid, so a half-width one on a wide screen
 * is a 700px row being asked to hold a chart and a table side by side. What
 * decides whether they fit is the row's own width, which is what a container
 * query asks and a media query cannot.
 */
.rp-row { display: flex; align-items: stretch; width: 100%; min-height: 0; }
.rp-slot { min-width: 0; display: flex; transition: flex-basis .15s ease; }
.rp-slot > * { width: 100%; }

/* ---------- the chart half ---------- */

.cp-panel {
  background: var(--v2-surface);
  border: 1px solid var(--v2-rule);
  border-radius: var(--v2-radius-lg, 12px);
  padding: 16px 18px;
  /* The shadow falls to the right, onto the table. That is what makes the
     table read as behind the chart rather than beside it. */
  box-shadow: 4px 0 10px 0 rgba(0, 0, 0, .10);
  position: relative;
  z-index: 2;
  box-sizing: border-box;
  width: 100%;
}
.cp-panel[data-square="true"] { border-radius: var(--v2-radius-lg, 12px) 0 0 var(--v2-radius-lg, 12px); }
.cp-panel[data-collapsed="true"] { padding: 18px 0; }

.cp-toolbar { display: flex; justify-content: flex-end; gap: 6px; margin-bottom: 6px; }
.cp-tool {
  display: flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; flex: none;
  border-radius: var(--v2-radius-sm, 6px);
  background: transparent; border: 1px solid var(--v2-rule);
  color: var(--v2-ink-mute); cursor: pointer;
  font: 700 14px/1 var(--v2-font, inherit);
}
.cp-tool:hover { border-color: var(--v2-ink-soft); color: var(--v2-ink); }
.cp-tool[data-on="true"] {
  background: rgba(168, 132, 46, .12);
  border-color: var(--c-brand-42);
  color: var(--c-brand-42);
}

/* The collapsed strip. A rotated word rather than an icon alone: sixty-four
   pixels of grey with a chevron in it is not a label. */
.cp-strip, .dp-strip {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 12px; width: 100%; min-height: 200px; height: 100%;
  background: none; border: 0; cursor: pointer; color: var(--v2-ink-mute);
}
.cp-strip-label, .dp-strip-label {
  writing-mode: vertical-rl; transform: rotate(180deg);
  font: 700 10px/14px var(--v2-font, inherit); letter-spacing: .12em;
}
.cp-strip-mark, .dp-strip-mark { font: 700 15px/1 var(--v2-font, inherit); }
.cp-strip:hover, .dp-strip:hover { color: var(--v2-ink); }

/* The table beside it decides the row's height, so a short chart would sit at
   the top of a tall panel with a hand's width of nothing under it. */
.cp-panel { display: flex; flex-direction: column; }
.cp-panel[data-collapsed="true"] { display: block; }
.cp-body { min-height: 0; flex: 1; display: flex; flex-direction: column; justify-content: center; }
.cp-empty { margin: 24px 0; color: var(--v2-ink-mute); font-size: 13px; text-align: center; }
.cp-hint { margin: 10px 0 0; font-size: 11px; color: var(--v2-ink-mute); }

/* ---------- the donut ---------- */

.cp-donut-wrap { display: flex; align-items: center; justify-content: center; gap: 24px; flex-wrap: wrap; }
.cp-donut { position: relative; width: 230px; height: 230px; flex: none; }
.cp-donut svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.cp-arc { cursor: pointer; transition: opacity .15s ease; }
/* `inset` is set inline, from HOLE_INSET in lib/chart-panel.js: the hole has
   to land exactly on the inner ring's inner edge, and a number typed here as
   well as there is a number that ends up covering the ring. */
.cp-hole {
  position: absolute; border-radius: 50%;
  background: var(--v2-surface); pointer-events: none;
}
.cp-centre {
  position: absolute; border-radius: 50%;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  background: var(--v2-surface); border: 0; cursor: pointer; gap: 2px;
}
/* Drilled, the hole carries the pie, so the readable centre shrinks and gets
   its own edge — otherwise the number sits on top of four coloured wedges. */
.cp-centre[data-pie="true"] { box-shadow: 0 0 0 1px var(--v2-rule); }
.cp-centre-value { font: 800 15px/20px var(--v2-font, inherit); color: var(--v2-ink); }
.cp-centre-sub { font: 600 10px/14px var(--v2-font, inherit); color: var(--v2-ink-mute); }

.cp-legend { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.cp-legend-row {
  display: flex; align-items: center; gap: 8px; min-width: 0;
  background: none; border: 0; padding: 0; text-align: left;
}
.cp-legend-button { cursor: pointer; }
.cp-legend-button:hover .cp-legend-label { color: var(--v2-ink); text-decoration: underline; }
.cp-legend-label { font: 600 13px/18px var(--v2-font, inherit); color: var(--v2-ink); }
.cp-legend-value { font: 700 13px/18px var(--v2-font, inherit); color: var(--v2-ink-soft); }
.cp-swatch {
  display: inline-block; width: 10px; height: 10px; border-radius: 3px; flex: none;
}
.cp-swatch-dual { width: 11px; height: 11px; }

/* ---------- the bars ---------- */

.cp-bars { display: flex; flex-direction: column; gap: 12px; }
.cp-bar {
  display: block; width: 100%; background: none; border: 0; padding: 0; text-align: left;
}
.cp-bar-button { cursor: pointer; }
.cp-bar-head { display: flex; justify-content: space-between; gap: 12px; margin-bottom: 4px; }
.cp-bar-label { font: 600 13px/18px var(--v2-font, inherit); color: var(--v2-ink); }
.cp-bar-value { font: 700 13px/18px var(--v2-font, inherit); color: var(--v2-ink-soft); }
.cp-bar-track { width: 100%; background: var(--v2-rule); border-radius: 4px; }
.cp-bar-fill { height: 22px; border-radius: 4px; }
.cp-bar-stack { height: 22px; border-radius: 4px; overflow: hidden; display: flex; }
.cp-bar-seg { display: block; min-width: 1px; }
.cp-row-legend, .cp-shared-legend, .cp-column-legend {
  display: flex; flex-wrap: wrap; gap: 10px; margin-top: 5px;
}
.cp-shared-legend { margin: 0 0 12px; }
.cp-legend-chip {
  display: inline-flex; align-items: center; gap: 5px;
  font: 500 11px/15px var(--v2-font, inherit); color: var(--v2-ink-soft);
}
.cp-back {
  background: none; border: 0; padding: 0; margin-bottom: 10px; cursor: pointer;
  font: 700 12px/16px var(--v2-font, inherit); color: var(--c-brand-42);
}

/* ---------- the columns ---------- */

.cp-stack-plot { position: relative; padding: 0 4px 0 46px; }
.cp-grid-line { position: absolute; left: 46px; right: 4px; height: 1px; background: var(--v2-rule); }
.cp-grid-label {
  position: absolute; left: 0; width: 38px; text-align: right;
  font: 600 10px/12px var(--v2-font, inherit); color: var(--v2-ink-mute); white-space: nowrap;
}
.cp-columns { position: relative; z-index: 1; display: flex; align-items: flex-end; gap: 16px; height: 100%; }
.cp-column { flex: 1; display: flex; align-items: flex-end; justify-content: center; height: 100%; }
.cp-column-bar {
  width: 100%; max-width: 64px; display: flex; flex-direction: column-reverse;
  border-radius: 4px; overflow: hidden;
}
.cp-column-seg { display: block; min-height: 1px; }
.cp-column-feet { display: flex; gap: 16px; padding: 0 4px 0 46px; margin-top: 8px; }
.cp-column-foot { flex: 1; min-width: 0; }
.cp-column-label { display: block; font: 600 12px/16px var(--v2-font, inherit); color: var(--v2-ink); }
.cp-column-value { display: block; font: 700 11px/16px var(--v2-font, inherit); color: var(--v2-ink-soft); }
.cp-column-legend { flex-direction: column; gap: 3px; }

/* ---------- the table half ---------- */

.dp-panel {
  border: 1px solid var(--v2-rule);
  border-radius: var(--v2-radius-lg, 12px);
  padding: 18px 20px 18px 34px;
  /* Pulled left, under the chart's shadow. This is what "emerges from behind"
     is made of; without it the two are simply two panels in a row. */
  margin-left: -20px;
  position: relative;
  z-index: 1;
  background: var(--paper);
  box-sizing: border-box;
  width: 100%;
  overflow: hidden;
}
.dp-panel[data-collapsed="true"] { padding: 18px 0 18px 10px; }
.dp-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 10px; }
.dp-title {
  margin: 0; font: 700 10px/16px var(--v2-font, inherit); letter-spacing: .06em;
  color: var(--v2-ink-mute); text-transform: uppercase;
}
.dp-fold {
  display: flex; align-items: center; justify-content: center; width: 24px; height: 24px;
  background: none; border: 0; cursor: pointer; color: var(--v2-ink-mute);
  font: 700 15px/1 var(--v2-font, inherit); flex: none;
}
.dp-fold:hover { color: var(--v2-ink); }
.dp-table-wrap { overflow-x: auto; }
/*
 * Never narrower than its own content needs.
 *
 * Without this the panel's `overflow: hidden` cut "2,692" down to "2,69" and
 * the heading "HOURS" to "HOUR": `width: 100%` let the browser squeeze the
 * numeric columns below what they hold, and the overflow was clipped rather
 * than scrolled. `min-content` is the width at which every cell is as narrow
 * as it can be — labels wrapped as far as they go, numbers whole — so the
 * wrap scrolls instead, and a figure missing its last digit is worse than a
 * figure you have to scroll to.
 */
.dp-table { width: max-content; min-width: 100%; border-collapse: collapse; }
.dp-table th {
  font: 700 10px/16px var(--v2-font, inherit); letter-spacing: .05em;
  color: var(--v2-ink-mute); text-transform: uppercase;
  padding: 0 14px 8px 0; border-bottom: 1px solid var(--v2-rule);
}
.dp-table td {
  padding: 7px 14px 7px 0; border-bottom: 1px solid var(--paper);
  font: 500 12.5px/18px var(--v2-font, inherit); color: var(--v2-ink-soft);
  font-variant-numeric: tabular-nums;
}
/* A child row, indented under its parent. A leading space in the cell text
   would be collapsed by the browser and would need `white-space: pre` to
   survive, which then breaks every long label in the table. */
.dp-table td[data-indent="true"] { padding-left: 14px; }
.dp-table th[data-align="right"], .dp-table td[data-align="right"] {
  text-align: right;
  /* Numbers never wrap: "1,182" broken across two lines is two numbers. The
     label column is the one that gives, which is why it is the only one left
     free to wrap. */
  white-space: nowrap;
}
.dp-table th:last-child, .dp-table td:last-child { padding-right: 0; }
.dp-table tr[data-bold="true"] td { font-weight: 700; color: var(--v2-ink); }
.dp-table tr[data-compact="true"] td { padding-top: 5px; padding-bottom: 5px; }
/* A total that looks like another row is a total somebody adds to the rows. */
.dp-table tr[data-total="true"] td {
  border-bottom: 0; padding-top: 9px;
  font: 800 13px/18px var(--v2-font, inherit); color: var(--v2-ink);
}
.dp-empty { color: var(--v2-ink-mute); font-style: italic; }

/* ---------- a panel around something these components cannot draw ---------- */

.rp-custom-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.rp-custom-head .rp-title { flex: 1; min-width: 0; }
.rp-custom-actions { display: flex; gap: 8px; }
.rp-custom-body { margin-top: 10px; }

/* Below the width where a chart and a table side by side are both unreadable,
   they stack. The collapse controls stay — in a narrow panel folding the
   table away is worth more, not less. */
/*
 * 950, not 700.
 *
 * A half-width panel in the two-column grid is ~900px on a wide screen, and
 * at a 60/40 split that leaves the table under 300px for three columns —
 * enough to make "2,692" scroll off the side, which is a worse table than a
 * stacked one. Below this the chart takes the width and the numbers sit under
 * it; above it — the full-width panels — they stay side by side, which is
 * what the layout is for.
 */
@container rp-panel (max-width: 950px) {
  .rp-row { flex-direction: column; }
  .rp-slot { flex-basis: auto !important; }
  .cp-panel, .cp-panel[data-square="true"] { border-radius: var(--v2-radius-lg, 12px); }
  .dp-panel { margin-left: 0; margin-top: 10px; padding-left: 20px; }
  /* Stacked, a collapsed half is a band across the panel rather than a tall
     strip beside it. Kept low and laid horizontally so it reads as a fold —
     a 200px grey column with a rotated word in it looks like a panel that
     failed to draw. */
  .cp-panel[data-collapsed="true"], .dp-panel[data-collapsed="true"] { padding: 0; }
  .cp-panel[data-collapsed="true"] .cp-strip,
  .dp-panel[data-collapsed="true"] .dp-strip {
    min-height: 0; height: 32px; flex-direction: row; gap: 8px;
  }
  .cp-strip-label, .dp-strip-label { writing-mode: horizontal-tb; transform: none; }
  .cp-strip-mark, .dp-strip-mark { transform: rotate(90deg); }
}
/* The same, for a browser with no container queries: a narrow window is the
   case that would otherwise be unreadable rather than merely cramped. */
@media (max-width: 860px) {
  .rp-row { flex-direction: column; }
  .rp-slot { flex-basis: auto !important; }
  .cp-panel, .cp-panel[data-square="true"] { border-radius: var(--v2-radius-lg, 12px); }
  .dp-panel { margin-left: 0; margin-top: 10px; padding-left: 20px; }
}

/*
 * A donut in half a row has no width for a legend beside it, so the legend
 * goes underneath — `flex-wrap` on the wrap does that already; this keeps it
 * centred rather than left against the ring.
 */
@container rp-panel (max-width: 560px) {
  .cp-donut-wrap { flex-direction: column; }
  .cp-legend { align-items: flex-start; }
}

/* =====================================================================
   Which of the two general reports you are reading.

   Two of the report bar's tabs are the same report twice while the rebuilt
   one is being judged. At opposite ends of a nine-tab bar they read as
   siblings rather than as alternatives, which is the one thing somebody
   comparing them needs to see — so a two-position switch says it plainly.
   ===================================================================== */

.report-bar-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
}
.report-bar-row .sub-nav { flex: 1; min-width: 0; }

.report-switch { display: inline-flex; align-items: center; gap: 8px; flex: none; }
.report-switch-label {
  font: 700 10px/16px var(--v2-font, inherit); letter-spacing: .06em;
  text-transform: uppercase; color: var(--v2-ink-mute);
}
.report-switch-group {
  display: inline-flex; padding: 2px;
  background: var(--paper); border: 1px solid var(--v2-rule);
  border-radius: var(--v2-radius-pill, 999px);
}
.report-switch-option {
  padding: 4px 12px; border-radius: var(--v2-radius-pill, 999px);
  font: 700 12px/16px var(--v2-font, inherit);
  color: var(--v2-ink-mute); text-decoration: none; white-space: nowrap;
}
.report-switch-option:hover { color: var(--v2-ink); }
/* The one you are on carries the fill, so which half is live is readable
   without comparing two greys. */
.report-switch-option[data-active="true"] {
  background: var(--v2-surface); color: var(--v2-ink);
  box-shadow: 0 1px 2px rgba(0, 0, 0, .12);
}

/* A control, not content: a print-out of one report should not carry a link
   to the other. */
@media print { .report-switch { display: none; } }

/* =====================================================================
   The Report button, and its chat panel

   On every page — session.js mounts it once a session opens — so it is styled
   here beside the other shared components. Bottom right, where every
   application people already know puts the "tell us" control.
   ===================================================================== */

.fab { position: fixed; right: 22px; bottom: 22px; z-index: 60; }

.fab-button {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 16px; border: 0; cursor: pointer;
  border-radius: var(--v2-radius-pill);
  background-image: var(--v2-accent-gradient);
  background-color: var(--v2-accent);
  color: var(--c-neutral-100); font: inherit; font-size: 13px; font-weight: 700;
  box-shadow: 0 6px 18px rgba(17, 24, 39, .22);
}
.fab-button:hover { filter: brightness(1.06); }
.fab-button:focus-visible { outline: 2px solid var(--v2-ink); outline-offset: 2px; }
.fab-mark {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; border-radius: 50%;
  background: rgba(255, 255, 255, .22); font-size: 12px;
}

.fab-panel {
  position: absolute; right: 0; bottom: 52px;
  width: min(380px, calc(100vw - 44px));
  display: flex; flex-direction: column;
  background: var(--v2-surface); color: var(--v2-ink);
  border: 1px solid var(--v2-hairline);
  border-radius: var(--v2-radius-lg);
  box-shadow: 0 18px 48px rgba(17, 24, 39, .22);
  overflow: hidden;
}

.fab-head {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 14px; border-bottom: 1px solid var(--v2-hairline);
}
.fab-title { font-weight: 700; font-size: 14px; flex: 1; }
.fab-mine { font-size: 12px; color: var(--v2-accent); font-weight: 600; }
.fab-close {
  border: 0; background: none; cursor: pointer; font-size: 18px;
  color: var(--v2-ink-mute); padding: 0 4px; line-height: 1;
}
.fab-close:hover { color: var(--v2-ink); }

/* The conversation. Capped, so a long bug description scrolls inside the
   panel rather than growing it past the top of the window. */
.fab-thread {
  display: flex; flex-direction: column; gap: 8px;
  padding: 14px; max-height: min(420px, 60vh); overflow: auto;
}
.fab-say {
  margin: 0; align-self: flex-start; max-width: 85%;
  background: var(--v2-band); border-radius: 12px 12px 12px 4px;
  padding: 8px 12px; font-size: 12.5px; line-height: 1.5;
}
.fab-said {
  margin: 0; align-self: flex-end; max-width: 85%;
  background: var(--v2-accent); color: var(--c-neutral-100);
  border-radius: 12px 12px 4px 12px;
  padding: 8px 12px; font-size: 12.5px; line-height: 1.5;
  white-space: pre-wrap; overflow-wrap: anywhere;
}

.fab-choices { display: flex; flex-direction: column; gap: 6px; }
.fab-choice {
  display: flex; flex-direction: column; gap: 2px; text-align: left;
  border: 1px solid var(--v2-hairline); border-radius: var(--v2-radius);
  background: var(--v2-surface); cursor: pointer; font: inherit;
  padding: 9px 12px; color: inherit;
}
.fab-choice:hover { border-color: var(--v2-accent); }
.fab-choice-label { font-size: 13px; font-weight: 700; }
.fab-choice-blurb { font-size: 11.5px; color: var(--v2-ink-soft); }

.fab-input { display: flex; flex-direction: column; gap: 6px; }
.fab-input textarea {
  font: inherit; font-size: 12.5px; padding: 8px 10px;
  border: 1px solid var(--v2-hairline); border-radius: var(--v2-radius);
  background: var(--v2-surface); color: var(--v2-ink); resize: vertical;
}
.fab-next { align-self: flex-end; }

/* The context the send carries, said before it is sent: nothing leaves the
   browser that the person pressing Send has not seen. */
.fab-context {
  margin: 0; display: grid; grid-template-columns: max-content 1fr; gap: 2px 12px;
  font-size: 11px; color: var(--v2-ink-soft);
  background: var(--v2-page); border-radius: var(--v2-radius); padding: 9px 11px;
}
.fab-context dt { font-weight: 700; }
.fab-context dd { margin: 0; overflow-wrap: anywhere; }

/* The pages you came through, one per line, so the steps to reproduce can be
   read — and the report corrected — before anything is sent. */
.fab-trail-title { margin: 10px 0 2px; font-size: 12px; font-weight: 700; }
.fab-trail { margin: 0; padding-left: 20px; font-size: 12px; }
.fab-trail li { overflow-wrap: anywhere; }

.fab-actions { display: flex; align-items: center; gap: 10px; }
.fab-status { font-size: 11.5px; color: var(--v2-warn, var(--c-danger-42)); }

@media print { .fab { display: none; } }

/* Attachments on the Report panel: two quiet buttons, the files as rows. */
.fab-files { margin: 6px 0; }
.fab-file-buttons { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.fab-file-list { margin-top: 6px; display: flex; flex-direction: column; gap: 4px; }
.fab-file {
  display: flex; align-items: center; gap: 8px;
  font-size: 12px; padding: 4px 8px;
  background: var(--v2-band); border: 1px solid var(--v2-hairline);
  border-radius: var(--v2-radius);
}
.fab-file-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fab-file-size { flex: none; color: var(--v2-ink-meta); }
.fab-file-drop {
  flex: none; margin-left: auto; border: 0; background: none; cursor: pointer;
  font-size: 14px; line-height: 1; color: var(--v2-ink-meta); padding: 2px 4px;
}
.fab-file-drop:hover { color: var(--v2-accent); }
.fab-file-note { margin: 4px 0 0; font-size: 11px; color: var(--v2-ink-meta); }

/* The route through a report, named before it is walked: describe, then
   screenshot & files, then send. The current step carries the accent; the
   walked ones fade. */
.fab-steps {
  display: flex; align-items: center; gap: 4px;
  list-style: none; margin: 0; padding: 8px 14px 0;
  counter-reset: fab-step;
}
.fab-step {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11px; font-weight: 600; color: var(--v2-ink-mute);
  counter-increment: fab-step;
}
.fab-step::before {
  content: counter(fab-step);
  display: grid; place-items: center;
  width: 16px; height: 16px; border-radius: 50%;
  font-size: 10px; font-weight: 700;
  background: var(--v2-band); color: var(--v2-ink-meta);
  border: 1px solid var(--v2-hairline);
}
.fab-step:not(:last-child)::after {
  content: ''; width: 12px; height: 1px;
  background: var(--v2-hairline); margin-left: 4px;
}
.fab-step[data-on="true"] { color: var(--v2-ink); }
.fab-step[data-on="true"]::before {
  background-image: var(--v2-accent-gradient); border-color: transparent; color: var(--c-neutral-100);
}
.fab-step[data-done="true"] { color: var(--v2-ink-soft); }
.fab-step[data-done="true"]::before {
  background: var(--c-success-93a); border-color: var(--c-success-83); color: var(--c-success-30a);
  content: '✓';
}

.intro-tip {
  width: min(420px, calc(100vw - 48px));
  padding: 0;
  border: 1px solid var(--v2-hairline);
  border-radius: var(--v2-radius-lg);
  background: var(--v2-surface);
  color: var(--v2-ink);
  box-shadow: 0 18px 50px rgba(17, 24, 39, .22);
}
.intro-tip::backdrop { background: rgba(17, 24, 39, .35); }
.intro-tip-head {
  display: flex; align-items: center; gap: 10px;
  padding: 16px 20px 4px;
}
.intro-tip .intro-mark {
  flex: none; width: 32px; height: 32px; border-radius: var(--v2-radius);
  display: grid; place-items: center;
  background-image: var(--v2-accent-gradient); color: var(--c-neutral-100);
}
.intro-tip-title { margin: 0; font-size: 16px; }
.intro-tip-line {
  margin: 8px 0 0; padding: 0 20px;
  font-size: 13px; line-height: 19px; color: var(--v2-ink-soft);
}
.intro-tip-foot {
  display: flex; justify-content: flex-end; gap: 10px;
  padding: 14px 20px 16px;
}

/*
 * A tab that is looking at yesterday's code.
 *
 * Fixed at the foot of the screen rather than pushed into the page: every
 * screen has its own layout and a bar that reflowed one of them would move
 * whatever somebody was reading. Above the rail's own layer so it is not
 * half-covered on a narrow window, and clear of the Report button, which
 * lives in the right-hand corner.
 *
 * Gold rather than red: nothing is broken and nothing is lost — the screen
 * is merely old — and red here would compete with the warnings that mean
 * somebody's plan is in trouble.
 */
.stale-build {
  position: fixed; left: 50%; bottom: 18px; transform: translateX(-50%);
  z-index: 60; max-width: min(760px, calc(100vw - 32px));
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 12px 16px;
  border: 1px solid var(--v2-warn-line); border-radius: var(--v2-radius-lg);
  background: var(--v2-warn-bg); color: var(--v2-warn-text);
  box-shadow: var(--v2-shadow-panel);
}
.stale-build-mark { font-size: 18px; line-height: 1; flex: none; }
.stale-build-text { margin: 0; flex: 1; min-width: 220px; font-size: 13px; }
.stale-build .v2-btn { flex: none; }

/* On a phone the sentence needs the width more than the buttons need to be
   beside it. */
@media (max-width: 640px) {
  .stale-build { left: 16px; right: 16px; transform: none; max-width: none; }
  .stale-build-text { min-width: 0; }
}
