/**
 * Back-Office content vocabulary — the record-workspace layer.
 *
 * Companion to be-shell.css (the frame): this file styles what goes INSIDE the
 * shell's content column on staff record surfaces:
 *
 *   - `.mca-case-*`     — the case workspace tabs + padded body (moved here
 *                         from the mca-case-tabs partial's inline <style>; the
 *                         partial renders only markup now).
 *   - `body.be-record`  — the fill runtime's record-workspace mode
 *                         (fill-page.js sets the class on a BeShell-framed,
 *                         marker-less page with sections): context strip,
 *                         derived section rail, sections as shared surface
 *                         cards with label/value grids.
 *
 * Loaded by internal/web/templates/layout.html AFTER the page stylesheet so
 * its equal-specificity overrides win over fill.css; card chrome itself comes
 * from the COMPOSED `.fit-surface-card` class (base.css) — this file never
 * hand-rolls a radius+shadow surface (docs/one-shared-card.md).
 */

/* Case workspace tabs (was: partials/mca-case-tabs.html <style>) ---------- */
/* Framed /mca/case* surfaces render inside .be-content, which now owns the
   standard shell gutter by DEFAULT (be-shell-frame-gutter-default-on) — this
   body must NOT re-pad or the content double-insets. Zeroed, not dropped, so a
   future base rule can't silently re-add a gutter here. */
.mca-case-body { padding: 0; }
.mca-case-tabs { display: flex; gap: var(--space-xs); margin: 0 0 var(--space-lg); border-bottom: 1px solid var(--color-border-light); }
.mca-case-tabs a { padding: var(--space-sm) var(--space-md); text-decoration: none; color: var(--color-grey-darkest); font: var(--font-small-bold); border-bottom: 2px solid transparent; margin-bottom: -1px; }
.mca-case-tabs a:hover { color: var(--color-primary-base); }
.mca-case-tabs a[aria-current="page"] { color: var(--color-primary-base); border-bottom-color: var(--color-primary-base); }

/* Queue provenance — the "← <queue>" back-link a queue's action form paints
   above its content (staff-page.js renderProvenance). It moved here from
   css/pages/queue-detail.css when the MCA judicial surfaces became queue action
   forms (tasks/2026-08-04-portable-role-entry-points.md §2): the strip is now
   painted by FOUR pages, not one, so its rules belong in the shared BeShell
   content layer rather than on any single page's stylesheet. Empty ⇒ the
   #provenance container has no children and nothing shows. */
.queue-provenance__back { display: inline-flex; align-items: center; gap: var(--space-xs, 6px); font-size: 0.9rem; }
.queue-provenance__arrow { font-size: 1.05em; }

/* Content card FLUSH with the tab strip. On the action-panel case pages
   (minutes / finalise-orders / order — the `.be-form-panel` templates) the tab
   strip spans the full `.mca-case-body` content column (margin:0), but the panel
   is capped + auto-centred (`max-width:1168px; margin:0 auto`, be-action.css),
   so the card sat ~68px more inset than its own tabs. Drop the panel cap AND the
   inner `.container`'s own 1168 cap (`body.jds-fill .container`) here so the
   card's left AND right edge line up with the tabs directly above it; both caps
   stay for the non-case `.be-form-panel` action surfaces. The container rule
   (0,3,0) also beats `body.jds-fill .container` (0,2,1) and `body.be-record
   .container` (0,2,1), so neither the jds cap nor a be-record gutter can re-inset
   a case card. */
.mca-case-body .be-form-panel { max-width: none; margin: 0; }
.mca-case-body .be-form-panel .container { max-width: none; padding-left: 0; padding-right: 0; }
/* The Case + Conclusion tabs render via the generic `fill` template (be-record
   record workspace, NO `.be-form-panel`); there the case tabs are flush to the
   content edge but `body.be-record .container`'s horizontal gutter insets the
   content ~36px, so the record content sat inset from its own tabs. Zero that
   gutter ONLY on the framed case surface — scoped by the presence of the case
   tab strip so the OTHER framed be-record pages (e.g. /queue/item, which has no
   case tabs) keep their gutter unchanged. Vertical gutter is untouched. */
body.be-record:has(.mca-case-tabs) .container { padding-left: 0; padding-right: 0; }

/* Fluid staff content surfaces (inbox/queue, search, tray/dashboard pages) go
   full-width beside the rail. The shell gutter is now default-ON on .be-content
   (be-shell-frame-gutter-default-on), so this rule only strips the centred
   `.container` cap (max-width + auto margins) to make the surface fluid; the
   padding is zeroed explicitly so `.container`'s base gutter (fill.css) can't
   double up against the .be-content gutter. Scoped to `.be-shell` so the public
   (non-framed) list keeps its own layout. */
.be-shell .be-fluid-content { max-width: none; margin: 0; padding: 0; }

/* MEASURED content surfaces — a block that keeps its own centred max-width but
   takes the SHELL's frame gutter rather than its own. `.be-fluid-content`'s
   sibling: that one drops the measure as well as the inset; this one drops only
   the inset.

   The callers are the public portal's server-rendered pages (submitted, pay,
   chit, apply — tasks/2026-08-18-the-rest-of-the-public-pages-wear-the-shell.md).
   Each centres a card in a fixed measure and carried its own padding when it
   rendered on the front-office strip; inside the shell the `.be-content` gutter
   is already there, so the page's own would be a second one. The two pages that
   genuinely own their horizontal layout do the opposite — they stay flush and
   keep their own gutter (flushPublicShellPages, cmd/server/tenant_gate.go).

   Scoped to `.be-shell`, so an unframed render of the same template is
   byte-identical. */
.be-shell .be-measured-content { padding: 0; }

/* Record workspace (body.be-record) --------------------------------------- */
/* The record page floats its pieces on the grey shell background — the
   SECTIONS are the cards, so the one big form-card wrapper goes flat and the
   content column turns fluid (back-office look, not the centred public form). */
/* The record page floats its pieces on the grey shell background — the SECTIONS
   are the cards, so the one big form-card wrapper goes flat and the content
   column turns fluid (back-office look, not the centred public form). The fill
   `.container` OWNS this gutter (the fill page is .be-content--flush — see
   cmd/server flushShellPages "fill"), so it survives BOTH the framed /mca/case
   AND the bare catalog `?chrome=beshell` preview embed (which has no .be-content
   at all). */
