/*
 * ropebreak-components.css — the house component kit, for the Django admin.
 *
 * The public apps get these components from the Bootstrap theme
 * (`bootstrap/scss/_native.scss`). The admin can't: it runs on Django's own
 * CSS, not Bootstrap, and there are no `--bs-*` variables to hang them from.
 * So this is the same vocabulary, re-cut against `design/tokens.css` alone —
 * identical class names, identical markup contracts, so a pattern learned on
 * one side of the house works on the other and `django/verify.py` fails the
 * build if the two vocabularies drift apart.
 *
 *   Bootstrap component   →  RopeBreak replacement
 *   ---------------------    -----------------------------------------------
 *   Accordion / Collapse  →  .rb-accordion over <details>/<summary>
 *   Dropdown              →  .rb-menu-list inside <details>
 *   Tabs (tab-pane)       →  .rb-tabs — a radio group, panels swap in place
 *   Carousel              →  .rb-scroller — CSS scroll-snap
 *   Tooltip               →  .rb-tooltip (hover + keyboard focus), or `title`
 *   Modal                 →  .rb-modal — the Popover API, no script
 *   Offcanvas             →  .rb-drawer — the Popover API, no script
 *   Toast                 →  .rb-toast-region holding server-rendered alerts
 *   Alert                 →  .rb-alert
 *   Card                  →  .rb-panel
 *   List group            →  .rb-list
 *   Progress              →  .rb-meter (in the data kit)
 *   Button group          →  .rb-btn-group
 *   Input group           →  .rb-input-group
 *
 * NO-JS FIRST. Django's admin is staff-only and may use JavaScript — its own
 * calendar and autocomplete widgets do — but nothing in this file waits for a
 * script. Every pattern here is paint over an element that already has the
 * behaviour: <details> has opened and closed itself since 2011, radio inputs
 * since forever, and [popover] is browser-native. The rule that governs the
 * public build governs the vocabulary here too: if the markup needs a
 * `data-bs-toggle` attribute to do its job, it doesn't ship.
 *
 * That matters more in an admin than it looks. A staff tool is the thing you
 * reach for when something is broken — a flaky CDN, a Content-Security-Policy
 * you just tightened, a browser extension eating scripts. A disclosure that
 * still opens under all of those is worth more here than on the public site.
 */

/* ==========================================================================
   1. Disclosure — replaces Accordion and Collapse
   ==========================================================================
 *
 * The browser handles open/close, keyboard operation and the accessibility
 * semantics. Content inside a closed <details> is still in the document, so
 * find-in-page reaches it — which is exactly what you want when the panel is
 * hiding the provenance of a record you're trying to correct.
 */

.rb-accordion {
  border: 1px solid var(--rb-admin-line-strong);
}

.rb-accordion > details + details {
  border-top: 1px solid var(--rb-admin-line-strong);
}

.rb-disclosure {
  background: var(--rb-admin-panel-sunk);
}

.rb-disclosure > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  font-weight: var(--font-weight-medium);
  color: var(--color-fg);
  cursor: pointer;
  list-style: none;
}

.rb-disclosure > summary::-webkit-details-marker {
  display: none;
}

/* The chevron is drawn, not fetched: no icon font, no sprite, no request. */
.rb-disclosure > summary::after {
  flex: 0 0 auto;
  width: 0.5em;
  height: 0.5em;
  margin-inline-end: 0.25em;
  content: "";
  border-right: 2px solid var(--rb-gold-500);
  border-bottom: 2px solid var(--rb-gold-500);
  transform: rotate(45deg) translate(-0.15em, -0.15em);
  transition: transform var(--duration-base) var(--ease-standard);
}

.rb-disclosure > summary:hover {
  color: var(--rb-gold-300);
  background: var(--rb-admin-row-hover);
}

.rb-disclosure[open] > summary {
  color: var(--rb-gold-300);
  border-bottom: 1px solid var(--rb-admin-line-strong);
}

