/* ══════════════════════════════════════════════════════════════════════════
   bwui-components.css — the component layer.
   Load order: tokens → base → COMPONENTS → (docs | portal) → thin per-property.

   WHAT THIS FILE IS
     Every shared component in SPEC.md §4, namespaced .bwui-. The atom is
     .bwui-lrow — the statement line. The guide's chapter list, the ticket
     list, the seat table, the search result and the licence summary are that
     one component with different cells filled in (§1, §4.0).

   WHAT THIS FILE MUST NEVER CONTAIN
     · A --bw-* token declaration. bwui-tokens.css is the only file that may
       declare one (lint T1) — with NO hand-carved exceptions, so the lint is
       one unconditional grep for `--bw-[a-z]` outside the tokens file.
       Component-LOCAL channel properties are --bwui-*: the callout/tag triple
       (§4.3), the figure's scaling triple (§4.12) and the mark's size (§4.13).
       Those three were --bw-fig-* / --bw-mark until 2026-07-26, which is 33
       declarations that made the rule unwritable as stated.
     · A raw hex. One exception, mandated by SPEC §9 trade-off 5: the figure
       frame's literal #FFFFFF ground.
     · A theme. Dark is resolved entirely in bwui-tokens.css.
     · A rejected idiom: border-left/right rails ≥2px, inset accent bars on
       active items, gradients, backdrop-filter, a heading that does not
       outrank body copy, or a figure that scrolls.
     · An element rule that bwui-base.css already owns. code/pre/kbd/hr/table
       and .bwui-rule-total live in base; only the DRESSED forms are here.

   CONTRAST
     Every text colour states its computed WCAG 2.1 ratio against the ground
     it actually sits on, taken from SPEC §2.4. Light figure first; where a
     component is theme-sensitive the dark figure follows. Fill-only tokens
     (--bw-green 2.63 on paper / 2.90 on surface, --bw-faint 2.85 on paper /
     3.14 on surface, --bw-flag) carry no type here — the figures name the
     grounds these tokens actually touch, and the FIRST of each pair is the
     one that applies in this file.

   SPACE / RADIUS
     Every margin and padding is 0 or a --bw-s* step. Where SPEC §4 writes a
     literal (.bwui-btn 0.75rem 1.5rem, .bwui-field 0.75rem 1rem, .bwui-tag
     0.25rem 0.5rem, .bwui-key 0.25rem 0.5rem) the literal is EXACTLY a ladder
     step, so the token is used instead — identical rendering, and lint P1's
     three named exceptions stop being needed. Radii are the four-step ladder;
     the two shapes that cannot be (.bwui-tag::before 50%, .bwui-mark i 999px)
     are called out where they appear.
   ══════════════════════════════════════════════════════════════════════════ */


/* ══ THE PAGE WRAP ═══════════════════════════════════════════════════════
   NOT IN SPEC §4 as a named component, and it should have been: SPEC §4.16
   already writes `.bwui-app > .bwui-wrap`. The single left edge is the
   library's central structural claim (§2.3, §5.3), and until now the library
   shipped no way to obtain one — the header, the footer, the footer base and
   the doc grid each re-typed the same three declarations, and the gallery
   invented a fourth copy (.gal-wrap). Four copies of a structural rule is
   exactly how "four left edges at 112 / 200 / 336 / 472" happened the first
   time.

   ONE gutter, one max-width, one centring. Anything that needs a different
   vertical padding sets padding-BLOCK; nothing overrides padding-inline.   */
.bwui-wrap,
.bwui-head__in,
.bwui-foot__in,
.bwui-foot__base,
.bwui-doc{
  max-width:var(--bw-wrap);
  margin-inline:auto;
  padding-inline:var(--bw-pad);
}


/* ══ 4.0 — .bwui-lrow · THE STATEMENT LINE ════════════════════════════════
   The atom. One primitive renders: the guide's chapter list, the FAQ question
   index, a search result, a ticket row, a seat row, the staff queue and the
   export summary. Because navigation and data are literally the same object,
   the two properties cannot drift stylistically without drifting structurally.

   Two shapes:
     two-cell  [reference][description]                    — navigation
     four-cell [reference][description][leader][figure]    — data

   NO CONTAINER. No rail, no card, no background, no hover tint on the row
   itself, no translate. Every rejected attempt so far failed as a container;
   there is nothing here for an accent bar to be added to.                  */

.bwui-lrow{
  display:grid;
  grid-template-columns:var(--bwui-ref-w,1.75rem) minmax(0,1fr);
  column-gap:var(--bw-s3);
  align-items:center;
  min-height:2.75rem;                    /* 44px touch target */
  padding:var(--bw-s1) 0;
  font-size:var(--bw-t-small);
  line-height:var(--bw-lh-ui);
  color:var(--bw-muted);                 /* 7.67:1 paper · 8.46:1 surface */
  text-decoration:none;
}

/* THE FIGURE FORM. The leader track is minmax(--bw-lead-min,1fr) — a HARD
   120px minimum run. A dot leader carries the eye across a long gap to a real
   figure; at 30px it connects nothing and becomes costume. If the row cannot
   afford 120px of leader, the row does not get a leader — and that rule is
   IMPLEMENTED, at the 34rem breakpoint below §4.7, not merely asserted here.
   Lint L1 fails on any .bwui-lead outside .bwui-lrow--fig, and .bwui-lrow--fig
   is banned inside .bwui-stub.                                             */
.bwui-lrow--fig{
  grid-template-columns:var(--bwui-ref-w,3.25rem) minmax(0,auto)
                        minmax(var(--bw-lead-min),1fr) auto;
}

/* THE REFERENCE CELL. Mono at the 11px label floor — a label, never a
   heading. It is also the cell that carries "current" (see .is-here), which
   is why it exists on every row whether or not it is promoted.             */
.bwui-lrow__ref{
  font-family:var(--bw-mono);
  font-variant-numeric:tabular-nums;
  font-size:var(--bw-t-label);
  letter-spacing:.04em;
  color:var(--bw-muted);                 /* 8.46:1 surface · 7.67:1 paper */
  display:grid;
  place-items:center;
  min-width:1.75rem;
  height:1.5rem;
  border-radius:var(--bw-r-xs);
  transition:background .15s, color .15s;
}

/* THE DESCRIPTION CELL. min-width:0 so a long label shrinks rather than
   blowing the grid out; overflow-wrap so a URL-shaped token breaks.        */
.bwui-lrow__t{
  color:var(--bw-ink2);                  /* 16.42:1 paper · 18.10:1 surface */
  min-width:0;
  overflow-wrap:anywhere;
  transition:color .15s;
}

/* THE DOTTED LEADER — one of the system's two ornaments, and the ONLY legal
   use of --bw-faint (3.14:1, decoration; it carries no word a person reads). */
.bwui-lead{
  height:0;
  align-self:center;
  border-bottom:1px dotted var(--bw-faint);
}

/* THE FIGURE CELL. Tabular mono so digits stack in a column down the list —
   a date, an amount, a seat count, a ticket age.                           */
.bwui-lrow__fig{
  font-family:var(--bw-mono);
  font-variant-numeric:tabular-nums;
  font-size:var(--bw-t-mono);
  color:var(--bw-muted);                 /* 8.46:1 surface · 7.67:1 paper */
  white-space:nowrap;
}
/* A figure that is money or a count reads at the 15px figure step, not 12px.
   Amount colours match the data table (§4.6) so a row and a table agree.   */
.bwui-lrow__fig--amt{font-size:var(--bw-t-fig);color:var(--bw-ink2)} /* 18.10:1 */
.bwui-lrow__fig--credit{color:var(--bw-green-deep)}                  /*  5.53:1 */
.bwui-lrow__fig--debit{color:var(--bw-warn-ink)}                     /*  6.71:1 */

/* LINK STATE. Only an <a> reacts. A static row (the current chapter renders
   as <span aria-current="page">, a read-only seat line) is inert by
   construction — the selectors below cannot reach it.                      */
a.bwui-lrow:hover .bwui-lrow__t{color:var(--bw-ink)}          /* 17.86:1 paper */
a.bwui-lrow:hover .bwui-lrow__ref{
  background:var(--bw-mint);             /* ORNAMENT FILL — one of its two jobs */
  color:var(--bw-ink);                   /* 16.04:1 light · 10.47:1 dark. (14.75
                                            is the --bw-ink2 figure, quoted here
                                            by inheritance from the token file.) */
}
a.bwui-lrow:hover .bwui-lead{border-bottom-color:var(--bw-muted)}
/* Focus is ONE treatment for the whole company and it is declared once, on
   :focus-visible in bwui-base.css. It was restated here and on .bwui-card--go
   with byte-identical values, which is three places to edit and two to forget. */

/* CURRENT — SUBSTITUTIVE, NOT ADDITIVE. The reference cell that is already on
   every row is PROMOTED to a filled marker; nothing new appears on the page.
   No left bar, no inset stripe, no row background, no translate.
   Three redundant channels — a filled 24px shape, a 700 weight, and a colour
   jump to full --bw-ink — so it survives greyscale, colour-blindness and a
   cheap panel at arm's length. It is the HIGHEST-contrast row in the column,
   not the lowest. Current + hover is deliberately identical to current: it is
   where you are, not a destination.                                        */