body.be-record .container { max-width: none; margin: 0; padding: var(--space-lg) var(--space-xl); }
body.be-record .form-card-frame { border-radius: 0; box-shadow: none; overflow: visible; background: transparent; }
body.be-record .form-area { background: transparent; }
/* fill.css insets every .form-area child for the one-card layout; the record
   workspace has no card wrapper, the container gutter owns the inset. A child
   that IS a surface card (the context strip) keeps its own inner padding —
   zeroing it would pin content to the card edge. */
body.be-record .form-area > *:not(.fit-surface-card) { padding-left: 0; padding-right: 0; }
body.be-record .fit-sidebar-layout { padding-left: 0; padding-right: 0; }

/* Context strip — the record's identity band (leading loose fields): a shared
   surface card laying its label-over-value cells out in a responsive row. */
body.be-record .be-context-strip {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--space-sm) var(--space-lg);
  margin-bottom: var(--space-lg);
  /* Uniform card inset: the fill page's jds child-inset rule would otherwise
     win on the horizontal axis (48px left / 24px top asymmetry). */
  padding: var(--fit-card-pad, var(--space-lg));
}
body.be-record .be-context-strip [data-fit-widget="field-wrap"] { margin: 0; min-width: 0; }

/* Label-over-value cells — reference `detail-grid .detail`: small grey label,
   plain black value, no input chrome. */
body.be-record .preview-label {
  font: var(--font-small);
  color: var(--color-grey-darkest);
  margin-bottom: 2px;
}
body.be-record span[data-fit-widget][data-fit-mode="readPretty"] { padding: 0; }

/* The ONE label/value look for the whole record page: a quiet grey label over a
   bold dark value. It is declared ONCE here and every record-page pair opts in by
   class, so the look is never restated per surface:

     - generic TAB fields (Applications, Hearings, …), rendered by the fill
       runtime as a `.preview-label` over a `[data-fit-mode="readPretty"]` box;
     - the Overview "Case Information" card (`.be-record-overview__label/value`);
     - the summary side rail and its static catalog demo
       (`.be-record-side__label/value`).

   The generic selector is scoped to #record-read (NOT body.be-record): the
   per-tab renders do not carry the be-record body class — only the main page
   render does — so a body.be-record rule never reaches the tab content. The
   `be-record-*` selectors stay UNSCOPED because the catalog's static case-view
   demo draws them outside #record-read. `:not(.fit-field-section)` spares the
   composition / list HEADING labels ("Applicants", "P"). */
#record-read [data-fit-widget="field-wrap"]:not(.fit-field-section) > .preview-label,
.be-record-overview__label,
.be-record-side__label {
  font: var(--font-small);
  color: var(--color-grey-dark);
}
#record-read [data-fit-mode="readPretty"],
.be-record-overview__value,
.be-record-side__value {
  font: var(--font-paragraph-bold);
  color: var(--color-grey-darkest);
  overflow-wrap: anywhere;
}
/* The generic tab field has NO container gap (label + value stack directly in a
   field-wrap), so its label owns the small step down to its value. The Overview
   and side rows get that step from their group's own gap instead. */
#record-read [data-fit-widget="field-wrap"]:not(.fit-field-section) > .preview-label {
  margin-bottom: var(--space-xxs);
}
/* Vertical rhythm for NESTED fields. Top-level fields sit directly in the card
   body's grid and get its 24px row gap; fields inside a composition (a hasOne
   like "P", or a hasMany item like "Party 1") stack as plain blocks with no gap
   and read as one dense column. Give each nested leaf field the same breathing
   room the Overview/Hearings cards have between rows. */
#record-read .fit-field-section [data-fit-widget="field-wrap"]:not(.fit-field-section) {
  margin-bottom: var(--space-md);
}

/* Section cards — the shared surface card class is added by the runtime;
   here only rhythm + the internal label/value grid. */
body.be-record .fit-sidebar-content > [data-fit-widget="section"] { margin: 0 0 var(--space-lg); }
body.be-record [data-fit-widget="section"].fit-surface-card > .accordion-body,
body.be-record details[data-fit-widget="section"].fit-surface-card > .accordion-body {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: var(--space-md) var(--space-lg);
}
body.be-record .fit-surface-card > .accordion-body > * { min-width: 0; }
/* The fill grid system stamps every block `grid-column: span N` (12-col form
   grid); inside the record card the label/value grid owns placement — a cell
   is one track. */
body.be-record .fit-surface-card > .accordion-body > [data-be-cell="cell"] { grid-column: auto; }
/* Wide content spans the full card row. The runtime tags each child off its
   BLOCK's declared type (data-be-cell="wide": long text, lists/compositions,
   uploads, non-field blocks); anything untagged is unknown — span it too. */
body.be-record .fit-surface-card > .accordion-body > [data-be-cell="wide"],
body.be-record .fit-surface-card > .accordion-body > :not([data-be-cell]) {
  grid-column: 1 / -1;
}

/* Derived section rail — stick below the shell top bar like the reference's
   jds-list-group (be-shell.css exposes --be-topbar-h). */
body.be-record .fit-rail {
  position: sticky;
  top: calc(var(--be-topbar-h, 64px) + var(--space-lg));
  align-self: flex-start;
  width: 280px;
}

/* Phone widths: rail drops above the content; grids collapse naturally. */
@media (max-width: 768px) {
  body.be-record .fit-rail { position: static; width: auto; }
}

/* Record head + tab rail + summary panel — the Figma case-view anatomy
   (tasks/2026-08-07-queue-tabs-case-view-hearings.md Part 2). Rendered by
   fill-page.js into the empty regions queue-detail.html declares; nothing here
   is per-DataType, because the page is not.

   These are LAYOUT classes on the shared record workspace, not a new card: the
   sections inside .be-record-main are the ordinary .fit-surface-card the record
   workspace already renders, so the card guard stays satisfied. */