.rb-disclosure[open] > summary::after {
  transform: rotate(-135deg) translate(-0.15em, -0.15em);
}

.rb-disclosure-body {
  padding: var(--space-3);
}

/* ==========================================================================
   2. Menu — replaces Dropdown
   ========================================================================== */

.rb-menu-wrap {
  position: relative;
  display: inline-block;
}

.rb-menu-list {
  position: absolute;
  inset-inline-start: 0;
  z-index: var(--z-dropdown);
  min-width: 12rem;
  padding: var(--space-1) 0;
  margin: var(--space-1) 0 0;
  list-style: none;
  background: var(--rb-admin-panel);
  border: 1px solid var(--rb-admin-line-strong);
  box-shadow: var(--shadow-md);
}

.rb-menu-list a,
.rb-menu-list button {
  display: block;
  width: 100%;
  padding: var(--space-2) var(--space-3);
  font-family: var(--font-sans);
  font-size: var(--font-size-sm);
  color: var(--color-fg);
  text-align: start;
  text-decoration: none;
  background: none;
  border: 0;
  cursor: pointer;
}

.rb-menu-list a:hover,
.rb-menu-list a:focus,
.rb-menu-list button:hover,
.rb-menu-list button:focus {
  color: var(--rb-navy-900);
  background: var(--rb-gold-500);
}

/* No Popper here, so a menu near the viewport edge opts into right alignment
 * rather than being flipped for it. */
.rb-menu-end {
  inset-inline: auto 0;
}

/*
 * A menu that closes when focus leaves — the one thing <details> cannot do
 * without a document-level click listener. Tab to the trigger and it opens;
 * move focus anywhere else, including by clicking the page, and it closes. The
 * trade is that clicking the trigger a second time does not close it, because
 * the trigger still holds focus.
 */
.rb-menu-focus > .rb-menu-list {
  display: none;
}

.rb-menu-focus:focus-within > .rb-menu-list {
  display: block;
}

/* ==========================================================================
   3. Tabs — replaces tab panes
   ==========================================================================
 *
 * MARKUP CONTRACT for `.rb-tabs`, which the sibling selectors below depend on.
 * Its direct children must be, in this order:
 *   1. N `<input class="rb-tab-radio" type="radio">`, sharing one `name`, one
 *      of them `checked` — the only <input> children.
 *   2. One `<ul class="rb-tab-strip">` whose N `<li>` each hold a
 *      `<label class="rb-tab-label" for="…">`.
 *   3. N `<div class="rb-tab-panel">` — the only <div> children.
 * Panel k pairs with radio k by position, so the counts and order must match.
 *
 * Switching tabs is a native input changing state: the panel swaps in place
 * with no request, no reload and no scroll jump. Arrow keys move between the
 * radios and select as they go, which is the keyboard behaviour the ARIA tabs
 * pattern specifies.
 *
 * A bare `.rb-tab-panel` outside `.rb-tabs` is the link-based form — one URL
 * per tab, server-rendered. Use it when the tabs must be linkable, or when a
 * panel is too heavy to send with every request.
 */

.rb-tabs {
  position: relative;
}

.rb-tabs > .rb-tab-radio {
  position: absolute;
  width: 1px;
  height: 1px;
  /* Not `display: none` — that would take it off the tab order. */
  opacity: 0;
}

.rb-tab-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
  padding: 0;
  margin: 0;
  list-style: none;
  border-bottom: 1px solid var(--rb-admin-line-strong);
}

.rb-tab-label {
  display: block;
  padding: var(--space-2) var(--space-4);
  font-family: var(--font-sans);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-bold);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--color-fg-muted);
  cursor: pointer;
  border: 1px solid transparent;
  border-bottom: 0;
}

.rb-tab-label:hover {
  color: var(--rb-gold-300);
}

.rb-tab-panel {
  padding: var(--space-4);
  background: var(--rb-admin-panel-sunk);
  border: 1px solid var(--rb-admin-line-strong);
  border-top: 0;
}