.bwui-lrow.is-here .bwui-lrow__ref{
  background:var(--bw-green-deep);
  color:var(--bw-on-green);              /* 5.53:1 light · 11.90:1 dark */
}
.bwui-lrow.is-here .bwui-lrow__t{
  color:var(--bw-ink);                   /* 17.86:1 paper */
  font-weight:var(--bw-w-bold);
}

/* A closed row — the last line of a licence summary or an export readout,
   sitting under the double rule. It totals; it does not navigate.          */
.bwui-lrow--total .bwui-lrow__t{color:var(--bw-ink);font-weight:var(--bw-w-semi)}
.bwui-lrow--total .bwui-lrow__fig{
  font-size:var(--bw-t-fig);
  font-weight:var(--bw-w-bold);
  color:var(--bw-ink);                   /* 17.86:1 paper */
}

/* THE DOUBLE RULE is <hr class="bwui-rule-total"> and lives in bwui-base.css
   (SPEC §3.2) — it is not redeclared here. It appears ONLY above a total:
   a <tfoot> row, the foot of the stub's chapter COUNT, the foot of the
   licence seat count. Three or fewer per page (lint B3). A reading position
   is not a total, so it never marks one. The table-cell form of the same
   1/1/1 geometry is at §4.6 below.                                         */


/* ══ 4.1 — BUTTONS ═══════════════════════════════════════════════════════
   One construction, ONE hover gesture: ink ground → green-deep, a 1px lift,
   a green-tinted shadow. 44px minimum target everywhere.

   2026-10-14 (the stylesheet convergence, owner ruling): ONE spec, TWO sizes
   (44 and 52), FOUR variants (primary, ghost, quiet, danger-quiet). The
   portal's .btn, .btn.small, .copy, .mode-btn, .acc-btn, .attach-btn and
   .print-btn were nine heights and seven shapes; every one is now this
   class. A "small" button is the 44 size with less horizontal padding
   (--compact); an icon-only button is .bwui-iconbtn, 44 by 44. The --soft
   and --danger roles were deleted (no page used them and the ruling names
   four); --sm was deleted because 36px is under the house target.         */

/* 2026-10-14, owner ruling (keep the current look): the approved portal's
   button, 14 / 22 padding (45px tall, over the 44px floor), and a label
   that may wrap on a phone rather than run off the card. */
.bwui-btn{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  gap:var(--bw-s2);
  font-family:var(--bw-sans);
  font-weight:var(--bw-w-semi);
  font-size:var(--bw-t-small);
  line-height:1;
  padding:calc(var(--bw-s3) + var(--bw-s0)) calc(var(--bw-s5) - var(--bw-s0));
  min-height:2.75rem;                    /* 44px, everywhere */
  border:1px solid transparent;
  border-radius:var(--bw-r-btn);
  cursor:pointer;
  text-decoration:none;
  list-style:none;                       /* a <summary> may carry the class */
  transition:background .2s, border-color .15s, color .15s,
             transform .15s, box-shadow .15s;
}
.bwui-btn::-webkit-details-marker{display:none}
.bwui-btn svg{flex:none}

/* PRIMARY — the house gesture. Ink at rest, green-deep on hover.
   THE LABEL FOLLOWS ITS GROUND. --bw-ink is theme-following (#0B0B0B light,
   #F5F3EC dark) so its partner must be too: --bw-paper inverts in lockstep.
   Pairing it with --bw-on-ink, which is pinned to the theme-INDEPENDENT
   --bw-ink-panel ramp, computed 1.00:1 in dark — the same near-white hex on
   itself, a blank slab with an invisible label — and 1.00:1 in print.
   Do NOT "fix" this the other way, by making the FILL --bw-ink-panel: that
   reads 17.73:1 but leaves a #0B0B0B button on #121110 paper (1.06:1), an
   invisible BUTTON instead of an invisible label.                          */
/* 2026-10-14, owner ruling: the approved label is white on the light ink and
   near-black on the dark theme's light ink, which is --bw-on-green in both
   (19.68:1 light, 16.99:1 dark), and the hover lift is the small shadow. */
.bwui-btn--primary{
  background:var(--bw-ink);
  color:var(--bw-on-green);              /* 19.68:1 light · 16.99:1 dark */
  border-color:var(--bw-ink);
}
.bwui-btn--primary:hover{
  background:var(--bw-green-deep);
  border-color:var(--bw-green-deep);
  color:var(--bw-on-green);              /* 5.53:1 light · 11.90:1 dark */
  transform:translateY(-1px);
  box-shadow:var(--bw-sh-sm);
}

/* GHOST: the secondary of a pair. Outlined, never tinted at rest. The
   border is --bw-field-line (2026-10-14): the house rule measures every
   control border at 3:1, and this one is 3.17 light / 3.85 dark on a card;
   --bw-line-strong was 1.37.                                              */
.bwui-btn--ghost{
  background:var(--bw-surface);
  color:var(--bw-ink);                   /* 19.68:1 surface */
  border-color:var(--bw-field-line);
}
.bwui-btn--ghost:hover{
  border-color:var(--bw-ink);
  transform:translateY(-1px);
}

/* QUIET: a tertiary action (Cancel, Clear, Resend). No border at rest, the
   sunk ground on hover. 44px tall whatever the label (2026-10-14).         */
.bwui-btn--quiet{
  background:transparent;
  color:var(--bw-muted);                 /* 7.67:1 paper · 8.46:1 surface */
  font-size:var(--bw-t-ui);              /* 2026-10-14, owner ruling: 14 on */
  padding:calc(var(--bw-s2) + var(--bw-s0)) calc(var(--bw-s3) + var(--bw-s0));  /* 10 / 14 */
}
.bwui-btn--quiet:hover{color:var(--bw-ink);background:var(--bw-sunk)}

/* DANGER-QUIET: destructive, outlined. The ink is the warn channel's own
   text token, never the fill red (--bw-flag as TYPE is 4.19:1 and fails,
   which is exactly why --bw-warn-ink exists).                              */
.bwui-btn--danger-quiet{
  background:transparent;
  color:var(--bw-warn-ink);              /* 6.71:1 on --bw-surface */
  border-color:var(--bw-field-line);
}
.bwui-btn--danger-quiet:hover{border-color:var(--bw-warn-ink)}

/* COMPACT: the same 44px button with less horizontal padding, for a row
   action inside a table or a chip. 2026-10-14, owner ruling (keep the
   current look): the approved small button, 13.5 type on 9 / 15 padding
   with the small radius. */
.bwui-btn--compact{
  font-size:var(--bw-t-note);
  padding:calc(var(--bw-s2) + var(--bw-s0) / 2) calc(var(--bw-s4) - var(--bw-s0) / 2);
  border-radius:var(--bw-r-sm);
}

/* LARGE: the second size, 52px: the one closing action of a form column
   (the sign-in card's buttons) (2026-10-14).                               */
.bwui-btn--lg{min-height:3.25rem;padding-inline:var(--bw-s6)}

/* Full-bleed inside a narrow form column (sign-in, ticket compose). It stays
   inline-flex, as approved (2026-10-14), so its top margin adds to the
   block above it instead of collapsing into it. */
.bwui-btn--block{width:100%}

/* DISABLED is a COLOUR change, never opacity — opacity on text silently
   reduces measured contrast (portal.css's .msg-when opacity:.9 pushes 5.43:1
   down to 4.45:1). Lint C1 fails on `opacity` on any selector that also sets
   `color`.                                                                 */
.bwui-btn[disabled],
.bwui-btn[aria-disabled="true"]{
  background:var(--bw-sunk);
  color:var(--bw-muted);                 /* 8.16:1 on --bw-sunk */
  border-color:var(--bw-line);
  pointer-events:none;
  box-shadow:none;
  transform:none;
}

/* ON AN INK PANEL the pair inverts — an ink button on an ink band is
   invisible. .bwui-cta, .bwui-foot and the sign-in brand half carry
   .bwui-on-ink so this fires. Ratios are against --bw-ink-panel #0B0B0B,
   which does NOT follow the theme.                                         */
/* The FILL here is on-ink (near-white in both themes), so the LABEL must be the
   theme-independent constant too — --bw-ink-panel, not the theme's --bw-ink.
   With --bw-ink the dark ramp put #F5F3EC on #F5F3EC: 1.00:1, and the page's
   one closing action had no label at all.                                   */
.bwui-on-ink .bwui-btn--primary{
  background:var(--bw-on-ink);
  color:var(--bw-ink-panel);             /* 19.68:1 light · 17.73:1 dark */
  border-color:var(--bw-on-ink);
}
.bwui-on-ink .bwui-btn--primary:hover{
  background:var(--bw-on-ink-2);
  color:var(--bw-ink-panel);             /* 12.57:1 on --bw-on-ink-2, both themes */
  box-shadow:none;
}
.bwui-on-ink .bwui-btn--ghost{
  color:var(--bw-on-ink);                /* 19.68:1 on --bw-ink-panel */
  border-color:var(--bw-on-ink-line);
}
.bwui-on-ink .bwui-btn--ghost:hover{
  background:var(--bw-on-ink-wash);
  color:var(--bw-on-ink);
}