.be-record-head {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  margin: 0 0 var(--space-lg);
}
.be-record-head[hidden] { display: none; }
.be-record-head__crumb { font: var(--font-small); color: var(--color-grey-dark); }
.be-record-head__crumb a { color: var(--color-grey-dark); text-decoration: none; }
.be-record-head__crumb a:hover { color: var(--color-primary-base); text-decoration: underline; }
.be-record-head__crumb-sep { margin: 0 var(--space-xs); }
.be-record-head__row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-md);
}
.be-record-head__ident { min-width: 0; }
/* The h1 + status-pill row sits together in one flex line; the pill is a
   sibling of the h1 (not a child) so the h1's textContent stays a clean
   case reference for screen readers and text-equality assertions. #183. */
.be-record-head__title-row {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--space-sm);
}
/* 28px/34px per work item #183. Not on --font-h2 (35px) or --font-h2-5 (30px);
   the design ask is a size neither token carries, so it lives inline until a
   second consumer earns it its own token. */
.be-record-head__title {
  margin: 0;
  font-family: var(--font-family-primary);
  font-weight: 700;
  font-size: 28px;
  line-height: 34px;
  color: var(--color-grey-darkest);
}
.be-record-head__badge-slot { display: inline-flex; align-items: center; }
.be-record-head__badge-slot:empty { display: none; }
.be-record-head__sub { margin: var(--space-xxs) 0 0; font: var(--font-small); color: var(--color-grey-dark); }
/* The actions. #action-bar is the SAME element the runtime always filled, so it
   still contains the runtime's `.form-action-bar` row — the maroon band's own
   rules are undone here rather than the row being rebuilt, which is what keeps
   the buttons, their dispatch and their confirm modals byte-identical. */
/* margin-left:auto keeps the actions hard right on BOTH lines: beside the
   title when it fits, and — when the title row wraps them onto their own line —
   still flush with the row's right edge (a lone wrapped flex item under
   `justify-content: space-between` otherwise falls to the LEFT of its line). */
/* The container's OWN gap, for the children it does not mount itself. A
   Go-template page (no JS renderer) hand-writes its actions straight in — see
   internal/web/templates/pages/calendar-session.html — and until this landed
   nothing spaced them: the destructive button's border met the lead's. Same
   --space-sm the runtime's row uses (`.be-record-head__actions
   .form-action-bar` and its `__right` group, just below), so both paths read
   alike. It is
   inert where the runtime DOES mount the row (queue-detail), because there the
   container has exactly one element child and a lone flex item has no sibling
   to space — pinned in test/e2e/mca-backoffice.spec.ts; the distance itself is
   pinned in test/e2e/calendar-sessions-management.spec.ts. */
.be-record-head__actions { display: flex; align-items: flex-start; gap: var(--space-sm); margin-left: auto; }
.be-record-head__actions:empty { display: none; }
/* An actions area that also carries a blocked-reason sentence STACKS: the
   sentence explains the button above it, so it belongs under the buttons and
   not beside them (where it read as a second, wordier control). The runtime
   sets the attribute only when it has a sentence to place, so an ordinary
   record head is byte-identical — including the single-element-child
   assumption the gap comment above depends on. */
.be-record-head__actions[data-has-blocked-note] { flex-direction: column; align-items: flex-end; }
.be-record-head__actions .form-action-bar {
  position: static;
  margin: 0;
  padding: 0;
  background: none;
  border: 0;
  box-shadow: none;
  display: flex;
  gap: var(--space-sm);
}
.be-record-head__actions .form-action-bar__left { display: none; }
.be-record-head__actions .form-action-bar__right { display: flex; gap: var(--space-sm); margin: 0; }

/* The tab rail. Same visual grammar as the tray's queue tabs, and it WRAPS for
   the same reason: eight tabs do not fit one row at 1280px and an overflow
   scroller hides the tail with no affordance. */
.be-record-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
  border-bottom: 1px solid var(--color-border-light);
}
.be-record-tabs:empty { display: none; }
.be-record-tabs__tab {
  padding: var(--space-sm) var(--space-md);
  text-decoration: none;
  color: var(--color-grey-darkest);
  font: var(--font-small-bold);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  white-space: nowrap;
}
.be-record-tabs__tab:hover { color: var(--color-primary-base); }
.be-record-tabs__tab--active { color: var(--color-primary-base); border-bottom-color: var(--color-primary-base); }
/* Unread red-dot on a tab whose `list.present` reports an unread row (the
   Correspondences tab). Presentational — the count is the panel's business. */
.be-record-tabs__dot {
  display: inline-block;
  width: 7px;
  height: 7px;
  margin-left: var(--space-xs);
  border-radius: 50%;
  background: var(--color-error-base);
  vertical-align: middle;
}

/* The record body column + optional summary rail. The rail is a FALLBACK now
   (tasks/2026-08-20-back-office-overview-tab.md): a queue that authors an
   "Overview" tab has moved its at-a-glance facts into that tab's Case
   Information card, so fill-page.js leaves `#record-side` empty and
   `:empty { display:none }` collapses it. The grid is therefore ONE column by
   default and widens to the summary track ONLY when the rail actually carries
   content (`:has(> .be-record-side:not(:empty))`) — so an MCA case (Overview
   tab) fills the full width while a task or a criminal case keeps the rail
   beside the read.

   The `.be-record-side*` label/value runs are SHARED beyond this page: the
   Hearing-Sessions management page (calendar-session.html) and the catalog
   case-view demo reuse them for their own configuration panels. */
.be-record-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-xl);
  align-items: start;
}
.be-record-layout:has(> .be-record-side:not(:empty)) {
  grid-template-columns: minmax(0, 1fr) 20rem;
}
.be-record-main { min-width: 0; }
.be-record-side { display: flex; flex-direction: column; gap: var(--space-md); position: sticky; top: var(--space-lg); }
.be-record-side:empty { display: none; }
/* label/value LOOK is the one shared rule above; the group owns only layout. */
.be-record-side__group { display: flex; flex-direction: column; gap: var(--space-xxs); }
.be-record-side__pills { display: flex; flex-wrap: wrap; gap: var(--space-xs); }

@media (max-width: 900px) {
  .be-record-side { position: static; }
}

/* The Overview tab's Case Information card. It IS the shared surface card
   (.fit-surface-card — one-shared-card.md); these classes own only its internal
   rhythm: a heading, then the label/value runs (same grammar the old summary
   rail used, reused so the reader meets one look). Never a border/radius/shadow
   of its own — the card guard stays satisfied. */