/* Panels start hidden ONLY inside .rb-tabs, where a radio is guaranteed to
 * reveal one. A standalone .rb-tab-panel is server-rendered and stays visible. */
.rb-tabs > .rb-tab-panel {
  display: none;
}

/* Position-matched pairing. Eight is a generous ceiling for one strip; a
 * surface needing more tabs wants navigation, not tabs. */
.rb-tabs > .rb-tab-radio:nth-of-type(1):checked ~ .rb-tab-strip > li:nth-child(1) > .rb-tab-label,
.rb-tabs > .rb-tab-radio:nth-of-type(2):checked ~ .rb-tab-strip > li:nth-child(2) > .rb-tab-label,
.rb-tabs > .rb-tab-radio:nth-of-type(3):checked ~ .rb-tab-strip > li:nth-child(3) > .rb-tab-label,
.rb-tabs > .rb-tab-radio:nth-of-type(4):checked ~ .rb-tab-strip > li:nth-child(4) > .rb-tab-label,
.rb-tabs > .rb-tab-radio:nth-of-type(5):checked ~ .rb-tab-strip > li:nth-child(5) > .rb-tab-label,
.rb-tabs > .rb-tab-radio:nth-of-type(6):checked ~ .rb-tab-strip > li:nth-child(6) > .rb-tab-label,
.rb-tabs > .rb-tab-radio:nth-of-type(7):checked ~ .rb-tab-strip > li:nth-child(7) > .rb-tab-label,
.rb-tabs > .rb-tab-radio:nth-of-type(8):checked ~ .rb-tab-strip > li:nth-child(8) > .rb-tab-label {
  color: var(--rb-gold-500);
  background: var(--rb-admin-panel-sunk);
  border-color: var(--rb-admin-line-strong);
}

/* The radio is visually hidden, so its focus ring has to be drawn on the
 * label. Inset, so it isn't clipped by the strip's bottom border. */
.rb-tabs > .rb-tab-radio:nth-of-type(1):focus-visible ~ .rb-tab-strip > li:nth-child(1) > .rb-tab-label,
.rb-tabs > .rb-tab-radio:nth-of-type(2):focus-visible ~ .rb-tab-strip > li:nth-child(2) > .rb-tab-label,
.rb-tabs > .rb-tab-radio:nth-of-type(3):focus-visible ~ .rb-tab-strip > li:nth-child(3) > .rb-tab-label,
.rb-tabs > .rb-tab-radio:nth-of-type(4):focus-visible ~ .rb-tab-strip > li:nth-child(4) > .rb-tab-label,
.rb-tabs > .rb-tab-radio:nth-of-type(5):focus-visible ~ .rb-tab-strip > li:nth-child(5) > .rb-tab-label,
.rb-tabs > .rb-tab-radio:nth-of-type(6):focus-visible ~ .rb-tab-strip > li:nth-child(6) > .rb-tab-label,
.rb-tabs > .rb-tab-radio:nth-of-type(7):focus-visible ~ .rb-tab-strip > li:nth-child(7) > .rb-tab-label,
.rb-tabs > .rb-tab-radio:nth-of-type(8):focus-visible ~ .rb-tab-strip > li:nth-child(8) > .rb-tab-label {
  outline: 2px solid var(--rb-gold-500);
  outline-offset: -2px;
}

.rb-tabs > .rb-tab-radio:nth-of-type(1):checked ~ .rb-tab-panel:nth-of-type(1),
.rb-tabs > .rb-tab-radio:nth-of-type(2):checked ~ .rb-tab-panel:nth-of-type(2),
.rb-tabs > .rb-tab-radio:nth-of-type(3):checked ~ .rb-tab-panel:nth-of-type(3),
.rb-tabs > .rb-tab-radio:nth-of-type(4):checked ~ .rb-tab-panel:nth-of-type(4),
.rb-tabs > .rb-tab-radio:nth-of-type(5):checked ~ .rb-tab-panel:nth-of-type(5),
.rb-tabs > .rb-tab-radio:nth-of-type(6):checked ~ .rb-tab-panel:nth-of-type(6),
.rb-tabs > .rb-tab-radio:nth-of-type(7):checked ~ .rb-tab-panel:nth-of-type(7),
.rb-tabs > .rb-tab-radio:nth-of-type(8):checked ~ .rb-tab-panel:nth-of-type(8) {
  display: block;
}