/* ══ 4.2 — CARD ══════════════════════════════════════════════════════════
   A white OBJECT YOU ACT ON. The governing rule:
       white = an object · tint = advisory · ink = the action band.
   A navigation card is therefore NEVER tinted — that confusion is what made
   .entry (a primary route) indistinguishable from .callout (an inline note)
   on the current site: same mint fill, same green border, differing only in
   padding.

   A card is never given a top accent bar, a left bar, or a coloured header
   strip. Emphasis comes from ORDER in the grid and from .bwui-card--lead,
   which enlarges the heading one step. No decoration.                      */

/* 2026-10-14, owner ruling (keep the current look): the approved portal's
   card, the large 18px corner and a soft resting shadow in light (the dark
   ramp sets --bw-sh to none, so it is flat there), 28 / 32 inside. The
   panels, the thread head, the message, the sign-in card and the dialog
   set their own padding in portal.css, as they did. */
.bwui-card{
  background:var(--bw-surface);
  border:1px solid var(--bw-line);
  border-radius:var(--bw-r-lg);
  padding:calc(var(--bw-s5) + var(--bw-s1)) var(--bw-s6);
  box-shadow:var(--bw-sh);
  display:block;
  text-decoration:none;
}
/* A card's head: a heading (.h-sub or .h-sec in the portal sheet) over one
   sentence of lede. 20px under it, as approved (2026-10-14).               */
.bwui-card__head{margin-bottom:calc(var(--bw-s4) + var(--bw-s1))}
.bwui-card__head p{
  margin-top:calc(var(--bw-s1) + var(--bw-s0) / 2);   /* 5px */
  font-size:var(--bw-t-ui);
  line-height:var(--bw-lh-note);
  color:var(--bw-muted);                 /* 8.46:1 on --bw-surface */
}
/* A quiet card: the sunk ground, for a block that informs rather than acts
   (the configured owners, the funnel). Flat, as approved (2026-10-14).    */
.bwui-card--sunk{background:var(--bw-sunk);box-shadow:none}
.bwui-card--go{transition:border-color .15s, transform .15s, box-shadow .15s}
.bwui-card--go:hover{
  border-color:var(--bw-line-strong);
  transform:translateY(-1px);
  box-shadow:var(--bw-sh-sm);
}
/* focus: the global :focus-visible in bwui-base.css, not a second copy here */
.bwui-card h3,
.bwui-card h4{margin:0 0 var(--bw-s2)}
/* 2026-10-14, owner ruling: a bare paragraph in a card takes the card's own
   type, as approved; the notes, help lines and ledes name their size and
   their margin (base already zeroes a paragraph's), so nothing here
   overrules them. */
.bwui-card > :last-child{margin-bottom:0}
.bwui-card__go{
  display:inline-flex;
  align-items:center;
  gap:var(--bw-s2);
  margin-top:var(--bw-s3);
  font-size:var(--bw-t-micro);
  font-weight:var(--bw-w-semi);
  color:var(--bw-green-deep);            /* 5.53:1 on --bw-surface */
}
.bwui-card__go::after{content:"\2192"}   /* → */
.bwui-card--lead h3{font-size:var(--bw-t-h3)}

/* Card grid — the hub. auto-fit so the count is the content's business.
   minmax(min(16rem,100%),…): with auto-fit a container NARROWER than the track
   minimum does not shrink the track, it overflows. min() is the self-limiting
   form and costs nothing at any width where the track fits.                 */
.bwui-cards{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(min(16rem,100%),1fr));
  gap:var(--bw-s4);
}


/* ══ PANEL ═══════════════════════════════════════════════════════════════
   NOT IN SPEC §4 — added because the brief names it, and flagged as an
   addition. A card holds ONE object; a panel GROUPS a set of rows or fields
   under a named head (the licence facts block, a seat list, a ticket detail
   pane). It is a card with a sunk head band and unpadded body, so .bwui-lrow
   and .bwui-tbl can run edge to edge inside it. Same bans apply: no accent
   strip, no tint on the body, no shadow at rest.                           */
.bwui-panel{
  background:var(--bw-surface);
  border:1px solid var(--bw-line);
  border-radius:var(--bw-r);
  overflow:hidden;                       /* clips the head band to the radius */
}
.bwui-panel__head{
  display:flex;
  align-items:center;
  gap:var(--bw-s3);
  padding:var(--bw-s3) var(--bw-s5);
  background:var(--bw-sunk);
  border-bottom:1px solid var(--bw-line-strong);
}
.bwui-panel__head h3,
.bwui-panel__head h4{margin:0;font-size:var(--bw-t-h4)}   /* 18px heading floor */
.bwui-panel__meta{
  margin-left:auto;
  font-family:var(--bw-mono);
  font-variant-numeric:tabular-nums;
  font-size:var(--bw-t-mono);
  color:var(--bw-muted);                 /* 8.16:1 on --bw-sunk */
}
.bwui-panel__body{padding:var(--bw-s5)}
.bwui-panel__body > :last-child{margin-bottom:0}
.bwui-panel__foot{
  display:flex;
  gap:var(--bw-s3);
  flex-wrap:wrap;
  padding:var(--bw-s4) var(--bw-s5);
  border-top:1px solid var(--bw-line);
}


/* ══ 4.3 — CALLOUT · FOUR SEVERITIES ═════════════════════════════════════
   An advisory note inside running text. Tinted, fully bordered, NO left bar,
   NO icon tile, NO emoji. The channel is named in mono above the text, so it
   survives greyscale and a screen reader gets the WORD rather than a colour.

   Body copy inside any callout is --bw-ink2: 15.18–16.36:1 on all four light
   fills (note 15.35 · tip 16.29 · caut 16.36 · warn 15.18), and ≥9.17:1 on all
   four dark fills (tip 9.17 · caut 9.64 · note 10.21 · warn 10.50). The dark
   floor was stated as ≥11:1, which is wrong on all four — they pass, but the
   bound did not.

   The --bwui-c-* triple is a component-LOCAL property set on the modifier,
   not a token: --bw-* is the token namespace and stays sealed in
   bwui-tokens.css. This is how one rule body serves four severities without
   four copies of it. The same mechanism is specified for .bwui-flash in
   SPEC §4.16 — which has NOT been authored: there is no portal sheet in this
   phase, and nothing here should be read as saying otherwise.              */

/* The unmodified fallback is declared FIRST, not last: a modifier carries the
   same specificity (0,1,0), so a trailing fallback would win on source order
   and flatten all four severities to note. */
.bwui-callout{--bwui-c-fill:var(--bw-note-fill);--bwui-c-line:var(--bw-note-line);--bwui-c-ink:var(--bw-note-ink)}
/* 2026-10-14, owner ruling (keep the current look): the approved portal's
   callout, the soft corner and 20 / 24 inside, the body at 16px. */
.bwui-callout{
  border-radius:var(--bw-r-btn);
  padding:calc(var(--bw-s4) + var(--bw-s1)) var(--bw-s5);
  border:1px solid var(--bwui-c-line);
  background:var(--bwui-c-fill);
  color:var(--bw-ink2);                  /* ≥15.18:1 on every light fill */
}
.bwui-callout__k{
  display:block;
  font-family:var(--bw-mono);
  font-size:var(--bw-t-label);           /* 11px LABEL — never marked up h1–h6 */
  font-weight:var(--bw-w-semi);
  letter-spacing:.12em;                  /* the approved callout word (2026-10-14) */
  text-transform:uppercase;
  color:var(--bwui-c-ink);               /* 4.98–5.63:1 on its own fill */
  margin-bottom:calc(var(--bw-s2) + var(--bw-s0) / 2);
}
.bwui-callout > :last-child:not(.bwui-callout__x){margin-bottom:0}   /* the dismiss keeps its 44px margins (2026-10-14) */
.bwui-callout p{max-width:none;font-size:var(--bw-t-body)}   /* 16px, as approved */
/* a text link takes the channel ink; a button inside the callout keeps its
   own (2026-10-14: the licence page's Renew button read amber on ink) */
.bwui-callout a:not(.bwui-btn){color:var(--bwui-c-ink);text-decoration-color:currentColor}

.bwui-callout--note{--bwui-c-fill:var(--bw-note-fill);--bwui-c-line:var(--bw-note-line);--bwui-c-ink:var(--bw-note-ink)} /* ink 5.53:1 light · 7.57:1 dark */
.bwui-callout--tip {--bwui-c-fill:var(--bw-tip-fill); --bwui-c-line:var(--bw-tip-line); --bwui-c-ink:var(--bw-tip-ink)}  /* ink 4.98:1 light · 8.42:1 dark */
.bwui-callout--caut{--bwui-c-fill:var(--bw-caut-fill);--bwui-c-line:var(--bw-caut-line);--bwui-c-ink:var(--bw-caut-ink)} /* ink 5.34:1 light · 7.24:1 dark */
.bwui-callout--warn{--bwui-c-fill:var(--bw-warn-fill);--bwui-c-line:var(--bw-warn-line);--bwui-c-ink:var(--bw-warn-ink)} /* ink 5.63:1 light · 7.03:1 dark */

/* THE FLASH (2026-10-14): the same callout laid as one line, the channel word
   at the left, a 44px dismiss at the right. The portal's .flash was a second
   banner spec with the same four fills; it is this modifier now. The word
   and the colour come from one map in the template, so a red banner can
   never carry an info word.                                                */