.be-record-overview__title {
  margin: 0 0 var(--space-md);
  font: var(--font-h3);
  color: var(--color-grey-darkest);
}
.be-record-overview__grid { display: flex; flex-direction: column; gap: var(--space-md); }
/* label/value LOOK is the one shared rule above; the group owns only layout. */
.be-record-overview__group { display: flex; flex-direction: column; gap: var(--space-xxs); }

/* The empty sentence a tab shows when it has nothing — never a blank panel. */
.be-record-empty {
  padding: var(--space-lg);
  font: var(--font-paragraph);
  color: var(--color-grey-dark);
}

/* One card per LISTED row (the cross-record arm of a record tab —
   tasks/2026-08-07-queue-tabs-case-view-hearings.md §3.5). A hearing is not a
   table row: its date, its coram, its status and "what happened at it" are read
   together, and the four states it can be in are sentences, not cells. So the
   arm renders the listed View readPretty into the SHARED card
   (.fit-surface-card — no second card is defined here, only its inner runs). */
/* The three list resets are for a caller that uses a real `<ul>` — the
   changeset entry page's "waiting for you" side door, which IS a list and says
   so.

   THE OTHER CALLER IS A `<div>` AND RENDERS IDENTICALLY, but not for the reason
   this comment first gave ("all three are already the browser default"). Two of
   them are: `margin` and `padding` on a `<div>` are already 0. `list-style` is
   NOT — it is an INHERITED property, so it does reach every descendant of the
   div, including the read views fill-page.js mounts into each
   `.be-record-card__body` and any `<ul>` fit-rich-text.js injects.

   It changes nothing there because inheritance is the LAST resort: the UA
   stylesheet declares `list-style-type` on `ul` ITSELF — `disc` at the top
   level, `circle` for a list nested inside another list — and a declaration
   that matches an element always beats a value inherited into it. So a bulleted
   list inside a card keeps its bullets. `list-style-image: none` and
   `list-style-position: outside` are the initial values anyway.

   That is a claim about the cascade, so it is asserted in a browser rather than
   reasoned about here — test/e2e/changeset-card-interior.spec.ts, "the record-
   card list reset does not strip a nested list's bullets". Scope this rule to
   `ul.be-record-cards` and that test still passes; it is written to catch the
   direction that would actually hurt, which is anything making the inherited
   `none` win. */
.be-record-cards {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  list-style: none;
  margin: 0;
  padding: 0;
}
.be-record-card { padding: var(--space-lg); }
.be-record-card__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-md);
  margin-bottom: var(--space-sm);
}
.be-record-card__open {
  font: var(--font-h5);
  color: var(--color-primary-base);
  text-decoration: none;
  overflow-wrap: anywhere;
}
.be-record-card__open:hover { text-decoration: underline; }
.be-record-card__body { display: flex; flex-direction: column; gap: var(--space-md); }

/* A card that ASKS before it opens (hearing-workspace 4a1,
   docs/generic-record-page.md § A card that asks first). The whole card is the
   click target, so it says so — a pointer, a hover lift, and the offered word
   ("Commence hearing" / "Rejoin") in the head beside the title. A card with no
   way in gets NONE of this and is byte-identical to before. */
.be-record-card--asks { cursor: pointer; }
.be-record-card--asks:hover { border-color: var(--color-primary-base); }
.be-record-card--asks:focus-within { box-shadow: var(--shadow-focus); }
.be-record-card__hint {
  flex: none;
  font: var(--font-small-bold);
  color: var(--color-primary-base);
  white-space: nowrap;
}
.be-record-card__hint::after { content: " →"; }

/* The confirmation itself is the SHARED editor modal (fit-editor-modal.ts) —
   fixed to the viewport, so the scrim covers the left rail too. Only its inner
   runs are named here: a definition list of facts, then the notes. */
.be-record-confirm .be-record-confirm__facts {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  margin: 0 0 var(--space-md);
}
.be-record-confirm__fact { display: flex; gap: var(--space-sm); align-items: baseline; }
.be-record-confirm__fact dt { flex: none; min-width: 11rem; font: var(--font-small); color: var(--color-grey-dark); }
.be-record-confirm__fact dd { margin: 0; font: var(--font-small-bold); color: var(--color-heading); }
/* A fact the record does not carry reads as the authored sentence, in the
   quieter voice — it is an absence, not a value. */
.be-record-confirm__fact-empty { font: var(--font-small); color: var(--color-grey-dark); font-style: italic; }
.be-record-confirm__notes { margin: 0; padding-left: var(--space-lg); }
.be-record-confirm__note { margin-bottom: var(--space-xs); }

/* The message-thread presentation of a `list` tab (the Correspondences tab —
   tasks/2026-08-11-figma-be-sync-5-correspondences.md, Figma states 1–3). ONE
   shared card (.fit-surface-card); rows are a counterparty thread collapsed to
   avatar + name + role tag + count + preview + date + unread badge. */
.corr-panel { padding: var(--space-lg); }
.corr-panel__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  margin-bottom: var(--space-md);
}
.corr-panel__title { font: var(--font-h5); color: var(--color-grey-darkest); margin: 0; }

.corr-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.corr-row {
  display: flex;
  align-items: flex-start;
  gap: var(--space-md);
  padding: var(--space-md) 0;
  border-top: 1px solid var(--color-border-light);
  cursor: pointer;
}
.corr-row:first-child { border-top: 0; }
.corr-row:hover { background: var(--color-grey-lightest); }
.corr-row__avatar {
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--color-grey-lighter);
  color: var(--color-grey-darkest);
  display: flex;
  align-items: center;
  justify-content: center;
  font: var(--font-small-bold);
}
.corr-row__main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: var(--space-xxs); }
.corr-row__line1 { display: flex; align-items: center; gap: var(--space-xs); flex-wrap: wrap; }
.corr-row__name { font: var(--font-paragraph-bold); color: var(--color-grey-darkest); }
.corr-row__role {
  font: var(--font-small);
  color: var(--color-grey-dark);
}
.corr-row__count {
  font: var(--font-small);
  color: var(--color-grey-dark);
  background: var(--color-grey-lighter);
  border-radius: var(--radius-sm);
  padding: 0 var(--space-xs);
}
.corr-row__preview {
  font: var(--font-small);
  color: var(--color-grey-dark);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
}
.corr-row__meta { flex: 0 0 auto; display: flex; flex-direction: column; align-items: flex-end; gap: var(--space-xs); }
.corr-row__date { font: var(--font-small); color: var(--color-grey-dark); white-space: nowrap; }
.corr-row__unread {
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  border-radius: 10px;
  background: var(--color-error-base);
  color: var(--color-white);
  font: var(--font-small-bold);
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Empty state — icon + the one sentence (Figma state 1). */
.corr-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-md);
  padding: var(--space-xl) var(--space-lg);
  text-align: center;
}
.corr-empty__icon { color: var(--color-grey); }
.corr-empty__text { font: var(--font-paragraph); color: var(--color-grey-dark); margin: 0; }