/* ==========================================================================
   4. Scroller — replaces Carousel
   ==========================================================================
 *
 * A horizontally snapping strip. Touch swipe, trackpad, shift+wheel and
 * keyboard scrolling all come from the browser. No auto-advance: nothing in a
 * RopeBreak surface moves on its own.
 */

.rb-scroller {
  display: flex;
  gap: var(--space-4);
  padding-bottom: var(--space-2);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding-inline-start: var(--space-4);
  overscroll-behavior-x: contain;
}

.rb-scroller > * {
  flex: 0 0 auto;
  scroll-snap-align: start;
}

/* ==========================================================================
   5. Popover API — replaces Modal and Offcanvas
   ==========================================================================
 *
 * `<button popovertarget="x">` and `<div id="x" popover>` are a complete
 * overlay with no script: the browser opens and closes it, Escape dismisses, a
 * click outside dismisses, focus moves in as you tab and returns to the
 * trigger on close, and the element renders in the top layer so no ancestor's
 * overflow or z-index can trap it.
 *
 * One honest limit: `popover` is NOT modal. Background content stays
 * interactive and focus is not trapped. So this is right for a detail peek, a
 * filter panel or a bulk-action preview, and wrong for anything that must not
 * be dismissed by accident. Destructive confirmations keep Django's own
 * confirmation page, which is a real URL and a real POST.
 *
 * Do not set `display` on these outside the fallback block below: the UA hides
 * a closed popover with `display: none`, and an author `display` would beat it
 * and leave the overlay permanently open.
 */

.rb-modal,
.rb-drawer {
  position: fixed;
  padding: 0;
  overflow: auto;
  color: var(--color-fg);
  background: var(--rb-admin-panel);
  border: 1px solid var(--rb-admin-line-strong);
}

.rb-modal {
  inset: 0;
  width: min(38rem, calc(100vw - 2rem));
  max-height: calc(100vh - 4rem);
  /* Centres in the viewport — the UA default for a popover. */
  margin: auto;
  /* Bracket frame. */
  border-inline-start: 3px solid var(--rb-gold-500);
}

.rb-drawer {
  inset: 0 auto 0 0;
  width: min(24rem, 85vw);
  /* The UA stylesheet gives [popover] `height: fit-content`, which wins over
   * the stretch implied by `top: 0; bottom: 0`. Say `auto` outright or the
   * drawer only grows as tall as its content. */
  height: auto;
  margin: 0;
  border-block: 0;
  border-inline-start: 0;
  border-inline-end: 1px solid var(--rb-gold-700);
}

.rb-drawer-end {
  inset: 0 0 0 auto;
  border-inline-start: 1px solid var(--rb-gold-700);
  border-inline-end: 0;
}

.rb-modal-header,
.rb-modal-footer {
  padding: var(--space-3) var(--space-4);
  background: var(--rb-admin-panel-sunk);
}

.rb-modal-header {
  border-bottom: 1px solid var(--rb-admin-line-strong);
}

.rb-modal-header > * {
  margin: 0;
}

.rb-modal-footer {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  border-top: 1px solid var(--rb-admin-line-strong);
}

.rb-modal-body {
  padding: var(--space-4);
}

/* Arena black-out. ::backdrop is a real element the browser paints for
 * top-layer content; it needs no markup. */
.rb-modal::backdrop,
.rb-drawer::backdrop {
  background: color-mix(in srgb, var(--rb-navy-900) 55%, black);
}

/*
 * Where the Popover API is missing, the trigger is a button that cannot work.
 * Hide it and let the content sit in the page as an ordinary panel: everything
 * stays readable and reachable, and only the overlay is lost. Written as
 * `@supports not` so the enhanced path is the default and this is the retreat.
 */