/* 2026-10-14, owner ruling: the approved banner, 14 / 20 inside, a 10px
   gap, the word at .1em. */
.bwui-callout--flash{
  display:flex;
  gap:calc(var(--bw-s2) + var(--bw-s0));
  align-items:baseline;
  font-size:var(--bw-t-small);           /* the banner's own 15px (2026-10-14) */
  padding:calc(var(--bw-s3) + var(--bw-s0)) calc(var(--bw-s4) + var(--bw-s1));
  margin-bottom:var(--bw-s5);
}
.bwui-callout--flash .bwui-callout__k{margin:0;flex:none;letter-spacing:.1em}
.bwui-callout--flash p{min-width:0;font-size:var(--bw-t-small)}
/* a 44px hit area around a 14px glyph; the negative margins keep the banner
   the height it was */
.bwui-callout__x{
  margin:calc(-1 * var(--bw-s3) - 1 * var(--bw-s0) / 2) calc(-1 * var(--bw-s3) - 1 * var(--bw-s0) / 2) calc(-1 * var(--bw-s3) - 1 * var(--bw-s0) / 2) auto;
  align-self:center;
  width:2.75rem;height:2.75rem;padding:0;
  display:grid;place-items:center;
  background:none;border:0;cursor:pointer;
  color:var(--bw-meta);                  /* 6.5:1 on the lightest fill */
  border-radius:var(--bw-r-sm);
  flex:none;
}
.bwui-callout__x:hover{color:var(--bw-ink)}
/* a callout that carries its one action under the sentence */
.bwui-callout__act{margin-top:calc(var(--bw-s3) + var(--bw-s0));display:flex;gap:calc(var(--bw-s2) + var(--bw-s0));flex-wrap:wrap}   /* 14 / 10, as approved (2026-10-14) */
.bwui-callout p+p{margin-top:var(--bw-s3)}


/* ══ 4.4: THE PILL ══════════════════════════════════════════════════════
   One badge. It was squared (6px) by the convergence; the owner's ruling of
   2026-10-14 (keep the current look) makes it FULLY ROUND again, as the
   approved portal had it (--bw-r-pill).

   2026-10-14 (owner ruling): the component is named .pill, as every portal
   template and smoke test already calls it, and its channels are the
   portal's SIX states, because those are the words the pages use:
       .open    mint      Open · Active · Live · Bought · Cleared
       .wait    amber     Waiting on you / on customer · Clearing · Awaiting
       .closed  neutral   Closed · Reversal · Switched off · Used
       .flag    red       Suspended · Expired · Not set up · Wrong address
       .avail   blue      Available · an open override
       .comp    amber     Complimentary (a KIND, not a live state)
   The licence page's four colours (Active mint, Available blue,
   Complimentary amber, Suspended / Expired red) are these channels.

   THE DOT IS OFF BY DEFAULT and on by class (.pill--dot), and it stays off on
   the licence page whatever the class (portal.css). Every status pill off the
   licence page carries the class, closed included, as approved (2026-10-14).

   SEMANTIC CHANNEL RULE. Green means reconciled / verified / active. It does
   NOT mean "this message came from staff": authorship is --bw-sunk plus a
   mono author line, never a green block.                                   */

/* Fallback first, for the same source-order reason as the callout above. */
.pill{--bwui-c-fill:var(--bw-sunk);--bwui-c-line:var(--bw-line-strong);--bwui-c-ink:var(--bw-meta)}
/* 2026-10-14, owner ruling (keep the current look): the approved portal's
   pill, FULLY ROUND (--bw-r-pill), 5 / 12 inside, .04em tracking, a 6px
   gap and a 6px dot. The dot is still on by class (.pill--dot) and off on
   the licence page whatever the class; where it is on it shows on every
   state, closed included, as it did. */
.pill{
  display:inline-flex;
  align-items:center;
  gap:calc(var(--bw-s1) + var(--bw-s0));
  font-family:var(--bw-mono);
  font-variant-numeric:tabular-nums;
  font-size:var(--bw-t-label);           /* 11px floor */
  font-weight:var(--bw-w-semi);
  letter-spacing:.04em;
  padding:calc(var(--bw-s1) + var(--bw-s0) / 2) var(--bw-s3);
  border-radius:var(--bw-r-pill);
  background:var(--bwui-c-fill);
  color:var(--bwui-c-ink);               /* ≥4.70:1 on its own fill */
  border:1px solid var(--bwui-c-line);
  white-space:nowrap;
}
/* The live-state dot. 50% is off the radius ladder by necessity — a 6px
   circle cannot be expressed by it. This is the first of RADIUS LINT R1's
   two exemptions; the other is .bwui-mark i's 999px bar cap.              */
.pill::before{
  content:"";
  display:none;
  width:6px;height:6px;
  border-radius:50%;
  background:currentColor;
  flex:none;
}
.pill--dot::before{display:block}

/* .open is the portal's --bw-mint ground with --bw-green-on-ground type
   (4.70:1), the pair measured on 2026-10-14; --bw-tip-ink on --bw-mint is
   4.51 and excluded by rule.                                               */
.pill.open  {--bwui-c-fill:var(--bw-mint);     --bwui-c-line:var(--bw-tip-line);   --bwui-c-ink:var(--bw-green-on-ground)} /* 4.70:1 */
.pill.wait  {--bwui-c-fill:var(--bw-caut-fill);--bwui-c-line:var(--bw-caut-line);  --bwui-c-ink:var(--bw-caut-ink)} /* 5.34:1 */
.pill.closed{--bwui-c-fill:var(--bw-sunk);     --bwui-c-line:var(--bw-line-strong);--bwui-c-ink:var(--bw-meta)}     /* 6.16:1 */
.pill.flag  {--bwui-c-fill:var(--bw-warn-fill);--bwui-c-line:var(--bw-warn-line);  --bwui-c-ink:var(--bw-warn-ink)} /* 5.63:1 */
.pill.avail {--bwui-c-fill:var(--bw-note-fill);--bwui-c-line:var(--bw-note-line);  --bwui-c-ink:var(--bw-note-ink)} /* 5.53:1 */
.pill.comp  {--bwui-c-fill:var(--bw-caut-fill);--bwui-c-line:var(--bw-caut-line);  --bwui-c-ink:var(--bw-caut-ink)} /* 5.34:1 */


/* ══ 4.5 — FORM FIELD ════════════════════════════════════════════════════
   Every input on both properties. 16px type so iOS Safari NEVER zooms on
   focus — portal.css sets 14.5px including the sign-in email field, where the
   customer is most likely to be on a phone. 44px targets. A real error state.

   ONE error idiom across the product: server-side validation renders
   .is-error + aria-invalid="true" + aria-describedby pointing at
   .bwui-field__err. No native validation bubbles, no alert(), no confirm();
   destructive actions use the modal in the portal sheet.                   */

/* 2026-10-14: the field owns no bottom margin; the space is between fields
   (adjacent-sibling), so a field beside a button in a row (.grant-row in the
   portal) sits on the button's baseline instead of 16px under it.         */
.bwui-field{display:block;min-width:0}
.bwui-field+.bwui-field{margin-top:var(--bw-s5)}
/* the label row: the label, then an optional mono hint ("optional",
   "3 to 120 characters") on the same baseline (2026-10-14, from portal.css) */
/* 2026-10-14, owner ruling (keep the current look): the approved label,
   14.5 bold, 10px from its hint and 9px over its box. */
.bwui-field__lab{display:flex;align-items:baseline;gap:calc(var(--bw-s2) + var(--bw-s0));margin-bottom:calc(var(--bw-s2) + var(--bw-s0) / 2)}
.bwui-field label{
  font-size:var(--bw-t-row);
  font-weight:var(--bw-w-bold);
  color:var(--bw-ink);                   /* 19.68:1 on --bw-surface */
}
.bwui-field__hint{
  font-family:var(--bw-mono);
  font-size:var(--bw-t-label);
  color:var(--bw-meta);                  /* 6.50:1 on --bw-surface */
}
.bwui-field__req{color:var(--bw-warn-ink)}   /* 6.71:1 — the asterisk */

/* THE INPUT. One spec, two hooks: every control inside a .bwui-field, and a
   bare control that sits in a table cell or a toolbar carries .bwui-input
   (2026-10-14). The width is the field's; a row narrows it with its own
   rule.                                                                    */
/* 2026-10-14, owner ruling (keep the current look): the approved box, ink
   type, 13 / 16 inside; the textarea 170px tall on 1.6 leading. */
.bwui-field input,
.bwui-field textarea,
.bwui-field select,
.bwui-input{
  font-family:var(--bw-sans);
  font-size:var(--bw-t-body);            /* 16px — the iOS zoom floor */
  color:var(--bw-ink);                   /* 19.68:1 on --bw-field-bg */
  background:var(--bw-field-bg);
  border:1px solid var(--bw-field-line); /* 3.17:1 light · 3.85:1 dark */
  border-radius:var(--bw-r-btn);
  padding:calc(var(--bw-s3) + var(--bw-s0) / 2) var(--bw-s4);
  width:100%;
  transition:border-color .15s;
}
/* the height is set once per control kind: 44px for a line, a box for a
   textarea (2026-10-14; it was set on the group and overridden a line later).
   A line keeps the browser's own leading, as approved (2026-10-14). */