/* Thread DETAIL — the email-style letter stack (renderMessageThreadDetail).
   Both the staff case tab and the public case page reuse it; the public
   audience simply feeds fewer header rows. */
.corr-thread { display: flex; flex-direction: column; gap: var(--space-lg); max-width: 820px; }
/* The two thread buttons are ordinary `.jud-button`s and NAME their look: Back is
   `ghost`/`brand` and Reply is `primary`/`brand`, both painted by jud-button.css
   off the two data attributes. The colour blocks that used to sit here — a
   hand-mixed transparent/`--color-primary-light` pair for Back and a
   `--color-primary-light` fill + its own hover for Reply — are GONE: they were
   restating the two pairs jud-button already ships, and being (0,1,0) they would
   now be dead under the pair rules' (0,3,0) anyway.

   `.corr-thread__*` survives as the identity hook the e2e specs and fill-page's
   `returnFocusSel` select by, and it keeps the one thing the shared button has no
   opinion about: Back sits flush at the START of the column, not stretched by the
   thread's flex column.

   Back's old `padding-left/right: 0` went with the colours, because it was already
   DEAD: `.corr-thread__back` is (0,1,0) and jud-button's own
   `.jud-button[data-jud-size="sm"]` padding is (0,2,0), so the button has been
   drawing jud's `0 16px` for as long as it has been a `.jud-button`. Re-winning it
   would be a visual CHANGE dressed as a rename, so it is not re-won here. */
.corr-thread__back { align-self: flex-start; }
.corr-thread__head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-md); flex-wrap: wrap; }
.corr-thread__subject { font: var(--font-h4); color: var(--color-heading); margin: 0 0 var(--space-xxs); }
.corr-thread__caseline { font: var(--font-small); color: var(--color-grey-dark); margin: 0; }
.corr-letter { padding: var(--space-lg); }
.corr-letter__head {
  display: grid;
  grid-template-columns: 110px 1fr;
  gap: var(--space-xxs) var(--space-md);
  padding-bottom: var(--space-md);
  margin-bottom: var(--space-md);
  border-bottom: 1px solid var(--color-grey-lighter);
}
.corr-letter__from { grid-column: 1 / -1; font: var(--font-paragraph-bold); color: var(--color-grey-darkest); }
.corr-letter__k { font: var(--font-small); color: var(--color-grey-dark); }
.corr-letter__v { font: var(--font-small); color: var(--color-grey-darkest); }
.corr-letter__body { font: var(--font-paragraph); color: var(--color-grey-darkest); line-height: 1.6; }
.corr-letter__body > * + * { margin-top: var(--space-sm); }
/* A letter's attachments — the court's enclosures, under the body and above the
   next letter (tasks/2026-08-20-attach-files-to-an-outgoing-correspondence-
   message.md). Drawn only when the View's `present` names an attachments field
   AND the letter carries one, so a letter without enclosures keeps the exact
   spacing it had before. */
.corr-letter__files {
  margin-top: var(--space-md);
  padding-top: var(--space-md);
  border-top: 1px solid var(--color-grey-lighter);
}
.corr-letter__files-label {
  font: var(--font-small);
  color: var(--color-grey-dark);
  margin-bottom: var(--space-xs);
}
.corr-letter__file-list { list-style: none; margin: 0; padding: 0; }
.corr-letter__file-list > li + li { margin-top: var(--space-xs); }
/* Layout only. The link's COLOUR and its hover underline come from base.css's
   global `a` rule (--color-primary-light, the action maroon) — re-declaring
   them here painted the deep --color-primary-base instead, which is the brand
   fill colour, not the link role. */
.corr-letter__file {
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-xs);
  font: var(--font-paragraph);
}
.corr-letter__file-size { font: var(--font-small); color: var(--color-grey-dark); }

/* ═══════════════════════════════════════════════════════════════════════════
   A CHANGE, SHOWN CHANGED — the before-and-after anatomy
   (/private/catalog/#/changerow; docs/mcp-changesets.md;
   tasks/2026-09-01-the-changeset-card-interior-is-unstyled.md).

   The owner's reading rules, 2026-08-31: a changed value is SHOWN changed and
   never described in a sentence; on-screen JSON is syntax highlighted; a time
   reads in the READER's clock with a relative form beside it. Its first caller
   is the MCP approval screen, whose whole job is showing a person what an agent
   asked to change before they approve it — but nothing here knows that, and a
   version history, an audit trail or a staleness banner wants the same three.

   THESE ARE THE ONLY SHAPES THAT CARD NEEDED AND THE RECORD ANATOMY ABOVE DID
   NOT ALREADY HAVE. Everything else on it is `.fit-surface-card`,
   `.be-record-card__*`, `.be-record-overview__*`, `.be-record-empty`,
   `.be-record-confirm__note*`, `.status-pill` and `.deco-alert`. Nothing here
   draws a radius+shadow surface, so the card guard stays satisfied
   (docs/one-shared-card.md).

   NOTHING HERE COLLAPSES, TRUNCATES OR FOLDS — GROUP-A tradeoff 4. No clamp, no
   ellipsis, no scroll box: a long change is a long page. `overflow-wrap:
   anywhere` is the whole of what long values get, because breaking a line is
   not hiding one. `test/e2e/changeset-card-interior.spec.ts` asserts it on the
   rendered page rather than trusting this paragraph.
   ═══════════════════════════════════════════════════════════════════════════ */