@supports not selector(:popover-open) {
  .rb-modal-trigger {
    display: none;
  }

  .rb-modal,
  .rb-drawer {
    position: static;
    display: block;
    width: auto;
    height: auto;
    max-height: none;
    margin: 0 0 var(--space-4);
  }
}

/* ==========================================================================
   6. Toast region — replaces Toast
   ==========================================================================
 *
 * Position only. The content is whatever the server rendered — normally the
 * messages framework. Nothing auto-dismisses: a notice that removes itself on
 * a timer is a notice some people never finish reading.
 */

.rb-toast-region {
  position: fixed;
  inset-inline-end: var(--space-4);
  inset-block-end: var(--space-4);
  z-index: var(--z-toast);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  width: min(24rem, calc(100vw - 2rem));
}

/* ==========================================================================
   7. Tooltip and hint
   ==========================================================================
 *
 * The text comes from `data-tip` and is drawn with a pseudo-element — no
 * script, no positioning library. Unlike the usual CSS tooltip this one also
 * opens on `:focus-within`, so a keyboard user reaching the control sees it
 * too; a hover-only tooltip is invisible to everyone without a mouse.
 *
 * Generated content is decoration: not selectable, not found by find-in-page,
 * not reliably announced. Anything a reader actually needs belongs in real
 * text or `.rb-hint`.
 */

.rb-tooltip {
  position: relative;
  display: inline-block;
}

.rb-tooltip::after {
  position: absolute;
  bottom: calc(100% + 0.4rem);
  left: 50%;
  z-index: var(--z-toast);
  width: max-content;
  max-width: 18rem;
  padding: var(--space-1) var(--space-2);
  font-family: var(--font-sans);
  font-size: var(--font-size-xs);
  line-height: var(--line-height-normal);
  color: var(--rb-cream-50);
  text-align: center;
  text-transform: none;
  letter-spacing: normal;
  content: attr(data-tip);
  background: color-mix(in srgb, var(--rb-navy-900) 55%, black);
  border: 1px solid var(--rb-gold-500);
  transform: translateX(-50%);
  visibility: hidden;
  opacity: 0;
  transition: opacity var(--duration-fast) linear;
}

.rb-tooltip:hover::after,
.rb-tooltip:focus-within::after {
  visibility: visible;
  opacity: 1;
}

.rb-tooltip-bottom::after {
  top: calc(100% + 0.4rem);
  bottom: auto;
}

/* When the information matters, don't hide it behind a hover at all. */
.rb-hint {
  display: block;
  margin-top: var(--space-1);
  font-size: var(--font-size-xs);
  color: var(--color-fg-muted);
}

/* `title` is the tooltip. Marking the element makes the affordance visible
 * rather than leaving it to a hover nobody discovers. */
.rb-has-title[title] {
  text-decoration: underline dotted;
  text-underline-offset: 0.2em;
  cursor: help;
}

/* ==========================================================================
   8. Alert — a standing notice inside a page
   ==========================================================================
 *
 * Django's `messagelist` is for the outcome of the request just made. This is
 * for a condition that is simply true of the record on screen: "this event
 * has no confirmed broadcast", "three sources disagree about this bout". It
 * has no dismiss control, because a dismissible alert with no script is a dead
 * button, and because a standing condition should not be dismissible anyway.
 */

.rb-alert {
  padding: var(--space-3) var(--space-4);
  margin: 0 0 var(--space-4);
  color: var(--color-fg);
  background: var(--rb-admin-panel-sunk);
  border: 1px solid var(--rb-admin-line-strong);
  border-inline-start: 3px solid var(--rb-navy-300);
}

.rb-alert > :first-child {
  margin-top: 0;
}

.rb-alert > :last-child {
  margin-bottom: 0;
}

.rb-alert-title {
  margin: 0 0 var(--space-1);
  font-family: var(--font-sans);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-bold);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--rb-gold-500);
}