.bwui-field input,
.bwui-field select,
.bwui-input{min-height:2.75rem;line-height:normal}   /* 44px */
.bwui-field textarea{min-height:10.625rem;line-height:var(--bw-lh-lede);resize:vertical}
.bwui-field textarea.short{min-height:8.125rem}
/* appearance:none removes the native arrow, so one is drawn back on from the
   token (a data: URI in a background is img-src, not style-src)           */
.bwui-field select,
select.bwui-input{
  appearance:none;
  background-image:var(--bw-select-arrow);
  background-repeat:no-repeat;
  background-position:right var(--bw-s4) center;
  padding-right:calc(var(--bw-s6) + var(--bw-s2));   /* 40, as approved (2026-10-14) */
  padding-left:calc(var(--bw-s4) - var(--bw-s0) / 2);/* 15; the type stays 16, the
                                                        floor that stops a phone zooming */
}
/* Placeholders are READABLE secondary text, not --bw-faint. opacity:1 undoes
   the UA's own fade rather than adding one — it sets no colour of its own, so
   lint C1 is satisfied.                                                    */
.bwui-field input::placeholder,
.bwui-field textarea::placeholder,
.bwui-input::placeholder{
  color:var(--bw-meta);                  /* 6.50:1 on --bw-field-bg */
  opacity:1;
}
/* the border turns ink on focus; the RING is the ink outline every control
   shares (bwui-base.css :focus-visible). The 3px mint glow measured 1.1:1
   and is gone (2026-10-14).                                                */
/* 2026-10-14, owner ruling: the approved focus border is the green words'
   colour; the ring stays the ink outline every control shares. */
.bwui-field input:focus,
.bwui-field textarea:focus,
.bwui-field select:focus,
.bwui-input:focus{border-color:var(--bw-green-deep)}
.bwui-field__help{
  font-size:var(--bw-t-note);            /* 13.5, as approved (2026-10-14) */
  line-height:var(--bw-lh-read);
  color:var(--bw-muted);                 /* 8.46:1 */
  margin:var(--bw-s2) 0 0;
}
/* the approved error state: a red border, no glow (2026-10-14) */
.bwui-field.is-error input,
.bwui-field.is-error textarea,
.bwui-field.is-error select{
  border-color:var(--bw-warn-ink);
}
.bwui-field__err{
  font-size:var(--bw-t-micro);
  font-weight:var(--bw-w-semi);
  color:var(--bw-warn-ink);              /* 6.71:1 on --bw-surface */
  margin:0;
}
/* A checkbox / radio row: the control is not stretched to 100%.            */
.bwui-field--check{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:center;gap:var(--bw-s3)}
.bwui-field--check input{width:1.125rem;height:1.125rem;min-height:0;padding:0}
.bwui-field--check label{font-size:var(--bw-t-small);color:var(--bw-ink2)}  /* 18.10:1 */
/* A row of actions under a form.                                           */
.bwui-formactions{display:flex;gap:var(--bw-s3);flex-wrap:wrap;margin-top:var(--bw-s5)}


/* ══ 4.6 — DATA TABLE ════════════════════════════════════════════════════
   The product's native object: seat lists, ticket queues, export summaries,
   the transaction table in a figure. Mono tabular figures right-aligned, a
   --bw-sunk header band, hairline rows, a tfoot closed with the double rule.

   Two rules this audience needs and the current sites break:
     · the column labels are NOT the smallest, most tracked, hardest-to-read
       thing on the page — 11px in --bw-muted at 8.16:1, tracking .06em not
       .13em;
     · THE TABLE NEVER SCROLLS THE PAGE SIDEWAYS. Below 35rem (560px) it
       reflows to stacked rows, each cell carrying its own label from
       data-th. (A wide sales table may scroll INSIDE its own box on a
       tablet; that is the portal sheet's business, and the page never
       moves.)

   2026-10-14 (the convergence): ONE density, 16px cells under a 12/16 label
   row; the stack point is 35rem, the portal's measured one (three text
   columns in 390px squeezed a subject to five lines); the header is no
   longer sticky, because the portal's page header is not, and a label row
   pinned 72px below the top of a page that scrolls under nothing read as a
   bug. The label mechanism is data-th, written inline before the value in
   the metadata colour; it replaced thirty class-keyed ::before rules in
   portal.css, two of which labelled the wrong column.                     */

.bwui-tblwrap{margin:var(--bw-s6) 0}
/* 2026-10-14, owner ruling (keep the current look): the approved ledger,
   the page's own type, 20px cells set on the middle, and the quiet mono
   label row (500 at .08em in the metadata colour, 14 / 20 inside). */
.bwui-tbl{width:100%;border-collapse:collapse;font-size:inherit;line-height:inherit}
.bwui-tbl thead th{
  background:var(--bw-sunk);
  font-family:var(--bw-mono);
  font-size:var(--bw-t-label);           /* 11px LABEL */
  font-weight:var(--bw-w-med);
  letter-spacing:.08em;
  text-transform:uppercase;
  color:var(--bw-meta);                  /* 6.16:1 on --bw-sunk */
  text-align:left;
  padding:calc(var(--bw-s3) + var(--bw-s0)) calc(var(--bw-s4) + var(--bw-s1));
  border-bottom:1px solid var(--bw-line-strong);
  vertical-align:bottom;                 /* a label that wraps keeps the baseline */
}
.bwui-tbl th.num,
.bwui-tbl td.num{
  text-align:right;
  font-family:var(--bw-mono);
  font-variant-numeric:tabular-nums;     /* digits stack in the column */
}
.bwui-tbl td{
  padding:calc(var(--bw-s4) + var(--bw-s1));
  color:inherit;                         /* the page's ink, 19.68:1 on --bw-surface */
  border-bottom:1px solid var(--bw-line);
  vertical-align:middle;
}
.bwui-tbl tbody tr:last-child td{border-bottom:0}
.bwui-tbl td.date{
  font-family:var(--bw-mono);
  color:var(--bw-muted);                 /* 8.46:1 */
  white-space:nowrap;
}
.bwui-tbl td.num.bal{color:var(--bw-muted)}      /* 8.46:1 — a carried balance */
.bwui-tbl td.credit{color:var(--bw-green-deep)}  /* 5.53:1 on --bw-surface */
.bwui-tbl td.debit-neg{color:var(--bw-warn-ink)} /* 6.71:1 on --bw-surface */
.bwui-tbl tr.is-flagged{background:var(--bw-warn-fill)}
.bwui-tbl tr.is-flagged td{color:var(--bw-warn-ink)}  /* 5.63:1 on the tint */
/* 2026-10-14, owner ruling (keep the current look): a table foot is the
   last row of the ledger, no rule under it; the month grid dresses its own
   total (portal.css), as approved. */
.bwui-tbl tfoot tr:last-child td{border-bottom:0}

/* STACKED REFLOW below 35rem (560px). A row becomes a block; a cell that
   carries data-th says what it is, inline, before the value, so no header
   is lost and nothing scrolls off the side. A cell without data-th is
   self-describing (a subject, an address, a pill) and carries no label.    */
@media (max-width:35rem){
  .bwui-tbl,
  .bwui-tbl tbody,
  .bwui-tbl tfoot,
  .bwui-tbl tr,
  .bwui-tbl td{display:block;width:100%}
  .bwui-tbl thead{position:absolute;left:-9999px}   /* still read aloud */
  /* 2026-10-14, owner ruling: the approved stacked row, 16 / 18 inside, the
     cells flush (the portal sheet gives a data cell its 10px above) */
  .bwui-tbl tr{border-bottom:1px solid var(--bw-line);padding:var(--bw-s4) calc(var(--bw-s4) + var(--bw-s0))}
  .bwui-tbl tbody tr:last-child{border-bottom:0}
  .bwui-tbl td{border:0;padding:0;text-align:left}
  /* the label is set in the cell's own face, as the approved labels were */
  .bwui-tbl td[data-th]::before{
    content:attr(data-th) " ";
    color:var(--bw-meta);                /* 6.50:1 on --bw-surface */
  }
  .bwui-tbl td.num{text-align:left}
}


/* ══ 4.7 — KEY / VALUE STRIP ═════════════════════════════════════════════
   The licence page's account facts, the ticket thread's metadata, any short
   list of labelled values. This is where the dotted leader EARNS its keep:
   the run is long and the figure is real.

   It is .bwui-lrow--fig with the reference cell dropped — same three tracks
   (label / 120px-minimum leader / figure), same tabular mono on the figure,
   same 120px floor. Closed by <hr class="bwui-rule-total"> when it totals.  */

.bwui-kv{margin:0;max-width:none}       /* a <dl> takes the measure in base;
                                           inside a panel the panel is the measure */