/* One subject's heading (a `.be-record-overview__group` pair) over its rows. */
.be-change-group { display: flex; flex-direction: column; gap: var(--space-sm); }
.be-change-rows { display: flex; flex-direction: column; }

/* One before → after line. Four tracks so the arrows line up down the column
   however long the values are, and a hairline between rows so a reader's eye
   can follow one across — the same divider the tray's rows use. */
.be-change-row {
  display: grid;
  grid-template-columns: minmax(0, 13rem) minmax(0, 1fr) auto minmax(0, 1fr);
  gap: var(--space-xxs) var(--space-md);
  align-items: baseline;
  padding: var(--space-sm) 0;
  border-top: 1px solid var(--color-border-light);
}
.be-change-row:first-child { border-top: 0; padding-top: 0; }
.be-change-row__label { text-align: left; }
/* `justify-self: start` so the MARK hugs its words. A grid item stretches to
   its track by default, which paints the tint across the whole column and reads
   as a highlighted ROW rather than a changed VALUE — and on a row where only
   one side moved it drew a full-width band beside a plain half. Long values
   still fill the track and wrap inside it; nothing is cut. */
.be-change-row__was,
.be-change-row__now { justify-self: start; overflow-wrap: anywhere; min-width: 0; }
.be-change-row__arrow { color: var(--color-grey-dark); }

/* THE MARK IS THE ELEMENT, NEVER THE COLOUR. The markup puts a value that WENT
   in `<del>` and one that ARRIVED in `<ins>`, so the row still reads correctly
   with colour off, in a monochrome print and to a screen reader; these two
   rules only paint.

   THE ADDITION'S SECOND CARRIER IS A DOTTED UNDERLINE, and it replaced
   `text-decoration: none` on 2026-09-01. The reasoning for switching the UA's
   underline off was right as far as it went — a SOLID underline beside a struck
   sibling reads as a second kind of deletion — but it left an addition with
   COLOUR as its only visual difference, which is nothing at all in a monochrome
   print or to a reader who cannot separate the two hues. A dotted line is not
   confusable with a line drawn through the middle of the words, so the pair now
   reads as "struck" versus "underlined-differently" with no colour at all.

   Both pairs are the 100 surface under the 700 text of the same ramp: 7.07:1
   and 7.17:1, comfortably past AA for body text. (It said 7.08 for the green
   until 2026-09-01; the numbers are now computed from the tokens by
   internal/prosecheck/changeset_contrast_test.go rather than remembered.) There is no dark palette to
   check them against — `jds-semantic-dark.css` is scoped to
   `:root.jds-night-theme` and nothing in the staff shell sets that class (only
   the JDS component gallery's own demo panes do) — and because these are token
   references rather than hexes, they follow the theme the day one arrives. */
.be-change-gone,
.be-change-new {
  border-radius: var(--radius-sm);
  padding: 0 var(--space-xxs);
}
.be-change-gone {
  background: var(--color-danger-light);
  color: var(--color-error-dark);
  text-decoration: line-through;
}
.be-change-new {
  background: var(--color-success-light);
  color: var(--color-success-dark);
  text-decoration: underline dotted;
  text-underline-offset: 0.2em;
}

/* ── A LIST-VALUED ROW: ONE ITEM PER LINE, EACH WITH ITS OWN MARK ────────────
   Take 2, mockups/lo-fi/2026-09-05-change-row-diff-six-takes.html, owner
   2026-09-05.

   WHAT IT REPLACED. A list was joined into one string before the row saw it, so
   "MCA cases" → "MCA cases, Records" drew four words struck beside five added,
   to say that one arrived. The owner: *"should just have been ADDING 'Records';
   not deleting the entire old thing and adding the combined new thing."*

   The list now goes vertical and each item carries its own mark, so the ink is
   proportional to what moved: the item that stays is drawn QUIETLY, the one
   that goes is struck, the one that arrives is marked. Same `.be-change-gone` /
   `.be-change-new` pair as a whole-value row — one mark vocabulary, two
   granularities.

   IT SPANS THE VALUE COLUMNS. A list-valued row has no before/after halves to
   line up, so the items occupy tracks 2–4 as one block and the label keeps
   track 1. That is why there is a `grid-column` here and nowhere else in this
   family.

   THE MARK CHARACTER IS `aria-hidden` DECORATION. `<del>`/`<ins>` carry the
   meaning to a screen reader and in monochrome, exactly as on a whole-value
   row; the `+` and `−` are for the sighted reader scanning the column, and a
   fixed-width gutter is what makes that column scannable. An item that stays
   gets a BLANK gutter rather than a bullet — it is the absence of a mark that
   says nothing happened to it. */
.be-change-row__items {
  grid-column: 2 / -1;
  display: flex;
  flex-direction: column;
  gap: var(--space-xxs);
  min-width: 0;
}
.be-change-item {
  display: grid;
  grid-template-columns: 1.25rem minmax(0, 1fr);
  align-items: baseline;
  overflow-wrap: anywhere;
}
/* THE MARK HUGS ITS WORDS — the same correction `.be-change-row__was/__now`
   already carry one level up, and for the same reason. A grid item stretches to
   its track by default, so the tint painted the full width of the card and read
   as a highlighted ROW rather than a changed VALUE. Long items still fill the
   track and wrap inside it; nothing is cut. */
.be-change-item > :not(.be-change-item__mark) { justify-self: start; min-width: 0; }
.be-change-item__mark {
  color: var(--color-grey-dark);
  font-variant-numeric: tabular-nums;
  user-select: none;
}
/* An item nothing is happening to. Quiet, so the eye lands on the ones that
   moved — but NOT so quiet that a reader has to hunt for what is being kept,
   which on a permissions screen is half of what they came to check. */
.be-change-item--same { color: var(--color-grey-darkest); }

