/* ============================================================================
   components.css — components shared by more than one shell.

   Anything used by both the desk (desk.css) and the ledger (ledger.css) belongs
   here rather than being written twice. The repo has already been bitten by the
   alternative: the Ask GCS bubble lived only in desk.css, so the four client
   pages on ledger_client_base rendered no bubble at all, and the shared Sales
   Engine sub-navigation had to double-class every element
   (`class="subnav__n n"`) to survive whichever stylesheet happened to load.

   Loaded after tokens.css and before the shell sheet, so a shell can still
   override a component locally. Everything here is written against tokens.
   ========================================================================= */

/* ---- Locked navigation ---------------------------------------------------
   A tab the account's plan does not include must SAY so before it is clicked.
   The Sales Engine sub-nav previously rendered all five tabs identically, so a
   Foundation client clicked "Sales Closer" and was met with a lock screen they
   had no warning about — rubric point 3, a dead end with no signposting.

   The link is deliberately still a link: the lock screen explains what the
   capability is and which plan includes it, which is a better answer than a
   disabled control that does nothing at all. What changes is that the client
   can see the difference first. */
.subnav__item.is-locked{
  color: var(--ink-3, #8E8779);
  opacity: .72;
}
.subnav__item.is-locked:hover{ opacity: 1; }
.subnav__lock{
  display: inline-block;
  margin-left: var(--space-3, 6px);
  font-size: var(--fs-cap, 11px);
  line-height: 1;
  color: var(--brass-600, #A08149);
  vertical-align: baseline;
}
.subnav__item.is-locked:hover .subnav__lock{ color: var(--brass-400, #D2B378); }

/* ---- Named patterns that were being hand-copied --------------------------
   Measured 2026-07-26: 1,630 inline style= attributes across 117 of 136
   templates carry the design instead of the stylesheets. The worst are not
   one-offs, they are components without a name — the same declaration pasted
   dozens of times, drifting a little each time. Naming one removes every copy
   at once and gives the next author something to reach for.

   Specificity note, learned the hard way: both shells define `.shell .reason`
   with DIFFERENT values — ledger.css:1358 is 17px/64ch, desk.css:87 is
   --fs-row/74ch — and that selector is (0,2,0). A modifier written as
   `.reason.reason--lede` is ALSO (0,2,0), so it ties and loses to whichever
   sheet loads last, which is the shell. Measured in the browser: the lede
   rendered at 17px/ink-2/64ch, i.e. the base rule, not the modifier. It needs
   `.shell .reason.reason--lede` (0,3,0) to win. Anything added here that
   overrides a shell rule must clear the shell's specificity, not match it. */

/* Hand-copied 35 times as
   `style="max-width:80ch;margin-top:2px;font-size:19px;color:var(--ink-1);"`.
   The section lede: one sentence under a heading saying what the page is for.
   NOT folded into `.reason` itself — 35 other `.reason` elements carry no
   inline style at all and would have moved. */
.shell .reason.reason--lede,
.reason.reason--lede{
  max-width: 80ch;
  margin: var(--space-1, 2px) 0 0;
  font-size: var(--fs-title, 19px);
  line-height: var(--lh-normal, 1.55);
  color: var(--ink-1, #E7E1D5);
}
/* The deliberate pull-up when the lede sits directly under a subnav (four
   Sales-Engine operator pages hand-wrote margin:-16px inline for this). Both
   forms declared so the .shell form is (0,4,0) and clears the lede's (0,3,0)
   whatever the order; a utilities.css class would be (0,2,0) and LOSE. */
.shell .reason.reason--lede.reason--lede-tight,
.reason.reason--lede.reason--lede-tight{ margin-top: -16px; }
/* `.reason--lead` (desk.css) was a near-twin of `--lede` with a different
   look — 16px + a brass left rule — used on adjacent Sales Engine pages for
   the SAME section-lede role. One role, one voice: this alias carries the
   --lede declarations so both spellings render identically. padding/border
   are zeroed EXPLICITLY: desk.css loads after this sheet and its (0,2,0)
   .shell .reason--lead still supplies the brass rule for any property this
   (0,3,0) alias stays silent on. desk.css:75 itself is untouched — it is one
   of the mega-lines where a `.shell ` prefix crosses the newline, and editing
   mid-file there severs rules. */
.shell .reason.reason--lead,
.reason.reason--lead{
  max-width: 80ch;
  margin: var(--space-1, 2px) 0 0;
  font-size: var(--fs-title, 19px);
  line-height: var(--lh-normal, 1.55);
  color: var(--ink-1, #E7E1D5);
  padding-left: 0;
  border-left: 0;
}

/* Hand-copied 48 times as `style="color:var(--danger);"`. A state, not a
   layout tweak, so it deserves a name it can be searched by.

   These replaced an inline style, which outranked everything. A bare
   `.txt-danger` is only (0,1,0), so any `.shell .something` rule already
   colouring that element would now win and the state would silently vanish.
   Scoped forms included for the same reason as the lede above. */
.shell .txt-danger, .txt-danger{ color: var(--danger, #E0806C); }
.shell .txt-warn,   .txt-warn{ color: var(--warn, #D9A441); }
.shell .txt-ok,     .txt-ok{ color: var(--ok, #8CD9AD); }
.shell .txt-quiet,  .txt-quiet{ color: var(--ink-3, #8E8779); }

/* ---- Tile list -----------------------------------------------------------
   desk.css defines .tile__k, .tile__lead and .tile__body and NO list styling at
   all — there is no `ul` rule in the entire stylesheet. Sales Research renders
   the account's search queries as a list, so the class it needs is added here
   rather than invented in a template and left unstyled. Scoped past .shell for
   the reason recorded at the top of this file. */
.shell .tile__list, .tile__list{
  margin: var(--space-5, 10px) 0 0;
  padding-left: 1.15em;
  list-style: disc;
}
.shell .tile__list li, .tile__list li{
  font-size: var(--fs-dense, 14px);
  line-height: var(--lh-normal, 1.55);
  color: var(--ink-2, #B6AFA3);
  margin: 0 0 var(--space-2, 4px);
}

/* ---- Empty state ---------------------------------------------------------
   templates/bl/components/_premium.html:39 defines a genuinely good emptystate
   macro — headline, detail, and a link so the state is not a dead end — and 17
   templates call it. But `.empty-state` was defined ONLY in ledger.css (four
   rules at :926) and NOWHERE in desk.css, so every client desk page that used
   the macro rendered it completely unstyled: a bare heading and a paragraph
   floating with no card, no padding, no border.

   That is this repo's most expensive recurring trap — correct CSS in the wrong
   stylesheet renders as nothing while every markup test still passes, because
   the markup IS right. Shared components belong here, where both shells get
   them.

   Values reproduced from ledger.css exactly so the operator console does not
   move; components.css loads before the shell sheet, so ledger's own copy
   still wins there and this only fills the gap on the desk. */
.empty-state{
  border: 1px solid var(--hairline, #26232B);
  padding: var(--space-16, 32px) var(--space-14, 28px);
  text-align: center;
  border-radius: var(--r-surface, 12px);
  background: var(--paper-0, #121115);
}
.empty-state__title{
  margin: 0;
  color: var(--ink-0, #F4EFE4);
  font-family: var(--serif, Georgia, serif);
  font-weight: 500;
  font-size: 1.25rem;           /* 20px — ledger's value, kept so admin holds */
  line-height: var(--lh-snug, 1.3);
  letter-spacing: -0.005em;
  text-transform: none;
}
.empty-state__detail{
  max-width: 54ch;
  margin: var(--space-4, 8px) auto 0;
  font-size: var(--fs-row, 15px);
  color: var(--ink-2, #B6AFA3);
  line-height: var(--lh-relaxed, 1.6);
}
.empty-state .textlink{ display: inline-block; margin-top: var(--space-7, 14px); }

/* ---- emptystate macro ----------------------------------------------------
   templates/bl/components/_premium.html's emptystate() macro is called by 17
   templates and styled every one of them with four inline declarations. Those
   move here so the empty state is a component rather than a hand-written card.

   Values reproduced exactly from the inline styles they replace, so nothing
   moves: the heading clamp was clamp(1.6rem,2.4vw,2.1rem), the detail was
   margin:0 with max-width:62ch, the action row was margin:18px 0 0.

   Scoped past `.shell` for the reason recorded above — the shells define
   `.decision__title` and `.reason` at (0,2,0), and these replaced inline
   styles that outranked everything. */
/* The .emptystate__* rules that lived here are GONE, not orphaned: the macro no
   longer emits that markup. templates/bl/components/_premium.html's emptystate()
   now delegates to the purpose-built empty_state component above, so all 44 call
   sites across both macros render one treatment and .empty-state is the only
   empty-state styling in the product. Dead CSS removed in the same change that
   made it dead, rather than left to be puzzled over later. */

/* ---- Destructive confirmation -------------------------------------------
   Paired with the `data-confirm` handler in components.js. The inline
   confirmation replaces the control in place rather than opening a modal, so
   it works without a dialog polyfill and cannot be dismissed by accident. */
.confirmbar{
  display: inline-flex; align-items: center; gap: var(--space-4, 8px);
  padding: var(--space-3, 6px) var(--space-5, 10px);
  border: 1px solid var(--danger-a40, rgba(224,128,108,.40));
  background: var(--danger-a12, rgba(224,128,108,.12));
  border-radius: var(--r-control, 8px);
}
.confirmbar__q{
  font-size: var(--fs-meta, 12.5px);
  line-height: var(--lh-snug, 1.35);
  color: var(--ink-1, #E7E1D5);
}
.confirmbar__yes, .confirmbar__no{
  font: inherit; font-size: var(--fs-cap, 11px); font-weight: 600;
  cursor: pointer; padding: 5px 10px;
  border-radius: var(--r-control, 8px);
  border: 1px solid var(--hairline-2, #3B3742);
  background: transparent; color: var(--ink-2, #B6AFA3);
}
.confirmbar__yes{
  border-color: var(--danger-a40, rgba(224,128,108,.40));
  color: var(--danger, #E0806C);
}
.confirmbar__yes:hover{ background: var(--danger-a12, rgba(224,128,108,.12)); }
.confirmbar__no:hover{ color: var(--ink-0, #F4EFE4); }
.confirmbar :focus-visible{
  outline: 2px solid var(--brass-300, #DFC791);
  outline-offset: 2px;
}

/* Flash variants — WHY THEY ARE NOT IN THIS FILE ---------------------------
   `flash flash--{{ category }}` is rendered by the desk shell, which defaults
   the category to `info`. Measured 2026-07-27: app.py flashes "warning" from 11
   call sites and "info" from 2, while `.flash--warning` existed only in
   ledger.css and `.flash--info` in no sheet at all — so on the client desk a
   warning was indistinguishable from a success notice.

   The first attempt declared both HERE and failed twice over, which is the
   lesson worth keeping:

   1. An asterisk-slash pair inside the explanatory comment (it named the warn
      token family with a trailing wildcard, immediately followed by a slash)
      closed the comment early, so the rest of the sentence became the rule's
      SELECTOR and every browser dropped the rule. NEVER let those two
      characters sit together inside a comment — including in a comment that is
      warning you about it, which is how this very block broke a second time.
      Caught with tinycss2.
   2. Even once parsing, `.flash--warning` here is (0,1,0) — identical to
      desk.css's `.flash` base rule, which loads LATER. Equal specificity means
      the later sheet wins, so the base kept supplying border/background/colour
      and the variant still did nothing. Caught by reading getComputedStyle in
      a real browser, which is the only thing that would have caught it.

   Raising the specificity here would have been wrong as well: ledger.css styles
   `.flash--warning` in its own left-accent grammar, and a (0,2,0) rule in this
   shared file would have dragged the operator console into the desk treatment.
   A per-shell variant belongs in the per-shell sheet — see the end of desk.css
   and ledger.css beside its `--success`/`--error` siblings. */

/* Severity badge tones the sheets never declared ---------------------------
   bl_context emits 13 distinct badge slugs. Measured 2026-07-27: ten of them
   have a `.badge--<slug>` rule in BOTH desk.css and ledger.css, and three have
   one in neither — `high`, `med`, `low`. Those three are the severity scale:
   bl_risk() returns low/med/high for every docket, and BL_ACCOUNT_FILE_BADGES
   maps the two WORST account-file states ("Blocked", "Missing acceptance") onto
   `high`. So the more serious the state, the more likely it rendered as a bare
   unstyled pill — the exact inversion of what a severity colour is for. Tones
   reuse the existing semantic tokens so these sit in the same family as
   .badge--warn / .badge--escalated rather than introducing a new palette. */
.badge--high{ color: var(--danger, #E0806C); background: var(--danger-a12, rgba(224,128,108,.12)); border-color: var(--danger-a40, rgba(224,128,108,.40)); }
.badge--med{ color: var(--warn, #D9A441); background: var(--warn-a12, rgba(217,164,65,.12)); border-color: var(--warn-a40, rgba(217,164,65,.40)); }
.badge--low{ color: var(--ink-3, #8A8577); background: var(--ink-a04, rgba(244,239,228,.04)); border-color: var(--hairline-2, rgba(244,239,228,.12)); }

/* ============================================================================
   THE PAGE HEADER — one component, every dashboard page
   ----------------------------------------------------------------------------
   Measured live 2026-07-27 at 1280px on the deployed head, by reading
   getComputedStyle on the real rendered pages rather than by reading markup:

       76.0px / 600 / serif   .greet__hi        64 pages (client + operator)
       64.0px / 600 / serif   .pagehead__title  13 pages (client + operator)
       46.1px / 500 / serif   h1.h-serif         9 operator pages on ledger.css
       42.2px / 500 / serif   h1.h-serif         client login, error pages

   Four headers. The two on the client desk differ by 12px, so a client moving
   from /client/today to /client/results watches the page title change size for
   no reason they will ever be told. The operator case is worse: /admin/review
   and /admin/operators are one click apart inside the same console and their
   headlines differ by 30 pixels AND a font weight, because the two pages load
   different shells.

   This is now ONE rule with one selector list. The geometry lives in tokens.css
   (--h1-size and friends) so there is a single place to change it, and the
   reasoning for choosing the 64px step over the 76px one is recorded there.

   SPECIFICITY, the trap this repo keeps falling into: both shells wrote
   `.shell .greet__hi` at (0,2,0) and desk.css also carries `.shell a` at
   (0,1,1) for link colour. A bare `.greet__hi` here would be (0,1,0) and lose
   to both — the rule would be correct CSS that renders as nothing. Every
   selector below is therefore written in the scoped + unscoped pair form used
   elsewhere in this file, and the shells' own copies were DELETED in the same
   change rather than left to fight this one.

   `h1.h-serif` is qualified by element on purpose: `.h-serif` is also used on
   <p> inside cards (admin_autopilot, admin_reviews) where it means "serif
   voice", not "page title". Those keep their utility-class sizes. */
.shell .pagehead, .pagehead,
.shell .greet, .greet{
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--space-12, 24px); flex-wrap: wrap;
  margin: 0 0 var(--space-4, 8px);
}
.shell .pagehead__title, .pagehead__title,
.shell .greet__hi, .greet__hi,
/* THE MIGRATION THIS RULE ASSUMED HAD HAPPENED.
   The shells' own `.shell .greet__hi` and `.shell .pagehead__title` copies were
   deleted when this rule was written, but only 19 templates were moved onto
   `h-serif`. Measured on the deployed head 25477306: 69 templates still emit
   `greet__hi` and 13 still emit `pagehead__title`, so 82 pages shipped with an
   h1 that matched NO rule at all and fell back to the browser default. The
   owner saw a dashboard that had got worse, not better.
   Both legacy names are folded into the selector list rather than rewritten
   across 82 templates: one edit, no template risk, and the markup can migrate
   later without a second visual regression. Element-qualified (h1.x) so each
   selector carries the same (0,1,1)/(0,2,1) specificity as h-serif and clears
   desk.css's `.shell a` (0,1,1) exactly as the note below describes. */
.shell h1.h-serif, h1.h-serif,
.shell h1.greet__hi, h1.greet__hi,
.shell h1.pagehead__title, h1.pagehead__title{
  font-family: var(--serif, Georgia, serif);
  font-weight: var(--h1-weight, 600);
  font-size: var(--h1-size, clamp(40px, 5vw, 64px));
  line-height: var(--h1-lh, .96);
  letter-spacing: var(--h1-track, .3px);
  color: var(--ink-0, var(--bl-ink-50, #F4EFE4));
  text-wrap: balance;
}
/* Margin is reset in a SEPARATE zero-specificity rule, not in the block above.
   `.shell h1.h-serif` is (0,2,1); every margin utility is (0,2,0); so folding
   `margin:0` into that block would have made this component silently outrank
   utilities.css and kill the spacing on the twelve headings that carry
   `u-mt-8` / `u-mb-12` / `u-m-0` — the login, two-step, recovery-code and error
   screens. `:where()` contributes nothing to specificity, so this only replaces
   the browser default and any utility still wins, which is the contract
   utilities.css is built on. */
:where(.pagehead__title, .greet__hi, h1.h-serif){ margin: 0; }
/* The one italic brass pivot per headline. `.ital` and `.pivot` are the same
   idea under two names — desk.css coined one, ledger.css the other — so both
   resolve here instead of only on whichever page you happened to open. */
.shell .pagehead__title .ital, .shell .greet__hi .ital, .shell h1.h-serif .pivot,
.pagehead__title .ital, .greet__hi .ital, h1.h-serif .pivot{
  font-style: italic;
  color: var(--brass-200, var(--bl-gold-300, #EDDFB8));
}
/* The line under the title. Two roles, deliberately kept distinct: a LEAD is a
   sentence explaining the page; a DATE line is meta. Same component, one
   definition each, instead of one per stylesheet. */
.shell .pagehead__lead, .pagehead__lead{
  font-size: var(--fs-body, 16px);
  line-height: var(--lh-normal, 1.6);
  color: var(--ink-1, #E7E1D5);
  margin: var(--space-8, 16px) 0 0;
  max-width: 60ch;
}
.shell .greet__date, .greet__date{
  font-size: var(--fs-note, 13px);
  line-height: var(--lh-snug, 1.35);
  color: var(--ink-3, #8E8779);
  letter-spacing: .02em;
  margin: var(--space-6, 12px) 0 0;
}
@media (max-width: 720px){
  .shell .pagehead, .pagehead, .shell .greet, .greet{
    flex-direction: column; align-items: flex-start; gap: var(--space-6, 12px);
  }
}


/* ============================================================================
   THE SECTION HEADER — one component, both spellings
   ----------------------------------------------------------------------------
   `.sec__*` and `.section__*` were byte-identical on the client desk except for
   ONE declaration: `.section__idx` carried font-variant-numeric:tabular-nums
   and `.sec__idx` did not. So the 01 / 02 / 03 step numerals that run down
   every page rendered in a different figure set depending on which spelling the
   template happened to use — proportional on one page, tabular on the next.
   Templates had already begun papering over it by hand-adding a `tnum` class to
   `.sec__idx` call sites, which is the tell that the component was wrong.

   The operator console on ledger.css carried a third treatment entirely: 15px
   UPPERCASE SANS in --ink-2, against the desk's 24px serif in --ink-0.

   One component now, keeping tabular figures (a vertical column of section
   numbers has to align) and the desk's serif title, which is what the large
   majority of pages carrying a section header already render. */
.shell .sec, .sec,
.shell .section, .section{
  margin-top: 58px; position: relative; display: block; min-width: 0;
  scroll-margin-top: 100px; isolation: isolate;
}
.shell .section:first-of-type, .section:first-of-type{ margin-top: 34px; }
.shell .sec__head, .sec__head,
.shell .section__head, .section__head{
  display: flex; align-items: center; gap: var(--space-8, 16px);
  margin-bottom: var(--space-11, 22px); min-width: 0; flex-wrap: wrap;
}
.shell .sec__idx, .sec__idx,
.shell .section__idx, .section__idx{
  font-family: var(--sans);
  font-size: var(--fs-meta, 12.5px);
  color: var(--brass-500, var(--bl-gold-500, #C9A96E));
  letter-spacing: .1em;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  font-weight: 400;
  line-height: 1;
  flex: none;
}
.shell .sec__title, .sec__title,
.shell .section__title, .section__title{
  font-family: var(--serif, Georgia, serif);
  font-size: var(--fs-section, 24px);
  font-weight: 600;
  color: var(--ink-0, #F4EFE4);
  letter-spacing: .3px;
  line-height: var(--lh-snug, 1.35);
  text-transform: none;
}
.shell .sec__line, .sec__line,
.shell .section__line, .section__line{
  flex: 1; height: 1px; min-width: 0; align-self: center; border-radius: 1px;
  background: linear-gradient(90deg, var(--hairline-2, #3B3742), transparent);
}


/* ============================================================================
   THE BUTTON — one geometry, every dashboard
   ----------------------------------------------------------------------------
   The primary action was implemented four times: site.css (.site .btn--primary,
   the public home), black-label.css (.bl-btn--primary, /pricing and /checkout),
   desk.css and ledger.css. Measured live on the deployed head:

       radius 12px  14px/500  padding 12/20  ivory gradient   desk pages
       radius 12px  14px/500  padding 12/20  ivory gradient   ledger + body.op3d
       radius  8px  15px/600  padding 0/22   FLAT ivory       client login,
                                                              operator login,
                                                              the error pages,
                                                              /admin/capability-tests
       pill         var       0.7/1.4rem     ivory gradient   /pricing, /checkout

   So the shape genuinely changes on the way in: the button a client presses to
   SIGN IN is a different control from every button behind the login. That third
   row is what this collapses — the sign-in and error surfaces now render the
   same control as the desk they open onto.

   /pricing and /checkout are NOT touched. They are public pages the owner has
   signed off, they load neither tokens.css nor this file, and their pill is a
   genuinely different shape: adopting this geometry would visibly move a page
   that was explicitly declared finished. Recorded here rather than silently
   left as a fifth implementation nobody had written down.

   Geometry is desk.css's, which is already byte-identical to site.css's, so the
   public home does not move either — it simply stops being a coincidence. */
.shell .btn, .btn{
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--space-4, 8px);
  cursor: pointer; text-decoration: none; white-space: nowrap;
  font-family: var(--sans); font-size: var(--fs-dense, 14px); font-weight: 500;
  /* Explicit, because the two shells set different body line-heights (the
     ledger body is 1.62) and `line-height: normal` on the desk. Measured: the
     SAME button rendered 42px tall on /admin/today and 48px on /admin/operators
     purely because of inherited leading. */
  line-height: 1.15;
  letter-spacing: 0; text-transform: none;
  border-radius: var(--r-btn, 12px);
  padding: var(--space-6, 12px) var(--space-10, 20px);
  min-height: 0; height: auto;
  /* The BASE button is the quiet button. desk.css previously expressed this
     with `.shell a.btn:not(.btn--primary, .btn--quiet, .btn--text, ...)` — a
     selector that had to list every colour modifier by hand, and that existed
     only on the desk, so `<button class="btn">` rendered as a real control on
     the client desk and as bare text on the operator console. Saying it once,
     here, is the same intent without the trapdoor. */
  border: 1px solid var(--hairline-2, #3B3742);
  color: var(--ink-1, #E7E1D5);
  background: var(--ink-a04, rgba(244,239,228,.04));
  transition: transform var(--dur-normal, 200ms) var(--ease),
              box-shadow var(--dur-slow, 320ms) var(--ease),
              background-color var(--dur-slow, 320ms) var(--ease),
              color var(--dur-normal, 200ms) var(--ease);
}
/* The base hover is declared FIRST, before any variant, and every variant then
   restates its own colour/border/background. `.shell .btn:hover` and
   `.shell .btn--primary:hover` are both (0,3,0) — a tie broken only by source
   order — so a base hover written after the variants would repaint the ivory
   primary button brass on mouseover, and a variant that listed only
   `transform` would lose its fill. Order and explicitness, not specificity
   games. */
.shell .btn:hover, .btn:hover{
  color: var(--ink-0, #F4EFE4);
  border-color: var(--brass-a45, rgba(201,169,110,.45));
  background: var(--brass-a08, rgba(201,169,110,.08));
  transform: translateY(-1px);
}
/* Law kept from both shells: the one filled action per screen is IVORY, never
   brass. Brass stays money / active / focus. */
.shell .btn--primary, .btn--primary{
  color: var(--btn-ink, #191307);
  background: linear-gradient(180deg, var(--action-top, #FBF7EE), var(--ink-1, #E7E1D5));
  border-color: transparent;
  box-shadow: var(--edge-top), 0 12px 26px -14px rgba(0,0,0,.9);
}
.shell .btn--primary:hover, .btn--primary:hover{
  color: var(--btn-ink, #191307);
  background: linear-gradient(180deg, var(--action-hover, #FFFFFF), var(--action, #F1EDE4));
  border-color: transparent;
  transform: translateY(-2px);
  box-shadow: 0 18px 34px -14px rgba(0,0,0,.9);
}
.shell .btn--quiet, .btn--quiet{
  color: var(--ink-1, #E7E1D5);
  background: var(--ink-a04, rgba(244,239,228,.04));
  border-color: var(--hairline-2, #3B3742);
}
.shell .btn--quiet:hover, .btn--quiet:hover{
  color: var(--ink-0, #F4EFE4);
  border-color: var(--brass-a45, rgba(201,169,110,.45));
  background: var(--brass-a08, rgba(201,169,110,.08));
  transform: translateY(-1px);
}
.shell .btn--ghost, .btn--ghost{
  color: var(--ink-1, #E7E1D5); background: rgba(18,17,21,.5);
  border-color: var(--hairline-2, #3B3742); backdrop-filter: blur(8px);
}
.shell .btn--ghost:hover, .btn--ghost:hover{
  color: var(--ink-0, #F4EFE4);
  border-color: var(--brass-a45, rgba(201,169,110,.45));
  background: var(--brass-a08, rgba(201,169,110,.08));
  transform: translateY(-1px);
}
.shell .btn--danger, .btn--danger,
.shell .btn--danger-ghost, .btn--danger-ghost{
  color: var(--danger, #E0806C);
  background: var(--danger-wash, rgba(224,128,108,.12));
  border-color: var(--danger-edge, rgba(224,128,108,.40));
}
.shell .btn--danger:hover, .btn--danger:hover,
.shell .btn--danger-ghost:hover, .btn--danger-ghost:hover{
  color: var(--danger, #E0806C);
  background: rgba(224,128,108,.2);
  border-color: var(--danger, #E0806C);
  transform: translateY(-1px);
}
/* Aligned to the ledger treatment on purpose: 27 of the 33 .btn--text call
   sites in the product were already the underlined text link, and the control
   has to mean one thing. */
.shell .btn--text, .btn--text{
  border: 0; padding: var(--space-3, 6px) var(--space-2, 4px);
  background: transparent; color: var(--ink-3, #8E8779);
  text-decoration: underline; text-underline-offset: 5px;
  text-decoration-color: var(--hairline-strong, #3B3742);
}
.shell .btn--text:hover, .btn--text:hover{
  color: var(--ink-1, #E7E1D5); background: transparent; transform: none;
  border-color: transparent;
  text-decoration-color: var(--brass-a45, rgba(201,169,110,.45));
}
.shell .btn--sm, .btn--sm{
  padding: 9px 15px; font-size: var(--fs-note, 13px); border-radius: 10px;
}
.shell .btn--lg, .btn--lg{
  padding: var(--space-7, 14px) var(--space-12, 24px); font-size: var(--fs-row, 15px);
}
.shell .btn:focus-visible, .btn:focus-visible{
  outline: var(--focus-ring, 2px solid #C9A96E); outline-offset: 2px;
}
.shell .btn[disabled], .btn[disabled], .shell .btn.is-disabled, .btn.is-disabled{
  opacity: .45; cursor: not-allowed; transform: none; box-shadow: none;
}
.act-form{ display: inline-flex; margin: 0; padding: 0; border: 0; background: none; }


/* ============================================================================
   THE EYEBROW — the kicker directly above the page title
   ----------------------------------------------------------------------------
   It sits one line above the header this file just unified, and it was three
   controls: 11px brass small-caps with a brass rule before it on the desk;
   14px semibold sans in --ink-2, sentence case, no rule, on the ledger shell;
   and 11px --ink-3 caps as `.brief__eyebrow`. Measured on the operator console:
   /admin/today rendered "GCS Operating Layer" at 11px brass caps and
   /admin/operators rendered "Admin · Operators" at 14px grey sentence case,
   directly above two headings that are now identical. Unifying the h1 and
   leaving this would have made the mismatch MORE obvious, not less.

   desk.css already carried a comment reading "ledger redefines it as a sans
   meta row - restore the Emergent form" — the intent to unify was there; what
   was missing was a shared place to put it. */
.shell .eyebrow, .eyebrow,
.shell .brief__eyebrow, .brief__eyebrow{
  display: inline-flex; align-items: center; gap: var(--space-4, 8px);
  font-family: var(--sans);
  font-size: var(--fs-cap, 11px);
  font-weight: 400;
  letter-spacing: .28em;
  text-transform: uppercase;
  color: var(--brass-300, var(--bl-gold-300, #DFC791));
  line-height: 1.2;
}
.shell .eyebrow::before, .eyebrow::before,
.shell .brief__eyebrow::before, .brief__eyebrow::before{
  content: ""; width: 26px; height: 1px; flex: none;
  background: linear-gradient(90deg, var(--brass-500, #C9A96E), transparent);
}
/* A pip replaces the rule where the eyebrow leads with a status dot. */
.shell .eyebrow:has(.pip)::before, .eyebrow:has(.pip)::before{ content: none; }
:where(.eyebrow, .brief__eyebrow){ margin: 0 0 var(--space-6, 12px); }

/* ============================================================================
   RADIO SET — a bare fieldset for a row of choices
   ----------------------------------------------------------------------------
   desk.css:463 gives every <fieldset> a border, radius and padding, which is
   right for a bordered form section and wrong for a plain group of radios — so
   the one template that needed a bare group undid all three with inline styles,
   the exact thing the design standard forbids. Named here instead.
   `.shell .radioset` is (0,2,0) and beats desk.css's `.shell fieldset` (0,1,1)
   on class count, so load order does not matter. */
.shell .radioset, .radioset{ border: 0; padding: 0; margin: 0 0 var(--space-10, 20px); }
.shell .radioset > legend, .radioset > legend{ padding: 0; margin: 0 0 var(--space-5, 10px); }
.shell .radioset__opts, .radioset__opts{
  display: flex; flex-wrap: wrap; gap: var(--space-5, 10px) var(--space-6, 12px);
}

/* ============================================================================
   BACK NAVIGATION — one treatment for every detail page
   ----------------------------------------------------------------------------
   Measured 2026-07-27: five client detail surfaces used five different back
   treatments — a .link with an inline-rotated →, a .btn--text with a literal ←,
   a .link with &larr; inside an inline-styled paragraph, a solid .btn--quiet
   with no arrow, and one page with no way back at all. One component, arrow
   supplied by the stylesheet so no template carries a glyph. Quiet by design:
   a back link is never the page's action. */
.shell .backlink, .backlink{
  display: inline-flex; align-items: baseline; gap: 6px;
  font-size: var(--fs-note, 13px);
  letter-spacing: .02em;
  color: var(--ink-2, #B6AFA3);
  text-decoration: none;
  transition: color .15s ease;
}
.shell .backlink::before, .backlink::before{ content: "\2190"; }
.shell .backlink:hover, .backlink:hover{ color: var(--ink-0, #F4EFE4); }
.shell .backlink:focus-visible, .backlink:focus-visible{
  outline: 2px solid var(--brass-300, #DFC791);
  outline-offset: 2px;
}