.bwui-kv__row{
  display:grid;
  grid-template-columns:minmax(0,auto) minmax(var(--bw-lead-min),1fr) auto;
  column-gap:var(--bw-s3);
  align-items:center;
  min-height:2.5rem;
  font-size:var(--bw-t-small);
}
.bwui-kv dt{color:var(--bw-muted);margin:0}     /* 8.46:1 on --bw-surface */
.bwui-kv dd{
  margin:0;
  font-family:var(--bw-mono);
  font-variant-numeric:tabular-nums;
  font-size:var(--bw-t-fig);             /* 15px — a figure, not a caption */
  color:var(--bw-ink2);                  /* 18.10:1 on --bw-surface */
  white-space:nowrap;
}
/* The closing line under the double rule — a seat count, a total.          */
.bwui-kv__row--total dt{color:var(--bw-ink);font-weight:var(--bw-w-semi)}   /* 19.68:1 */
.bwui-kv__row--total dd{color:var(--bw-ink);font-weight:var(--bw-w-bold)}   /* 19.68:1 */

/* ── THE LEADER RULE, IMPLEMENTED (≤34rem) ──────────────────────────────────
   "If the row cannot afford 120px of leader, the row does not get a leader"
   was stated in three places and enforced in none, and because the
   description track is minmax(0,auto) it was the DESCRIPTION that collapsed,
   never the ornament: at 390px a ticket row spent 52px on the reference, 120
   on dots and ~50 on the date, leaving ~90px for "Export to QBO is rejected by
   QuickBooks". The figure cell is nowrap, so the floor overflowed outright —
   a licence key (22 chars ≈ 198px) in a panel body of 270px was CLIPPED by
   .bwui-panel{overflow:hidden}, with no way to reveal it.

   Below 34rem the leader is dropped, the description takes the slack, and the
   figure may wrap. 34rem is .bwui-pager's breakpoint (§4.14) — the library has
   ONE narrow breakpoint for rows, not two.                                  */
@media (max-width:34rem){
  .bwui-lrow--fig{
    grid-template-columns:var(--bwui-ref-w,3.25rem) minmax(0,1fr) auto;
    column-gap:var(--bw-s2);
  }
  .bwui-kv__row{grid-template-columns:minmax(0,1fr) auto}
  .bwui-lrow--fig .bwui-lead,
  .bwui-kv__row .bwui-lead{display:none}
  .bwui-kv dd,
  .bwui-lrow__fig{white-space:normal;overflow-wrap:anywhere}
}


/* ══ 4.8 — KEYLINE, MENU PATH ════════════════════════════════════════════
   code / pre / kbd are ELEMENT rules and live in bwui-base.css; they are not
   restated here. Only the two classed forms belong to the component layer.  */

/* A licence key, a device id, an account number. Mono, tabular, in a well.  */
.bwui-key{
  font-family:var(--bw-mono);
  font-variant-numeric:tabular-nums;
  font-size:var(--bw-t-fig);
  letter-spacing:var(--bw-track-label);
  background:var(--bw-key-fill);
  border:1px solid var(--bw-key-line);
  border-radius:var(--bw-r-xs);
  padding:var(--bw-s1) var(--bw-s2);     /* = SPEC's 0.25rem 0.5rem, on-ladder */
  color:var(--bw-ink2);                  /* 15.59:1 on --bw-key-fill */
}
.bwui-key--block{display:block;overflow-wrap:anywhere;white-space:normal}

/* MENU PATH — one convention on both properties:  File › Export › CSV       */
.bwui-path{
  font-family:var(--bw-mono);
  font-size:var(--bw-t-micro);
  color:var(--bw-ink2);                  /* 16.42:1 on --bw-paper */
}
.bwui-path i{
  font-style:normal;
  color:var(--bw-green-deep);            /* 5.02:1 on --bw-paper */
  padding:0 var(--bw-s1);
}


/* ══ 4.9 — PAGE HEADER ═══════════════════════════════════════════════════
   Identical markup on both properties. Flat --bw-paper band, ONE hairline,
   NO backdrop-filter (frosted glass plus a tinted pill on the current item is
   the most generic app-chrome pair available, and v4 has neither).

   The active mark is v4's 2px --bw-green underline — the same "current" idea
   as the stub's promoted reference chip, expressed horizontally, and the one
   legal use of the fill green as a SHAPE in the header.                    */

.bwui-head{
  position:sticky;
  top:0;
  z-index:30;
  background:var(--bw-paper);
  border-bottom:1px solid var(--bw-line);
}
.bwui-head__in{                          /* gutter + wrap: .bwui-wrap, above */
  min-height:var(--bw-head-h);           /* THE HEADER IS THE TOKEN TALL — every
                                            sticky offset in the library depends
                                            on that being true. See the ≤46rem
                                            block at the end of this section. */
  display:flex;
  align-items:center;
  gap:var(--bw-s5);
}
.bwui-brand{display:inline-flex;align-items:center;gap:var(--bw-s3);
  text-decoration:none;flex:none}
.bwui-brand__img{height:28px;width:auto;display:block}

/* THE ONE SANCTIONED THEME QUERY IN THIS FILE. Dark is resolved in
   bwui-tokens.css and no component may test a theme — but an ASSET swap is not
   a colour, and it cannot be expressed as a token. So it is implemented ONCE,
   as a utility, and every light/dark asset in the company uses it: the brand
   logo pair, a theme-control glyph pair, anything else. Three copies of this
   three-rule shape (the logo, the gallery's sun/moon, and the next one) is how
   an asset desyncs from the palette. --light/--dark on .bwui-brand__img are
   kept as aliases so existing markup does not have to change.              */
.bwui-only-light,
.bwui-brand__img--light{display:block}
.bwui-only-dark,
.bwui-brand__img--dark{display:none}
:root[data-theme="dark"] .bwui-only-light,
:root[data-theme="dark"] .bwui-brand__img--light{display:none}
:root[data-theme="dark"] .bwui-only-dark,
:root[data-theme="dark"] .bwui-brand__img--dark{display:block}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]) .bwui-only-light,
  :root:not([data-theme="light"]) .bwui-brand__img--light{display:none}
  :root:not([data-theme="light"]) .bwui-only-dark,
  :root:not([data-theme="light"]) .bwui-brand__img--dark{display:block}
}
.bwui-brand__sub{
  font-family:var(--bw-mono);
  font-size:var(--bw-t-label);
  font-weight:var(--bw-w-semi);
  letter-spacing:var(--bw-track-label);  /* .06em — the kicker's .13em belongs to
                                            .bwui-kicker and two other selectors;
                                            thirteen carriers is wallpaper */
  text-transform:uppercase;
  color:var(--bw-muted);                 /* 7.67:1 on --bw-paper */
}

/* flex-wrap because a flex row of single-word links CANNOT shrink below its
   own max-content: four labels plus three 24px gaps measure ≈304px against a
   303px content box at 360px, so the page — not the nav — scrolled. Adding a
   fifth item made it certain.                                              */
.bwui-headnav{
  display:flex;
  flex-wrap:wrap;
  gap:var(--bw-s5);
  margin-left:auto;
  font-size:var(--bw-t-small);
  font-weight:var(--bw-w-med);
}
.bwui-headnav a{
  color:var(--bw-muted);                 /* 7.67:1 on --bw-paper */
  position:relative;
  padding:var(--bw-s2) 0;
  text-decoration:none;
}
.bwui-headnav a:hover{color:var(--bw-ink)}            /* 17.86:1 */
.bwui-headnav a[aria-current]{color:var(--bw-ink)}    /* 17.86:1 */
/* The underline is 2.63:1 against --bw-paper, the band it sits in — BELOW WCAG
   1.4.11's 3:1 for a non-text state indicator. It is legal only because the
   state is carried REDUNDANTLY by the ink change on the line above (--bw-muted
   7.67:1 → --bw-ink 17.86:1), which is what a reader who cannot see the bar
   reads. Remove that colour jump and this underline stops being sufficient. */
.bwui-headnav a[aria-current]::after{
  content:"";
  position:absolute;left:0;right:0;bottom:0;
  height:2px;
  background:var(--bw-green);             /* SHAPE token — the ONE current mark */
}
.bwui-headnav a[rel~="external"]::after{
  content:"\2197";                        /* ↗ */
  position:static;
  font-size:var(--bw-t-micro);            /* on the ladder (2026-10-14) */
  color:var(--bw-muted);                  /* 7.67:1 */
  margin-left:var(--bw-s1);
  background:none;height:auto;
}

/* THE ICON BUTTON: 44 by 44, the one shape for a control that is a glyph
   (Edit profile, Sign out, a year arrow, a card's collapse toggle). The
   border is --bw-field-line, 3.17:1 (2026-10-14; was --bw-line, 1.4:1).   */
.bwui-iconbtn{
  width:2.75rem;height:2.75rem;           /* 44px */
  padding:0;                              /* no UA button padding (2026-10-14) */
  border-radius:var(--bw-r-btn);
  border:1px solid var(--bw-field-line);
  background:var(--bw-surface);
  color:var(--bw-muted);                  /* 8.46:1 on --bw-surface */
  display:inline-grid;place-items:center;
  cursor:pointer;flex:none;
  text-decoration:none;
  transition:border-color .15s, color .15s;
}
.bwui-iconbtn:hover{border-color:var(--bw-ink);color:var(--bw-ink)}  /* 19.68:1 */

/* Skip link — visible only on focus, and never a dead control.             */
/* 2026-10-14, owner ruling (keep the current look): the approved skip link,
   a white card with the ink word, 12 / 18 inside, semibold. */