/* THE NARROW ARM. The row's four tracks assume a staff-width window; below
   this the label column and the two value columns cannot all hold a readable
   measure, so the four tracks become one and the row's four children — the
   label, the "was", the arrow and the "now" — become four stacked lines, in
   the same order.

   THE ARROW DOES NOT TURN. This block moves it (`justify-self: start`) and
   changes nothing else about it: no transform, no rotation, no replacement
   glyph. `&rarr;` still points right, and it is `aria-hidden` either way, so
   what carries the before → after reading down the stack is the ORDER and the
   `<del>`/`<ins>` marks — never the arrow's direction. The sentence that used
   to sit here said the row became THREE lines and that the arrow "turns to
   point DOWN the stack"; both were false and neither was pinned by anything,
   which is why `internal/prosecheck/changeset_narrowarm_test.go` now DERIVES
   the count from the markup and READS the rotation off this block.

   NOTHING IS HIDDEN HERE, AND THERE IS NO EXCEPTION. This block set
   `display: none` on `[data-kind="heading"]` for a day, which hid the "When
   you were asked / Now" column labels under a rule stated as "Nothing is
   hidden". The options were drawn lo-fi
   (mockups/lo-fi/2026-09-01-changeset-table-narrow-headings.html) and the
   owner chose the one that keeps them: the rule stays absolute rather than
   growing its first exception.

   THE ACCEPTED COST, so nobody "fixes" it later: the heading row stacks like
   any other row here, so its two labels sit on their own lines above the first
   field with nothing beside them. Deliberate. It is held by
   `internal/prosecheck/changeset_narrowarm_test.go` and measured at 640px by
   `test/e2e/changeset-card-interior.spec.ts` — the existing collapse scan runs
   at DESKTOP width and asks about overflow, not `display`, which is how the
   declaration shipped at all.

   (2026-09-01 review, minor 11: the grid had no media query at all.)

   THE BREAKPOINT IS A BARE VALUE because it has to be: `var()` does not resolve
   inside a media query, so `--jds-breakpoint-*` cannot be named here and every
   media query in this tree carries a literal. `40rem` is 640px at the default
   root size — the same value as the tree's existing `max-width: 640px` queries —
   written in `rem` so it tracks a reader who has enlarged their text. */
@media (max-width: 40rem) {
  .be-change-row {
    grid-template-columns: minmax(0, 1fr);
    row-gap: var(--space-xxs);
  }
  .be-change-row__arrow { justify-self: start; }
}

/* THE READER'S CLOCK, NOT THE SERVER'S. The markup ships
   `<time datetime="{RFC3339}">{the absolute time}</time>`; the page's script
   rewrites that text into the reader's own timezone and appends the relative
   form. With the script blocked the served absolute time simply stands, which
   is why the server still writes a complete sentence into the element. */
.be-when__rel { font: var(--font-small); color: var(--color-grey-dark); }

/* JSON ON SCREEN IS READ, NOT SKIPPED. A `<pre>` of the request exactly as the
   screen read it — no wrap-hiding, no height cap, no toggle. The token classes
   are added by the page's script over the block's own text, so not one byte of
   what is shown changes and a reader with no JavaScript gets the same
   characters in one colour. */
.be-code-json {
  margin: 0;
  padding: var(--space-md);
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-sm);
  background: var(--color-grey-lighter);
  color: var(--color-grey-darkest);
  font-family: var(--font-family-mono);
  font-size: 12px;
  line-height: 18px;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.be-code-json__key { color: var(--color-primary-light); }
.be-code-json__str { color: var(--color-success-dark); }
.be-code-json__num { color: var(--color-status-info); }
.be-code-json__punct { color: var(--color-grey-dark); }

/* ═══════════════════════════════════════════════════════════════════════════
   THE HEARING WORKSPACE — the sixth shared back-office layout
   (docs/be-layouts.md § The hearing workspace;
   tasks/2026-08-22-hearing-workspace-2a1-the-two-pane-workspace.md).

   Two panes, full height. The LEFT is the case (a rail of its tabs plus the
   panel the selected one opens), the RIGHT is the live form, and ONE bar across
   the bottom carries the save state, the record's identity and a slot for the
   submit.

   The shell's markup is `renderWorkspace` in engine-src/staff-page.ts — a value
   handed to one renderer, never page CSS (which is what
   be-layouts-guard.test.ts refuses). Everything INSIDE the slots is the record
   page's OWN regions, moved in by fill-page.js: the rail is `#record-tabs`, the
   panel `#record-read`, the save line `#status-bar`, the submit `#action-bar`.
   So the rules below restyle those shared classes IN THIS CONTEXT and add no
   second vocabulary.

   `body.be-workspace-page` is the pin. Everywhere else on the site the document
   scrolls; here it must not, or "full height" is a page that grows a second
   scrollbar and the bottom bar walks off the screen. It is scoped to the body
   class, so every other be-shell page is byte-identical.
   ═══════════════════════════════════════════════════════════════════════════ */

body.be-workspace-page,
body.be-workspace-page .be-shell {
  height: 100vh;
  min-height: 0;
  overflow: hidden;
}
/* The shell's own gutter would inset a surface whose whole point is to reach
   the edges — the same opt-out the flush pages take, taken per-LAYOUT rather
   than per-page because the page (`queue-detail`) still wants the gutter in its
   ordinary shape. */
body.be-workspace-page .be-main { min-height: 0; }
body.be-workspace-page .be-content { padding: 0; min-height: 0; }
/* The action panel's 1168px measure is right for a form you READ; it is wrong
   for a workspace, which is a full-window surface. Left alone it centred the
   whole two-pane frame and left a white gutter down each side (56px a side at
   1280) — the rail's own column then no longer touched the window edge, which is
   the thing dropping the site rail was for. */
body.be-workspace-page .be-form-panel {
  display: flex;
  flex-direction: column;
  min-height: 0;
  flex: 1 1 auto;
  max-width: none;
  margin: 0;
  gap: 0;
}
/* The ordinary record layout is emptied by the move (its `#record-read` now
   lives in the panel slot); an empty grid would still take its gap. */
body.be-workspace-page .be-record-layout { display: none; }

.be-workspace {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  flex: 1 1 auto;
  min-height: 0;
  background: var(--color-white);
}
.be-workspace__body {
  display: grid;
  grid-template-columns: 8.5rem 18rem minmax(0, 1fr);
  min-height: 0;
}

/* The top strip: the record head, compacted onto one line. It is the SAME
   `#record-head` every record page paints — breadcrumb (which already carries
   the route back to the queue and to the case), title, and the last-updated
   line — so nothing new is authored for it. */