.rb-alert--info {
  border-inline-start-color: var(--rb-navy-300);
}

.rb-alert--success {
  border-inline-start-color: var(--rb-green-600);
  background: color-mix(in srgb, var(--rb-green-600) 12%, var(--rb-navy-900));
}

.rb-alert--warning {
  border-inline-start-color: var(--rb-gold-500);
  background: color-mix(in srgb, var(--rb-gold-700) 14%, var(--rb-navy-900));
}

.rb-alert--danger {
  border-inline-start-color: var(--rb-red-600);
  background: color-mix(in srgb, var(--rb-red-600) 14%, var(--rb-navy-900));
}

.rb-alert--danger .rb-alert-title {
  color: var(--rb-admin-danger-fg);
}

/* ==========================================================================
   9. Panel — replaces Card
   ========================================================================== */

.rb-panel {
  margin: 0 0 var(--space-5);
  background: var(--rb-admin-panel-sunk);
  border: 1px solid var(--rb-admin-line);
}

/* Bracket frame — square, gold spine. For a panel carrying card-of-matches or
 * tournament data, which in an admin is most of them. */
.rb-panel--bracket {
  border-inline-start: 3px solid var(--rb-gold-500);
}

.rb-panel-header {
  padding: var(--space-2) var(--space-3);
  font-family: var(--font-sans);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-bold);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--rb-gold-500);
  background: var(--rb-admin-panel);
  border-bottom: 1px solid var(--rb-admin-line-strong);
}

.rb-panel-body {
  padding: var(--space-4);
}

.rb-panel-body > :first-child {
  margin-top: 0;
}

.rb-panel-body > :last-child {
  margin-bottom: 0;
}

.rb-panel-footer {
  padding: var(--space-2) var(--space-3);
  background: var(--rb-admin-panel);
  border-top: 1px solid var(--rb-admin-line-strong);
}

/* A row of panels that wraps. The admin's own `.module` grid doesn't apply
 * outside the dashboard, so surfaces that need one say so. */
.rb-panel-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
  gap: var(--space-4);
}

/* ==========================================================================
   10. List — replaces List group
   ========================================================================== */

.rb-list {
  padding: 0;
  margin: 0;
  list-style: none;
  border: 1px solid var(--rb-admin-line);
}

.rb-list > li {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--rb-admin-line);
}

.rb-list > li:last-child {
  border-bottom: 0;
}

.rb-list > li.rb-list-active {
  background: var(--rb-admin-gold-wash);
  box-shadow: inset 3px 0 0 0 var(--rb-gold-500);
}

a.rb-list-item:link,
a.rb-list-item:visited {
  color: var(--color-fg);
  text-decoration: none;
}

a.rb-list-item:focus,
a.rb-list-item:hover {
  color: var(--rb-gold-300);
}

/* ==========================================================================
   11. Buttons — the house button, outside a form
   ==========================================================================
 *
 * Django styles `.button` and `input[type=submit]`, and the theme restyles
 * those. These are for the places an admin renders its own controls — a
 * readonly field, a custom view, a modal footer — where `.button` would be
 * misleading because there is no form.
 */

.rb-btn {
  display: inline-block;
  padding: var(--space-2) var(--space-4);
  font-family: var(--font-sans);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  letter-spacing: 0.04em;
  color: var(--rb-cream-50);
  text-decoration: none;
  cursor: pointer;
  background: var(--rb-navy-500);
  border: 1px solid var(--rb-admin-line-strong);
}

a.rb-btn:link,
a.rb-btn:visited {
  color: var(--rb-cream-50);
  text-decoration: none;
}

.rb-btn:focus,
.rb-btn:hover {
  color: var(--rb-cream-50);
  background: color-mix(in srgb, var(--rb-navy-300) 70%, var(--rb-navy-500));
}