.bwui-skip{
  position:absolute;left:var(--bw-s4);top:var(--bw-s3);z-index:50;
  padding:var(--bw-s3) calc(var(--bw-s4) + var(--bw-s0));
  background:var(--bw-surface);
  color:var(--bw-ink);                    /* 19.68:1 light · 15.52:1 dark */
  border:1px solid var(--bw-line-strong);
  border-radius:var(--bw-r-btn);
  font-weight:var(--bw-w-semi);
  text-decoration:none;
  transform:translateY(-200%);
}
.bwui-skip:focus{transform:none}

/* ── THE NARROW HEADER: EXACTLY THREE ROWS ──────────────────────────────────
   The header wraps here, so --bw-head-h stops being 72px — and --bw-head-h is
   what .bwui-stub, the sticky <thead> and scroll-padding-top all offset by. A
   token cannot measure a wrapped flex box, so the LAYOUT is pinned instead:

     row 1  brand ………………………………………… theme control
     row 2  nav, one line, full width
     row 3  compact search, full width

   Ordering the nav to a full-width row of its own is what makes the count
   deterministic — left to itself the nav wraps to a line, then the icon button
   wraps to another, and the header is four rows on one page and two on the
   next. bwui-tokens.css carries the arithmetic and the resulting 10.5rem;
   .bwui-head__in's min-height then makes the header exactly that tall.

   If you add a sixth nav item or a two-word label, the nav row wraps and this
   contract breaks — re-measure --bw-head-h in the tokens file.             */
@media (max-width:46rem){
  .bwui-head__in{flex-wrap:wrap;padding-block:var(--bw-s3);gap:var(--bw-s3)}
  .bwui-headnav{order:2;flex:1 0 100%;margin-left:0;gap:var(--bw-s4)}
  .bwui-head .bwui-iconbtn{margin-left:auto}
  .bwui-search--compact{order:3;flex:1 0 100%;margin-left:0}
}


/* ══ 4.10 — FOOTER ═══════════════════════════════════════════════════════
   The end of the page, ONCE. Flat ink band — never a gradient. The panel is
   #0B0B0B in both themes (the constant the customer recognises), so every
   ratio below is against --bw-ink-panel and does not move with the theme.  */

.bwui-foot{
  background:var(--bw-ink-panel);
  color:var(--bw-on-ink-2);              /* 12.57:1 on --bw-ink-panel */
  margin-top:var(--bw-s8);
}
.bwui-foot__in{                          /* gutter + wrap: .bwui-wrap, above */
  padding-block:var(--bw-s7);            /* same gutter as header and body */
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(min(12rem,100%),1fr));
  gap:var(--bw-s6);
}
/* A COLUMN LABEL, AND THEREFORE NOT A HEADING. This was `.bwui-foot h5`, which
   rendered an h5 at 11px against 16px body copy — the exact defect
   bwui-base.css names ("THERE IS NO HEADING ROLE BELOW 18px … anything smaller
   is a LABEL, is set in mono, and is never marked up as h1–h6") and the exact
   complaint the client raised about v4. Styling it as a label while leaving it
   an <h5> fixed the pixels and kept the defect. It is a class now, and the
   markup emits <p class="bwui-foot__k">. If a footer genuinely needs landmark
   headings, add visually-hidden ones — do not put the label back.          */
.bwui-foot__k{
  font-family:var(--bw-mono);
  font-size:var(--bw-t-label);           /* 11px LABEL, not a heading role */
  font-weight:var(--bw-w-semi);
  letter-spacing:var(--bw-track-kicker); /* one of the three legal .13em carriers */
  text-transform:uppercase;
  color:var(--bw-on-ink-3);              /* 8.22:1 on --bw-ink-panel */
  margin:0 0 var(--bw-s3);
}
.bwui-foot ul{list-style:none;margin:0;padding:0;display:grid;gap:var(--bw-s2)}
.bwui-foot a{color:var(--bw-on-ink-2);text-decoration:none}    /* 12.57:1 */
.bwui-foot a:hover{color:var(--bw-on-ink);text-decoration:underline}  /* 19.68:1 */
.bwui-foot__base{                        /* gutter + wrap: .bwui-wrap, above */
  padding-block:var(--bw-s4) var(--bw-s6);
  border-top:1px solid var(--bw-on-ink-line-soft);
  font-family:var(--bw-mono);
  font-size:var(--bw-t-mono);
  color:var(--bw-on-ink-3);              /* 8.22:1 on --bw-ink-panel */
  display:flex;justify-content:space-between;gap:var(--bw-s4);flex-wrap:wrap;
}
.bwui-foot__seal{color:var(--bw-on-ink-green)}   /* 6.80:1 — the ONE green-as-type case */


/* ══ 4.11 — CTA BAND ═════════════════════════════════════════════════════
   ONE optional closing action, on pages that declare one. Flat ink panel —
   NEVER a gradient.

   A PAGE ENDS ONCE. The current guide page ends four times in ~300px
   (.updated, .pager, .cta-band, .site-foot — two adjacent black panels
   reading as one 500px slab). The band is emitted only when the page declares
   cta: in frontmatter, its primary href may not equal the page's own URL
   (lint E1), and it may not be the element immediately preceding the footer —
   the pager always sits between them (lint E2).

   .bwui-cta always carries .bwui-on-ink so the buttons invert (§4.1).      */

.bwui-cta{
  background:var(--bw-ink-panel);
  color:var(--bw-on-ink-2);              /* 12.57:1 on --bw-ink-panel */
  border-radius:var(--bw-r);
  padding:var(--bw-s6);
  margin:var(--bw-s8) 0 0;
}
.bwui-cta h2{color:var(--bw-on-ink);margin:0 0 var(--bw-s3)}   /* 19.68:1 */
.bwui-cta h2 em{color:var(--bw-on-ink-green)}                  /*  6.80:1 */
.bwui-cta p{color:var(--bw-on-ink-2);margin:0 0 var(--bw-s5);max-width:48ch} /* 12.57:1 */
.bwui-cta__actions{display:flex;gap:var(--bw-s3);flex-wrap:wrap}


/* ══ 4.12 — FIGURE FRAME — lives in bwui-doc.css ═════════════════════════
   Deliberately NOT here. A figure is an iframed replica of the desktop app
   sized from --fw/--fh, which build.py measures off the replica and stamps on
   the .fig element; that is documentation furniture, and the doc sheet is the
   only consumer.

   It was defined in BOTH files, on the same three selectors, with two
   different breakpoint ladders — 647/599/539/479/429/379 here against
   700/630/562/497/447/397/377/339 there. Source order made the winner depend
   on which ladder happened to match at a given width, so the frame could be
   sized from one sheet and the column from the other, and the document
   scrolled sideways at the widths where they disagreed. One owner removes the
   whole class of defect. If the portal ever needs figures it loads
   bwui-doc.css, or the block moves here wholesale — never both.        */

/* ══ 4.13 — EMPTY STATE, AND THE MARK ════════════════════════════════════
   Tickets-empty, staff-queue-empty, search-no-results, error.html, the 404.

   2026-10-14, owner ruling (keep the current look): CENTRED, as the
   approved portal set it, 88 / 32 inside a sheet; the heading is the
   section class (.h-sec, sized for this block in portal.css) with 12px
   under it, the sentence 44ch wide on the centre line, 28px over the
   actions.                                                                 */
.bwui-estate{text-align:center;max-width:none;padding:calc(var(--bw-s8) + var(--bw-s4)) var(--bw-s6)}
.bwui-estate h3,
.bwui-estate .h-sec{margin:0 0 var(--bw-s3)}
.bwui-estate .bwui-kicker{margin-bottom:calc(var(--bw-s3) + var(--bw-s0))}
.bwui-estate p{color:var(--bw-muted);margin:0 auto calc(var(--bw-s5) + var(--bw-s1));max-width:44ch}   /* 8.46:1 */
.bwui-estate .bwui-key{display:inline-block;margin-bottom:var(--bw-s4)}
.bwui-estate__actions{display:flex;gap:var(--bw-s3);flex-wrap:wrap;justify-content:center}

/* THE MARK. Measured off logo-light.svg: four tapered bars at
   y = 45.5 / 61.4 / 77.1 / 93.2 (pitch 15.85), lengths 44.02 / 34.35 /
   44.02 / 34.35 (ratio 0.7803), all LEFT-anchored with a ragged right edge.
   Long / short / long / short. Four elements, no gradient.
     short / long      = 34.35 / 44.02 = 0.78033  → width 78.03%
     bar height / long =  7.00 / 44.02 = 0.159
     gap = 15.85 − 7.00 = 8.85u; 8.85 / 44.02 = 0.201
   At --bwui-mark:44px that is four 7px bars with 8.85px gaps — a 54.5px block.
   BELOW 28px THE ALTERNATION STOPS READING; do not use it smaller.
   LEGAL PLACEMENTS ARE EXACTLY TWO: the empty state and the 404. Not the
   favicon (that is the real SVG), not the stub foot, not the sign-in panel,
   not a background wash — four green horizontal lines is also what a list
   glyph looks like, and deploying it everywhere would put the least
   distinctive asset in the most memorable positions.
   The 999px radius here is the second of RADIUS LINT R1's two exemptions (the
   other is .bwui-tag::before's 50% dot); it is a bar cap, not a pill. Both
   were mis-attributed to lint B3, which counts double rules.               */