.be-workspace__top {
  display: flex;
  align-items: baseline;
  gap: var(--space-md);
  padding: var(--space-sm) var(--space-lg);
  border-bottom: 1px solid var(--color-border-light);
  overflow: hidden;
}
.be-workspace__top .be-record-head {
  display: flex;
  /* The head is a COLUMN everywhere else (crumb over title over tabs); on one
     44px strip it has to be a row, and the tabs are not in it any more. */
  flex-direction: row;
  align-items: baseline;
  gap: var(--space-md);
  width: 100%;
  min-width: 0;
  margin: 0;
}
.be-workspace__top .be-record-head__crumb {
  flex: 0 1 auto;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* The workspace has NO WAY BACK OUT (owner, 2026-08-22), so fill-page.js does
   not BUILD the breadcrumb here — a hidden link is still tabbable and still read
   aloud. What is left is an empty <nav>, and an empty flex item still takes the
   row's gap; this is what keeps the title where the reader expects it. */
.be-workspace__top .be-record-head__crumb:empty { display: none; }
.be-workspace__top .be-record-head__row { display: flex; align-items: baseline; gap: var(--space-md); min-width: 0; }
.be-workspace__top .be-record-head__title { font: var(--font-h4); margin: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.be-workspace__top .be-record-head__sub { font: var(--font-small); color: var(--color-grey-dark); margin: 0; white-space: nowrap; }

/* The LEFT RAIL — the case's own tabs, stacked. Same `.be-record-tabs__tab`
   elements the horizontal rail draws, turned on their side: the active mark
   moves from the bottom edge to the leading edge, which is the only difference
   a vertical rail needs. */
.be-workspace__rail {
  display: flex;
  flex-direction: column;
  gap: 0;
  padding: var(--space-sm) 0;
  border-right: 1px solid var(--color-border-light);
  border-bottom: none;
  /* --color-grey-lightest DOES NOT EXIST in this repo — `background` would
     compute to TRANSPARENT and the pane read as one undifferentiated white
     sheet. The repo has paid for that once already (fill.css `.status-bar.busy`),
     and `--color-grey-lighter` is not the repair either: the JDS block re-aliases
     it to grey-50, which IS --color-bg-page. --color-grey-light (#F3F3F3) is one
     step from the page in EITHER token block. */
  background: var(--color-grey-light);
  overflow-y: auto;
}
.be-workspace__rail .be-record-tabs__tab {
  padding: var(--space-sm) var(--space-md);
  border-bottom: none;
  border-left: 3px solid transparent;
  margin-bottom: 0;
  white-space: normal;
  overflow-wrap: anywhere;
}
.be-workspace__rail .be-record-tabs__tab--active {
  border-left-color: var(--color-primary-base);
  background: var(--color-white);
}

/* The context PANEL — whichever tab the rail has open, scrolling on its own. */
.be-workspace__panel {
  border-right: 1px solid var(--color-border-light);
  overflow-y: auto;
  padding: var(--space-md);
  min-width: 0;
}
/* A panel is already a panel: the card inside it would draw a second box around
   the same content, one pixel inside the first. Same reasoning as the record
   card's "cards-in-cards is noise" (docs/generic-record-page.md). */
.be-workspace__panel > .fit-surface-card {
  border: none;
  box-shadow: none;
  padding: 0;
  background: transparent;
}

/* The FORM pane — the minute sheet exactly as it is on the ordinary page,
   scrolling on its own. */
.be-workspace__form {
  overflow-y: auto;
  min-width: 0;
  background: var(--color-grey-light);
}
/* The sheet takes the whole pane. `.container`'s 960px cap and auto margins
   would centre a narrow column inside an already-narrow pane and waste the
   width the layout just bought. */
body.be-workspace-page .be-workspace__form .container { max-width: none; margin: 0; }
/* …and the FORM's own 365px section rail comes off. The workspace's left rail
   IS the navigation on this screen; a second column of section links beside it
   is the duplication the layout exists to remove, and at this width it leaves
   the minute sheet about a third of the pane. The sections themselves are
   untouched — they are simply scrolled to rather than jumped to. */
body.be-workspace-page .be-workspace__form .fit-rail { display: none; }

/* The BOTTOM BAR — save state · identity · the submit slot. The three save
   strings are unchanged (`setSaveStatus` still writes `#status-bar`); the bar
   is where they are read now, instead of above the form. */
.be-workspace__bottom {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  padding: var(--space-sm) var(--space-lg);
  border-top: 1px solid var(--color-border-light);
  background: var(--color-grey-light);
}
.be-workspace__state { flex: none; }
.be-workspace__state #status-bar { margin: 0; }
.be-workspace__ident {
  margin: 0;
  font: var(--font-small);
  color: var(--color-grey-dark);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* The submit's slot. It holds "End hearing" since hearing-workspace 3a1 —
   `:empty` is kept for a surface that authors no action at all, so a bar with a
   gap does not read as a bar with a broken button. */
.be-workspace__submit { margin-left: auto; flex: none; }
.be-workspace__submit:empty { display: none; }
.be-workspace__submit .form-action-bar__left { display: none; }
.be-workspace__submit .form-action-bar__right { display: flex; gap: var(--space-sm); margin: 0; }

/* Narrow: the two panes stop being two panes. A 10rem rail plus a 20rem panel
   plus a form does not fit a laptop half-screen, and a squeezed minute sheet is
   the one thing this layout exists to protect — so the context stacks ABOVE the
   form and the page scrolls as a page again. */
@media (max-width: 1100px) {
  body.be-workspace-page,
  body.be-workspace-page .be-shell { height: auto; min-height: 100vh; overflow: visible; }
  .be-workspace__body { grid-template-columns: minmax(0, 1fr); }
  .be-workspace__rail { flex-direction: row; flex-wrap: wrap; border-right: none; border-bottom: 1px solid var(--color-border-light); }
  .be-workspace__rail .be-record-tabs__tab { border-left: none; border-bottom: 2px solid transparent; }
  .be-workspace__rail .be-record-tabs__tab--active { border-left-color: transparent; border-bottom-color: var(--color-primary-base); }
  .be-workspace__panel { border-right: none; border-bottom: 1px solid var(--color-border-light); max-height: 20rem; }
  .be-workspace__form, .be-workspace__panel { overflow-y: visible; }
}