/* The championship button. One per surface — it's the primary action. */
.rb-btn--primary,
a.rb-btn--primary:link,
a.rb-btn--primary:visited {
  color: var(--rb-navy-900);
  background: var(--rb-gold-500);
  border-color: var(--rb-gold-700);
  font-weight: var(--font-weight-bold);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.rb-btn--primary:focus,
.rb-btn--primary:hover {
  color: var(--rb-navy-900);
  background: var(--rb-gold-300);
}

.rb-btn--quiet,
a.rb-btn--quiet:link,
a.rb-btn--quiet:visited {
  color: var(--color-fg-muted);
  background: transparent;
}

.rb-btn--quiet:focus,
.rb-btn--quiet:hover {
  color: var(--rb-gold-300);
  background: var(--rb-admin-row-hover);
}

.rb-btn--danger,
a.rb-btn--danger:link,
a.rb-btn--danger:visited {
  color: var(--rb-cream-50);
  background: var(--rb-red-600);
  border-color: var(--rb-red-600);
}

.rb-btn--danger:focus,
.rb-btn--danger:hover {
  background: color-mix(in srgb, var(--rb-red-600) 75%, var(--rb-navy-900));
}

.rb-btn--sm {
  padding: var(--space-1) var(--space-2);
  font-size: var(--font-size-xs);
}

.rb-btn[disabled],
.rb-btn[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Button group — segmented controls, filter switches, per-row action sets. */
.rb-btn-group {
  display: inline-flex;
  flex-wrap: wrap;
}

.rb-btn-group > .rb-btn + .rb-btn {
  border-inline-start: 0;
}

/* Toolbar — a row of controls above a table or panel. */
.rb-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
}

.rb-toolbar-spacer {
  flex: 1;
}

/* ==========================================================================
   12. Input group — replaces Input group
   ========================================================================== */

.rb-input-group {
  display: flex;
  flex-wrap: nowrap;
  align-items: stretch;
}

.rb-input-group > input,
.rb-input-group > select {
  flex: 1;
  min-width: 0;
  margin: 0;
}

.rb-input-group > .rb-btn,
.rb-input-group > .rb-input-addon {
  flex: none;
}

.rb-input-group > * + * {
  margin-inline-start: -1px;
}

.rb-input-addon {
  display: flex;
  align-items: center;
  padding: var(--space-2) var(--space-3);
  font-size: var(--font-size-sm);
  color: var(--color-fg-muted);
  white-space: nowrap;
  background: var(--rb-admin-panel);
  border: 1px solid var(--rb-admin-line-strong);
}

/* ==========================================================================
   13. Layout utilities
   ==========================================================================
 *
 * A deliberately small set. This is not a utility framework — the public side
 * has Bootstrap for that. These are the handful an admin surface needs to lay
 * out the components above without reaching for inline styles, which is the
 * thing they exist to prevent.
 */

.rb-stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.rb-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

.rb-split {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
}

.rb-quiet {
  color: var(--color-fg-muted);
}

.rb-scroll-x {
  overflow-x: auto;
}

/* ==========================================================================
   14. Pattern library
   ==========================================================================
 *
 * Chrome for the reference page at /admin/patterns/. Scoped to it, because the
 * page exists to show the components rather than to be one.
 */

.rb-patterns-section {
  margin: var(--space-6) 0 var(--space-3);
  padding-bottom: var(--space-2);
  font-family: var(--font-sans);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-bold);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--rb-gold-500);
  border-bottom: 1px solid var(--rb-admin-line-strong);
}

/* Components are shown on the page's own canvas, not on a panel tint, so a
 * badge or a chip reads the way it will in a changelist cell. */
.rb-patterns-demo {
  padding: var(--space-3);
  background: var(--rb-admin-canvas);
  border: 1px dashed var(--rb-admin-line);
}

.rb-patterns-demo > .rb-panel:last-child,
.rb-patterns-demo > .rb-alert:last-child {
  margin-bottom: 0;
}

.rb-patterns-demo pre {
  white-space: pre-wrap;
}

.rb-panel-footer pre {
  margin: 0;
  font-size: var(--font-size-xs);
  white-space: pre-wrap;
  word-break: break-word;
}