.bwui-mark{
  --bwui-mark:44px;
  display:grid;
  gap:calc(var(--bwui-mark) * .201);
  width:var(--bwui-mark);
  margin-bottom:var(--bw-s4);
}
.bwui-mark i{
  display:block;
  height:calc(var(--bwui-mark) * .159);
  min-height:2px;
  border-radius:999px;
  background:var(--bw-green);            /* SHAPE token — a bar, never type */
}
.bwui-mark i:nth-child(2),
.bwui-mark i:nth-child(4){width:78.03%}


/* ══ 4.14 — PAGINATION ═══════════════════════════════════════════════════
   Two jobs, one component: the guide's prev/next chapter pager, and the
   ticket list's page controls.

   The pager carries the chapter NAME and nothing else. It does NOT repeat the
   chapter number — that is the stub's job, and repeating it is one of the six
   competing "you are here" signals being deleted (§5.7).                   */

.bwui-pager{
  display:grid;
  grid-template-columns:1fr 1fr;
  gap:var(--bw-s4);
  margin:var(--bw-s7) 0 0;
}
.bwui-pager a{
  display:grid;
  gap:var(--bw-s1);
  padding:var(--bw-s4);
  border:1px solid var(--bw-line);
  border-radius:var(--bw-r);
  background:var(--bw-surface);
  text-decoration:none;
  min-height:2.75rem;                    /* 44px */
  transition:border-color .15s, transform .15s;
}
.bwui-pager a:hover{border-color:var(--bw-line-strong);transform:translateY(-1px)}
.bwui-pager__next{text-align:right}
.bwui-pager__dir{
  font-family:var(--bw-mono);
  font-size:var(--bw-t-label);
  font-weight:var(--bw-w-semi);
  letter-spacing:var(--bw-track-label);  /* .06em — not a kicker */
  text-transform:uppercase;
  color:var(--bw-muted);                 /* 8.46:1 on --bw-surface */
}
.bwui-pager__t{
  font-size:var(--bw-t-small);
  font-weight:var(--bw-w-semi);
  color:var(--bw-ink);                   /* 19.68:1 on --bw-surface */
}
.bwui-pager a:only-child{grid-column:1 / -1}
@media (max-width:34rem){
  .bwui-pager{grid-template-columns:1fr}
  .bwui-pager__next{text-align:left}
}

/* LIST PAGINATION — the portal's ticket list. Same type, NO cards.         */
.bwui-pages{
  display:flex;align-items:center;gap:var(--bw-s3);
  margin-top:var(--bw-s6);
  font-family:var(--bw-mono);
  font-variant-numeric:tabular-nums;
  font-size:var(--bw-t-mono);
  color:var(--bw-muted);                 /* 7.67:1 on --bw-paper */
}
.bwui-pages a{
  color:var(--bw-green-deep);            /* 5.02:1 on --bw-paper */
  text-decoration:none;
  padding:var(--bw-s2);
}
.bwui-pages a:hover{text-decoration:underline}
/* A spent control still renders WORDS a person reads ("← Newer"), so it is
   type and takes a type token. It was --bw-faint, which is 2.85:1 on the
   --bw-paper this nav actually sits on (the 3.14 quoted in its defence is the
   figure against --bw-surface, a ground this component never touches). The
   spent state is carried non-chromatically by pointer-events + aria-disabled,
   so nothing is lost by making it readable.                                 */
.bwui-pages a[aria-disabled="true"]{
  color:var(--bw-muted);                 /* 7.67:1 on --bw-paper · 7.54:1 dark */
  pointer-events:none;
}
.bwui-pages__of{margin-left:auto}


/* ══ 4.15 — SEARCH ═══════════════════════════════════════════════════════
   The client asked for it by name. Two forms, on EVERY docs page: compact in
   the header, expanded on the hub. Landing on /guide/exports/ from Google
   with "QBO won't import" must not dead-end.

   The existing client-side implementation is carried over verbatim — the CSS
   below is the only thing that changes. The form ships [hidden] and the
   script un-hides it, so a no-JS reader never meets a dead control.

   RESULTS ARE .bwui-lrow. A search result and a chapter row are the same
   object: reference = section, figure = nothing.                           */

.bwui-search{position:relative;min-width:0}
.bwui-search__label{
  display:block;
  font-family:var(--bw-mono);
  font-size:var(--bw-t-label);
  font-weight:var(--bw-w-semi);
  letter-spacing:var(--bw-track-label);  /* .06em — not a kicker */
  text-transform:uppercase;
  color:var(--bw-green-deep);            /* 5.02:1 on --bw-paper */
  margin:0 0 var(--bw-s2);
}
.bwui-search__field{
  display:flex;align-items:center;gap:var(--bw-s2);
  background:var(--bw-field-bg);
  border:1px solid var(--bw-field-line);
  border-radius:var(--bw-r-btn);
  padding:0 var(--bw-s4);
  min-height:2.75rem;                    /* 44px */
}
.bwui-search__field:focus-within{border-color:var(--bw-ink);box-shadow:var(--bw-glow)}
.bwui-search__icon{color:var(--bw-muted);flex:none}   /* a stroke, not type */
.bwui-search__input{
  flex:1;min-width:0;
  border:0;background:none;outline:none;
  font-family:var(--bw-sans);
  font-size:var(--bw-t-body);            /* 16px — the iOS zoom floor */
  color:var(--bw-ink2);                  /* 18.10:1 on --bw-field-bg */
  padding:var(--bw-s3) 0;
}
.bwui-search__input::placeholder{color:var(--bw-muted);opacity:1}  /* 8.46:1 */
.bwui-search__input::-webkit-search-cancel-button{appearance:none}
.bwui-search__status{
  font-size:var(--bw-t-micro);
  color:var(--bw-muted);                 /* 7.67:1 on --bw-paper */
  margin:var(--bw-s2) 0 0;
  min-height:1.25rem;                    /* reserved, so results do not jump */
}
.bwui-search__panel{
  position:absolute;z-index:40;
  left:0;right:0;top:calc(100% + var(--bw-s2));
  background:var(--bw-surface);
  border:1px solid var(--bw-line-strong);
  border-radius:var(--bw-r);
  box-shadow:var(--bw-sh);               /* an overlay — elevation is earned here */
  padding:var(--bw-s2);
  max-height:26rem;
  overflow-y:auto;
  overscroll-behavior:contain;
}
.bwui-search__panel .bwui-lrow{padding:var(--bw-s2) var(--bw-s3)}
.bwui-search__panel .bwui-lrow:hover{background:var(--bw-sunk);border-radius:var(--bw-r-xs)}
.bwui-search__hit{
  font-size:var(--bw-t-micro);
  color:var(--bw-muted);                 /* 8.46:1 on --bw-surface */
  grid-column:2;
  margin-top:var(--bw-s1);
}
.bwui-search__hit mark{
  background:var(--bw-caut-fill);
  color:var(--bw-ink2);                  /* 16.36:1 on --bw-caut-fill */
  border-radius:var(--bw-r-xs);
  padding:0 var(--bw-s0);
}
.bwui-search__empty{
  padding:var(--bw-s4);
  font-size:var(--bw-t-small);
  color:var(--bw-muted);                 /* 8.46:1 on --bw-surface */
}
/* COMPACT — header form: label visually hidden (still announced), panel
   right-aligned under a 20rem field.                                       */
.bwui-search--compact{flex:0 1 20rem;margin-left:auto}
.bwui-search--compact .bwui-search__label,
.bwui-search--compact .bwui-search__status{
  position:absolute;width:1px;height:1px;
  overflow:hidden;clip-path:inset(50%);white-space:nowrap;
}
/* The compact field is SHORTER, never smaller-typed. Its font-size was
   var(--bw-t-small) — 15px, under iOS Safari's 16px zoom-on-focus floor, at
   (0,2,0) so it beat the 16px rule above — in the one field most likely to be
   used on a phone: below 46rem this is the full-width header search. That is
   the precise thing §4.5 criticises portal.css for. Height comes from
   min-height and padding instead.                                          */
.bwui-search--compact .bwui-search__field{min-height:2.25rem}
.bwui-search--compact .bwui-search__input{padding-block:var(--bw-s2)}


/* ══ PRINT ═══════════════════════════════════════════════════════════════
   Values for print (the light ramp, no elevation) are re-asserted in
   bwui-tokens.css. This is layout only: drop the furniture a reader cannot
   click, keep a figure and a row whole across a page break.                */
@media print{
  .bwui-head,
  .bwui-search,
  .bwui-pages,
  .bwui-cta,
  .bwui-iconbtn,
  .bwui-skip,
  .bwui-estate__actions{display:none}
  .bwui-foot{margin-top:var(--bw-s5)}
  .bwui-card,
  .bwui-panel,
  .bwui-callout,
  .bwui-pager a{box-shadow:none}
  .bwui-tbl thead th{position:static}
  .bwui-fig__frame{box-shadow:none;break-inside:avoid;page-break-inside:avoid}
  .bwui-lrow,
  .bwui-kv__row{break-inside:avoid;page-break-inside:avoid}
}
