/* ============================================================
   tacklebox-extras.css
   The few things Tacklebox needs that Tabler 1.6 doesn't have.
   Load after tacklebox-theme.css.

   Every class here starts with "tbx-". Anything without that
   prefix in a template is Tabler's (or Bootstrap's), and its
   markup is documented at docs.tabler.io.

   Before adding to this file, check Tabler again: a component
   it already ships is always preferred over one of ours.
   ============================================================ */

/* ---------- 1. The Ember button ---------------------------------------------
   The one creative action on a page ("Generate license"). At most one per
   page. Built from Tabler's own button variables, so it behaves like any
   .btn: sizes, icons, loading, disabled.                                   */
.tbx-btn-ember {
  --tblr-btn-color: var(--tbx-on-accent);
  --tblr-btn-bg: var(--tbx-heat);
  --tblr-btn-border-color: transparent;
  --tblr-btn-hover-color: var(--tbx-on-accent);
  --tblr-btn-hover-bg: var(--tbx-heat-deep);
  --tblr-btn-hover-border-color: transparent;
  --tblr-btn-active-color: var(--tbx-on-accent);
  --tblr-btn-active-bg: var(--tbx-heat-deep);
  --tblr-btn-active-border-color: transparent;
  --tblr-btn-disabled-color: var(--tbx-on-accent);
  --tblr-btn-disabled-bg: var(--tbx-heat);
  --tblr-btn-disabled-border-color: transparent;
}

/* ---------- 2. Sidebar details ------------------------------------------------ */
/* The area name at the top of a fly-out menu. Hidden while the sidebar is
   open, because the area's own row already says it. */
.tbx-flyout-title { display: none; }
html[data-bs-sidebar^=folded] .navbar-vertical .tbx-flyout-title {
  display: block;
  padding: var(--tbx-3) 10px var(--tbx-2);
  font-size: var(--tbx-fs-micro);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--tbx-muted);
}
/* The theme choice in the user menu: a check marks the current one
   (aria-pressed, kept in step by tacklebox.js). */
[data-tbx-theme-choice][aria-pressed=false] .tbx-theme-check { visibility: hidden; }
/* The collapse button swaps its icon with the state. */
[data-tbx-sidebar-toggle] .tbx-when-open { display: inline-flex; }
[data-tbx-sidebar-toggle] .tbx-when-folded { display: none; }
html[data-bs-sidebar^=folded] [data-tbx-sidebar-toggle] .tbx-when-folded { display: inline-flex; }
html[data-bs-sidebar^=folded] [data-tbx-sidebar-toggle] .tbx-when-open { display: none; }

/* ---------- 2b. Toolbar --------------------------------------------------------
   toolbar() (_table.jinja2.html) is a flex row with gap-2; its items are the
   controls themselves. A search field in it takes this class (agreed
   2026-10-05): it starts at 16rem and grows to 22rem, so it fills its line on
   a phone and is about a third of the bar on a wide screen, with no breakpoints. */
.tbx-toolbar-search { flex: 1 1 16rem; max-width: 22rem; }
/* A select or field placed straight in the bar takes its own width: Bootstrap gives them
   width: 100%, which in a flex row would put each on a line of its own. */
.card-header[data-tbx-toolbar] > * > :is(.form-select, .form-control) { width: auto; }

/* ---------- 3. Bulk action bar ------------------------------------------------
   Replaces the table's toolbar while rows are selected: a sunken strip in
   the theme's own colors, so it sits with the page in light and dark alike
   (it was a dark slab; Matt asked for it to match, 2026-10-10).
   tacklebox.js shows and hides it.                                          */
.tbx-bulkbar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--tbx-4);
  align-items: center;
  min-height: 46px;
  padding: var(--tbx-4) var(--tbx-6);
  color: var(--tbx-ink);
  background: var(--tbx-sunken);
  border-bottom: 1px solid var(--tbx-line);
  border-radius: calc(var(--tbx-r) - 1px) calc(var(--tbx-r) - 1px) 0 0;
}
.tbx-bulkbar[hidden] { display: none; }
.tbx-bulkbar-count { margin-inline-end: var(--tbx-4); font-size: var(--tbx-fs-sm); font-weight: 600; }
.tbx-bulkbar-end { margin-inline-start: auto; }
@media (max-width: 767.98px) {
  .tbx-bulkbar {
    position: fixed;
    inset: auto 0 0 0;
    z-index: 1030;
    padding-bottom: calc(var(--tbx-4) + env(safe-area-inset-bottom));
    border-radius: 0;
    box-shadow: var(--tbx-shadow-pop);
  }
}

/* ---------- 3b. Acting as someone --------------------------------------------
   The bar across the top of every page while a superuser uses the site as
   another person (tacklebox.impersonation; base.jinja2.html). The same
   always-dark slab as the bulk bar, so it too reads as a mode, and it stays
   in view while the page scrolls. One action: the way back.                 */
.tbx-acting-bar {
  position: sticky;
  top: 0;
  z-index: 1020;
  color: var(--tbx-on-inverse);
  background: var(--tbx-inverse);
  font-size: var(--tbx-fs-sm);
}
.tbx-acting-bar > .container-xl {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--tbx-3) var(--tbx-4);
  min-height: 40px;
  padding-block: var(--tbx-3);
}
.tbx-acting-bar > .container-xl > .icon { flex: none; }
.tbx-acting-bar-text { min-width: 0; }
.tbx-acting-bar-note { opacity: 0.72; }
.tbx-acting-bar-end { margin-inline-start: auto; }
@media (max-width: 575.98px) {
  .tbx-acting-bar-note { display: none; }
}

/* ---------- 3c. A badge in an own color ---------------------------------------
   A group or a tag colored with "My own color" (components/tbx/_badge:
   badge_class / badge_style set --tbx-badge-hue to the hex). The same
   treatment as a category hue: a 10% tint of the color for the fill, and
   for the text the color itself taken down to ink lightness (up, in the
   dark theme), as the --tbx-cat-*-ink tokens are cut from their hues.     */
.tbx-badge-custom {
  --tbx-badge-hue: var(--tbx-cat-blue);
  color: oklch(from var(--tbx-badge-hue) 0.44 min(c, 0.16) h) !important;
  background-color: color-mix(in oklab, var(--tbx-badge-hue) 10%, transparent) !important;
}
[data-bs-theme="dark"] .tbx-badge-custom,
[data-theme="dark"] .tbx-badge-custom {
  color: oklch(from var(--tbx-badge-hue) 0.82 min(c, 0.12) h) !important;
}

/* ---------- 4. Tables ---------------------------------------------------------- */
/* Group header rows in a grouped table. Sticky under the column headers. */
.tbx-group-row > th,
.tbx-group-row > td {
  position: sticky;
  top: 0;
  z-index: 1;
  height: 28px;
  font-size: var(--tbx-fs-tiny);
  font-weight: 600;
  color: var(--tbx-ink-2);
  background: var(--tbx-sunken);
}
.tbx-group-count { margin-inline-start: var(--tbx-3); font-weight: 400; color: var(--tbx-muted); }

/* Markdown in a table cell (a note on a reference list's entry): the cell's own
   size and line height, paragraphs close together. Tabler's .markdown is reading
   prose: h3-sized, loose lines. */
.markdown.tbx-markdown-cell { font-size: inherit; line-height: inherit; }
.markdown.tbx-markdown-cell > * { margin-bottom: var(--tbx-2); }
.markdown.tbx-markdown-cell > :last-child { margin-bottom: 0; }

/* A row a link points at (…#unit-4) shows as a selected row does, and stops a
   little below the top edge rather than flush against it. */
.table tr:target > * { --tblr-table-bg-state: var(--tblr-table-active-bg); }
.table tr:target { scroll-margin-top: var(--tbx-9); }

/* Keep the identifying column in view while a wide table scrolls sideways. */
.tbx-table-pin > :not(caption) > tr > :first-child {
  position: sticky;
  inset-inline-start: 0;
  z-index: 1;
  background: var(--tbx-raise);
  box-shadow: inset -1px 0 0 var(--tbx-line);
}
.tbx-table-pin > thead > tr > :first-child { background: var(--tbx-sunken); }

/* Column resize handle, added by tacklebox.js to tables with
   data-tbx-resizable. */
.tbx-th-resize {
  position: absolute;
  inset-block: 0;
  inset-inline-end: -3px;
  width: 7px;
  cursor: col-resize;
}
[data-tbx-resizable] th { position: relative; }
.tbx-th-resize:hover,
.is-resizing .tbx-th-resize { background: color-mix(in oklab, var(--tbx-link) 35%, transparent); }
.is-resizing { cursor: col-resize; user-select: none; }

/* The inline page size in a table's footer (components/tbx/_pagination:
   page_size_control). Plain text in the sentence until pointed at (an
   outline) or focused (a field); red while out of its 5 to 500 range. */
.tbx-page-size {
  display: inline-block;
  min-width: 2.5ch;
  padding: 0 2px;
  margin: -1px 0;
  font: inherit;
  font-variant-numeric: tabular-nums;
  line-height: inherit;
  color: inherit;
  text-align: center;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--tbx-r-sm);
  -moz-appearance: textfield;
  appearance: textfield;
}
.tbx-page-size::-webkit-outer-spin-button,
.tbx-page-size::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.tbx-page-size:hover { border-color: var(--tbx-line-strong); }
.tbx-page-size:focus { color: var(--tbx-ink); background: var(--tbx-raise); border-color: var(--tbx-link); outline: 0; }
.tbx-page-size:invalid,
.tbx-page-size.is-invalid { color: var(--tbx-danger); border-color: var(--tbx-danger); }

/* ---------- 4b. Groups and their permissions -----------------------------------
   The Groups page (Admin → Groups): the groups on the left, in their drag
   order, with Superusers fixed at the top; the chosen group's permissions on
   the right, one capability per row. The rows are links (?group=…), so the
   page works without JavaScript; tacklebox.js ([data-tbx-roles]) switches
   panels in place and keeps the counts in step. Below 600px of card width
   the list gives way to a select. (The classes keep their first name, roles.) */
.tbx-roles { container-type: inline-size; }
.tbx-roles-grid {
  display: grid;
  grid-template-columns: minmax(13rem, 17rem) minmax(0, 1fr);
  border-block: 1px solid var(--tbx-line-faint);
}
.tbx-roles-list { border-inline-end: 1px solid var(--tbx-line); }
.tbx-roles-list .list-group-item {
  display: flex;
  align-items: center;
  gap: var(--tbx-4);
  padding: 7px var(--tbx-5) 7px var(--tbx-6);
  text-align: start;
}
.tbx-roles-count {
  margin-inline-start: auto;
  font-size: var(--tbx-fs-sm);
  color: var(--tbx-muted);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
/* A row: the drag handle, the group (the link that picks it), the member count.
   Superusers' row has no handle; a gap keeps its badge in line with the rest. */
.tbx-roles-list .tbx-drag-handle { margin-inline-start: calc(-1 * var(--tbx-3)); }
.tbx-roles-handle-gap { flex: none; width: 20px; }
.tbx-roles-pick-link { flex: 1 1 auto; min-width: 0; color: inherit; text-decoration: none; }
.tbx-roles-pick-link:hover { text-decoration: none; }
.tbx-roles-fixed { border-bottom: 1px solid var(--tbx-line); }
.tbx-roles-list .list-group-item.active { z-index: 0; }
.tbx-roles-actions { padding: var(--tbx-5) var(--tbx-6); border-top: 1px solid var(--tbx-line-faint); }
.tbx-roles-pick { display: none; padding: var(--tbx-5) var(--tbx-6) 0; }
.tbx-roles-detail { min-width: 0; }
.tbx-roles-head { display: flex; align-items: baseline; gap: var(--tbx-5); padding: 14px var(--tbx-6) var(--tbx-5); }
.tbx-roles-head h3 { margin: 0; }
.tbx-roles-head .tbx-roles-count { margin-inline-start: auto; }
/* The check and name columns are fixed, so every name starts on one line and
   every description on another. Area rows are .tbx-group-row. */
.tbx-roles-table { table-layout: fixed; width: 100%; margin: 0; border-top: 1px solid var(--tbx-line-faint); }
.tbx-roles-table .tbx-roles-col-check { width: calc(var(--tbx-6) + 15px + var(--tbx-2)); }
.tbx-roles-table .tbx-roles-col-name { width: 10.5rem; }
.tbx-roles-table > tbody > tr > td { padding-block: 5px; vertical-align: top; }
.tbx-roles-table > tbody > tr > td:first-child { padding-inline-end: 0; }
.tbx-roles-table .form-check-input { margin-top: 1px; }
.tbx-roles-table label { display: block; margin: 0; cursor: pointer; }
.tbx-roles-table .tbx-roles-what { color: var(--tbx-muted); }
.tbx-roles-table > tbody > tr:last-child > td { border-bottom-width: 0; }
@container (max-width: 600px) {
  .tbx-roles-grid { grid-template-columns: minmax(0, 1fr); }
  .tbx-roles.is-ready .tbx-roles-list { display: none; }
  .tbx-roles.is-ready .tbx-roles-pick { display: block; }
  .tbx-roles-table .tbx-roles-col-name { width: 7.5rem; }
}

/* ---------- 5. Reordering -------------------------------------------------------
   A list the user puts in order by dragging the handle, or with the
   keyboard. Works on a Tabler .list-group or on table rows.                */
.tbx-drag-handle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  padding: 0;
  color: var(--tbx-faint);
  cursor: grab;
  touch-action: none;
  background: none;
  border: 0;
  border-radius: var(--tbx-r-sm);
}
.tbx-drag-handle:hover { color: var(--tbx-ink-2); background: var(--tbx-hover); }
.tbx-drag-handle:focus-visible { outline: 2px solid var(--tbx-link); outline-offset: 1px; }
.tbx-reorder-pos { min-width: 1.5em; color: var(--tbx-muted); text-align: end; }
[data-tbx-reorder-item].is-dragging,
[data-tbx-reorder-item].is-grabbed {
  position: relative;
  z-index: 2;
  background: var(--tbx-selected);
  outline: 2px solid var(--tbx-link);
  outline-offset: -2px;
}
[data-tbx-reorder-item].is-dragging { box-shadow: var(--tbx-shadow-2); }
[data-tbx-reorder-item].is-dragging .tbx-drag-handle { cursor: grabbing; }
[data-tbx-reorder-item].is-settling { transition: transform var(--tbx-speed) var(--tbx-ease); }
.is-reordering { user-select: none; }

/* ---------- 5b. Filter rail ------------------------------------------------------
   The filters of a list page, in a column left of the table's card
   (components/tbx/_filters.jinja2.html). As wide as the sidebar from 768px up,
   full width above the table on phones. The table's column may shrink past
   its content, so a wide table scrolls inside its card instead of pushing out. */
@media (min-width: 768px) {
  .tbx-filter-rail { flex: 0 0 auto; width: 240px; }
}
.tbx-filter-rail ~ .col { min-width: 0; }
.tbx-filter-rail[hidden] { display: none; }
/* The From and To labels of a date range share one width, so the two fields
   line up. It is the width of the text alone (content-box): the label's
   padding and border are added to it. In em, so it follows the label's font
   size at any zoom or text size setting. "From" in Inter measures 2.38em to
   2.52em between 10.5px and 24px (glyphs snap to whole pixels); 2.6em is the
   narrowest round value that holds it at all of them. */
.tbx-range-label { box-sizing: content-box; width: 2.6em; }

/* ---------- 5c. A list redrawing in place ---------------------------------------
   While htmx fetches the list's region (a filter, a sort, a page), it fades a
   little; only past 150ms, so a quick answer shows no flicker. */
.tbx-list .card { transition: opacity var(--tbx-speed) var(--tbx-ease); }
.tbx-list.htmx-request .card { opacity: 0.6; transition-delay: var(--tbx-speed); }
@media (prefers-reduced-motion: reduce) { .tbx-list .card { transition: none; } }

/* ---------- 5d. Site map ---------------------------------------------------------
   Maps (static/js/maps.js, MapLibre GL JS): the Sites list's map, a site's map page and its thumbnail. The map fills
   its card; its popups are themed like our menus, not the library's white box. */
.tbx-site-map { width: 100%; aspect-ratio: 16 / 9; min-height: 25rem; border-radius: 0 0 var(--tbx-r) var(--tbx-r); }
.tbx-site-map-tall { aspect-ratio: 4 / 3; min-height: 30rem; }
/* The Sites list's map, above the table: shorter, so the rows stay in view. */
.tbx-site-map-list { aspect-ratio: auto; height: 22rem; min-height: 0; border-radius: 0; }
/* The site page's thumbnail: a still map under the card header, the width of the card. */
.tbx-site-map-thumb { aspect-ratio: 4 / 3; min-height: 0; border-radius: 0; border-bottom: 1px solid var(--tbx-line); cursor: pointer; }
.tbx-site-map-thumb .maplibregl-canvas { cursor: pointer; }
.tbx-site-map .maplibregl-popup-content {
  padding: var(--tbx-4) var(--tbx-5);
  font: inherit;
  color: var(--tbx-ink);
  background: var(--tbx-raise);
  border: 1px solid var(--tbx-faint);         /* ~3:1 on the popup in both themes; --tbx-line is too faint over a map */
  border-radius: var(--tbx-r);
  box-shadow: var(--tbx-shadow-2);
}
/* The popup's pointer: MapLibre draws it as a border triangle. It is drawn here in the outline's
   color, and a triangle in the popup's color sits inside it (::after), 1px in and 1px over the
   box's edge, so the fill and the outline run on unbroken from the box into the pointer. */
.tbx-site-map .maplibregl-popup-tip { position: relative; z-index: 1; border-color: transparent; }
.tbx-site-map .maplibregl-popup-tip::after { content: ""; position: absolute; width: 0; height: 0; border: 9px solid transparent; }
.tbx-site-map [class*="maplibregl-popup-anchor-bottom"] .maplibregl-popup-tip { border-top-color: var(--tbx-faint); }
.tbx-site-map [class*="maplibregl-popup-anchor-bottom"] .maplibregl-popup-tip::after { left: -9px; top: -11px; border-bottom-width: 0; border-top-color: var(--tbx-raise); }
.tbx-site-map [class*="maplibregl-popup-anchor-top"] .maplibregl-popup-tip { border-bottom-color: var(--tbx-faint); }
.tbx-site-map [class*="maplibregl-popup-anchor-top"] .maplibregl-popup-tip::after { left: -9px; top: 2px; border-top-width: 0; border-bottom-color: var(--tbx-raise); }
.tbx-site-map .maplibregl-popup-anchor-left .maplibregl-popup-tip { border-right-color: var(--tbx-faint); }
.tbx-site-map .maplibregl-popup-anchor-left .maplibregl-popup-tip::after { top: -9px; left: 2px; border-left-width: 0; border-right-color: var(--tbx-raise); }
.tbx-site-map .maplibregl-popup-anchor-right .maplibregl-popup-tip { border-left-color: var(--tbx-faint); }
.tbx-site-map .maplibregl-popup-anchor-right .maplibregl-popup-tip::after { top: -9px; left: -11px; border-right-width: 0; border-left-color: var(--tbx-raise); }
/* A site with weather is marked by its temperature, tinted by its band: freezing or cold, now or forecast. */
.tbx-map-temp {
  padding: var(--tbx-1) var(--tbx-3);
  font-size: var(--tbx-fs-sm);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--tbx-ink);
  background: var(--tbx-raise);
  border: 1px solid var(--tbx-line-strong);
  border-radius: var(--tbx-r);
  box-shadow: var(--tbx-shadow-2);
  cursor: pointer;
  white-space: nowrap;
}
.tbx-map-temp.is-freezing { background: var(--tbx-danger-wash); border-color: var(--tbx-danger); }
.tbx-map-temp.is-cold { background: var(--tbx-warn-wash); border-color: var(--tbx-warn); }

/* ---------- 5e. Comments ---------------------------------------------------------
   A reply indents under what it answers, a step per level up to four, with
   a line down its left. Reply and Delete open in place (<details>).        */
.tbx-reply { border-left: 1px solid var(--tbx-line); padding-left: var(--tbx-5); }
.tbx-reply-1 { margin-left: var(--tbx-6); }
.tbx-reply-2 { margin-left: calc(var(--tbx-6) * 2); }
.tbx-reply-3 { margin-left: calc(var(--tbx-6) * 3); }
.tbx-reply-4 { margin-left: calc(var(--tbx-6) * 4); }
@media (max-width: 575.98px) { .tbx-reply-2, .tbx-reply-3, .tbx-reply-4 { margin-left: var(--tbx-6); } }
.tbx-inline-action > summary { cursor: pointer; list-style: none; }
.tbx-inline-action > summary::-webkit-details-marker { display: none; }
.tbx-inline-action[open] { flex-basis: 100%; }

/* ---------- 5f. Data Model: an object type's Overview ----------------------------
   The one card of facts (datamodel/object_type_detail): a grid of labelled
   values on the left, the cartridge in a column on the right, and the history
   by cartridge below it, each cartridge a <details> with its change sets. */
.tbx-ov { display: flex; flex-wrap: wrap; gap: var(--tbx-6) 40px; align-items: stretch; }
.tbx-ov-main { flex: 999 1 520px; min-width: 0; display: flex; flex-direction: column; gap: var(--tbx-6); }
.tbx-ov-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: var(--tbx-5) var(--tbx-8); }
.tbx-ov-value { margin-top: 2px; font-size: var(--tbx-fs-md); font-weight: 600; }
.tbx-ov-value + .tbx-ov-value { margin-top: var(--tbx-3); }
.tbx-ov-big { font-size: var(--tbx-fs-xl); font-weight: 600; }
.tbx-ov-ghost { margin-inline-start: calc(-1 * var(--tbx-3)); }
.tbx-ov-desc { border-top: 1px solid var(--tbx-line-faint); padding-top: var(--tbx-5); }
.tbx-ov-text { margin-top: var(--tbx-2); font-size: var(--tbx-fs-md); white-space: pre-line; }
.tbx-ov-cart { flex: 1 1 240px; max-width: 320px; display: flex; flex-direction: column; gap: var(--tbx-3); padding-inline-start: var(--tbx-7); border-inline-start: 1px solid var(--tbx-line-faint); }
.tbx-ov-pending { padding: var(--tbx-3) var(--tbx-4); border-radius: var(--tbx-r); background: var(--tbx-warn-wash); }
@media (max-width: 820px) { .tbx-ov-cart { padding-inline-start: 0; border-inline-start: 0; max-width: none; } }
/* The history card. A group is a <details>: its summary is the heading row, the chevron turns when open. */
.tbx-hist-comment { border-bottom: 1px solid var(--tbx-line-faint); }
.tbx-hist-comment > summary { display: inline-flex; margin: var(--tbx-3) var(--tbx-4); list-style: none; }
.tbx-hist-comment > summary::-webkit-details-marker { display: none; }
.tbx-hist-group { border-top: 1px solid var(--tbx-line-faint); }
.tbx-hist-group:first-of-type { border-top: 0; }
.tbx-hist-head { display: flex; align-items: center; gap: var(--tbx-3); padding: var(--tbx-4) var(--tbx-6); cursor: pointer; list-style: none; }
.tbx-hist-head::-webkit-details-marker { display: none; }
.tbx-hist-head:hover { background: var(--tbx-hover); }
.tbx-hist-chev { display: inline-flex; color: var(--tbx-muted); transition: transform var(--tbx-speed) var(--tbx-ease); }
.tbx-hist-group[open] > .tbx-hist-head .tbx-hist-chev { transform: rotate(90deg); }
.tbx-hist-note { padding: 0 var(--tbx-6) var(--tbx-4) 38px; font-size: var(--tbx-fs-sm); color: var(--tbx-ink-2); }
.tbx-hist-set { padding: var(--tbx-3) var(--tbx-6) var(--tbx-3) 38px; border-top: 1px dashed var(--tbx-line-faint); font-size: var(--tbx-fs-sm); }
.tbx-hist-row { display: flex; gap: var(--tbx-4); align-items: baseline; }
.tbx-hist-when { flex: none; width: 112px; font-variant-numeric: tabular-nums; }
.tbx-hist-when time { white-space: nowrap; }
.tbx-hist-text { min-width: 0; flex: 1 1 auto; }
.tbx-hist-why, .tbx-hist-more, .tbx-hist-lines { margin-inline-start: calc(112px + var(--tbx-4)); }
.tbx-hist-more > summary { display: inline-flex; margin: var(--tbx-2) 0 0 calc(-1 * var(--tbx-3)); list-style: none; }
.tbx-hist-more > summary::-webkit-details-marker { display: none; }
.tbx-hist-more[open] > summary .tbx-hist-show, .tbx-hist-more:not([open]) > summary .tbx-hist-hide { display: none; }
.tbx-hist-lines { margin-top: var(--tbx-2); margin-bottom: 0; padding-inline-start: var(--tbx-5); color: var(--tbx-ink-2); }
/* The tabs of an object type's page (datamodel/_type_page): a bar above the tab's
   card, the current one underlined in the heat color, a count after each title. */
.tbx-tabs { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 2px; margin-bottom: var(--tbx-5); border-bottom: 1px solid var(--tbx-line); }
.tbx-tab { display: inline-flex; align-items: center; gap: 4px; padding: var(--tbx-3) var(--tbx-5); margin-bottom: -1px; border-bottom: 2px solid transparent; color: var(--tbx-ink-2); text-decoration: none; white-space: nowrap; }
.tbx-tab:hover { color: var(--tbx-ink); text-decoration: none; border-bottom-color: var(--tbx-line-strong); }
.tbx-tab.active { color: var(--tbx-ink); font-weight: 600; border-bottom-color: var(--tbx-heat); }
.tbx-tab-add { color: var(--tbx-link); }
.tbx-tab-add:hover { color: var(--tbx-link); }
@media (max-width: 575.98px) {
  .tbx-hist-row { flex-direction: column; gap: 0; }
  .tbx-hist-why, .tbx-hist-more, .tbx-hist-lines { margin-inline-start: 0; }
  .tbx-hist-note, .tbx-hist-set { padding-inline-start: var(--tbx-6); }
}

/* The Edit type drawer's parent rules (datamodel/_object_type_drawer): one box per
   parent, its read-back under the fields; a rule marked Remove folds to its warning. */
.tbx-rule { display: flex; flex-direction: column; gap: var(--tbx-4); padding: var(--tbx-4) var(--tbx-5); margin-bottom: var(--tbx-4); border: 1px solid var(--tbx-line); border-radius: var(--tbx-r); background: var(--tbx-sunken); }
.tbx-rule-head { display: flex; align-items: center; gap: var(--tbx-3); }
.tbx-rule-head .tbx-rule-parent { max-width: 240px; }
.tbx-rule-body { display: flex; flex-direction: column; gap: var(--tbx-4); }
.tbx-rule-summary { font-size: var(--tbx-fs-sm); color: var(--tbx-ink-2); border-top: 1px solid var(--tbx-line-faint); padding-top: var(--tbx-3); }
.tbx-rule-summary:empty { display: none; }
.tbx-rule-gone { display: none; }
.tbx-rule:has(input[name$="-DELETE"]:checked) .tbx-rule-body { display: none; }
.tbx-rule:has(input[name$="-DELETE"]:checked) .tbx-rule-gone { display: block; }
.tbx-rules-add { margin-inline-start: calc(-1 * var(--tbx-3)); }

/* ---------- 5g. Data Model: the Points tab ---------------------------------------
   The table with a card rail beside it (datamodel/type_points): "At a glance"
   (one value filters, pick it again to clear) with a pie per value, and
   "Worth a look". A variable chip is a {token} with an end cap saying where
   the point lives; an issue mark is a small "!" with the text in its tooltip. */
.tbx-points { display: flex; flex-wrap: wrap; gap: var(--tbx-6); align-items: flex-start; }
.tbx-points-main { flex: 999 1 680px; min-width: 0; }
.tbx-points-rail { flex: 1 1 260px; max-width: 320px; min-width: 0; position: sticky; top: var(--tbx-6); display: flex; flex-direction: column; gap: var(--tbx-6); max-height: calc(100vh - var(--tbx-8)); overflow-y: auto; }
.tbx-focus { display: flex; flex-wrap: wrap; gap: var(--tbx-3) var(--tbx-5); align-items: center; padding: 10px var(--tbx-6); background: var(--tbx-sunken); border-bottom: 1px solid var(--tbx-line); font-size: var(--tbx-fs-sm); }
.tbx-glance-head { padding: 10px var(--tbx-6) 4px; border-top: 1px solid var(--tbx-line); font-size: var(--tbx-fs-micro); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--tbx-muted); }
.card-header + .tbx-glance-head { border-top: 0; }
.tbx-glance-row { display: flex; gap: 10px; align-items: center; justify-content: space-between; width: 100%; border: 0; border-top: 1px solid var(--tbx-line-faint); background: transparent; color: var(--tbx-ink); font: inherit; font-size: var(--tbx-fs-sm); text-align: left; padding: 6px var(--tbx-6); text-decoration: none; }
.tbx-glance-head + .tbx-glance-row { border-top: 0; }
.tbx-glance-row:hover { background: var(--tbx-hover); color: var(--tbx-ink); text-decoration: none; }
.tbx-glance-row[aria-pressed="true"] { background: var(--tbx-hover); box-shadow: inset 3px 0 0 var(--tbx-heat); }
.tbx-glance-value { min-width: 0; overflow-wrap: anywhere; }
.tbx-glance-count { display: inline-flex; gap: 6px; align-items: center; flex: none; font-variant-numeric: tabular-nums; }
.tbx-glance-count .tbx-glance-n { min-width: 20px; text-align: right; }
.tbx-pie { display: inline-block; width: 14px; height: 14px; border-radius: 50%; box-shadow: inset 0 0 0 1px var(--tbx-line-strong); background: conic-gradient(var(--tbx-ink-2) 0 var(--tbx-pie-deg, 0deg), transparent 0); }
.tbx-look { padding: 10px var(--tbx-6); border-top: 1px solid var(--tbx-line-faint); font-size: var(--tbx-fs-sm); }
.card-header + .tbx-look { border-top: 0; }
.tbx-look-text { margin: 4px 0 2px; }
.tbx-look .btn-ghost { margin-inline-start: calc(-1 * var(--tbx-3)); }
.tbx-pill { font-size: var(--tbx-fs-tiny); font-weight: 600; border-radius: 3px; padding: 1px 5px; white-space: nowrap; flex: none; }
.tbx-pill-warn { color: var(--tbx-warn); background: var(--tbx-warn-wash); }
.tbx-pill-bad { color: var(--tbx-danger); background: var(--tbx-danger-wash); }
.tbx-pill-muted { color: var(--tbx-muted); background: var(--tbx-sunken); }
/* A rich suggestion (tacklebox.js initSuggest): two lines, a badge at the end; a disabled one stays readable. */
.dropdown-item.tbx-suggest-rich { display: flex; align-items: center; gap: var(--tbx-3); white-space: normal; padding-block: 7px; }
.dropdown-item.tbx-suggest-rich:disabled { opacity: 0.6; }
.dropdown-item.tbx-suggest-info { font-size: var(--tbx-fs-sm); color: var(--tbx-muted); }
.tbx-suggest-main { min-width: 0; flex: 1 1 auto; display: flex; flex-direction: column; }
.tbx-suggest-text { font-weight: 500; }
.tbx-suggest-meta { font-size: var(--tbx-fs-sm); color: var(--tbx-muted); font-family: var(--tbx-font-mono); font-size: var(--tbx-fs-tiny); }
.tbx-suggest-plus { flex: none; color: var(--tbx-link); font-weight: 600; }
.tbx-ap-copy { padding-top: var(--tbx-4); border-top: 1px solid var(--tbx-line-faint); }
.tbx-issue { display: inline-flex; width: 16px; height: 16px; border-radius: 50%; align-items: center; justify-content: center; font-size: 11px; font-weight: 700; line-height: 1; cursor: help; flex: none; margin-inline-start: 6px; vertical-align: middle; }
.tbx-issue-bad { background: var(--tbx-danger-wash); color: var(--tbx-danger); }
.tbx-issue-warn { background: var(--tbx-warn-wash); color: var(--tbx-warn); }
.tbx-var { display: inline-flex; align-items: stretch; vertical-align: baseline; border: 1px solid var(--tbx-line-strong); border-radius: var(--tbx-r-sm); overflow: hidden; font-size: var(--tbx-fs-sm); line-height: 1.5; color: var(--tbx-ink); background: var(--tbx-raise); cursor: help; }
.tbx-var-pre { padding: 0 0 0 5px; }
.tbx-var-name { font-family: var(--tbx-font-mono); font-size: var(--tbx-fs-tiny); padding: 0 5px; }
.tbx-var-src { display: inline-flex; align-items: center; justify-content: center; padding: 0 3px; min-width: 18px; background: var(--tbx-link-wash, var(--tbx-sunken)); color: var(--tbx-link); border-inline-start: 1px solid var(--tbx-line); }
.tbx-var-src .icon { width: 12px; height: 12px; stroke-width: 2.5; }

/* The citation chip, tbx-cite (addendum 5, item 43; components/tbx/_cite.jinja2.html): built like tbx-var. A link
   to a document, to a page of it when there is one; a deleted document is a plain span, struck through, its icon cell red. */
.tbx-cite { display: inline-flex; align-items: stretch; vertical-align: baseline; border: 1px solid var(--tbx-line-strong); border-radius: var(--tbx-r-sm); overflow: hidden; font-size: var(--tbx-fs-sm); line-height: 1.5; color: var(--tbx-ink); background: var(--tbx-raise); text-decoration: none; max-width: 100%; }
.tbx-cite:hover { color: var(--tbx-ink); text-decoration: none; border-color: var(--tbx-link); }
.tbx-cite-src { display: inline-flex; align-items: center; justify-content: center; padding: 0 4px; background: var(--tbx-link-wash, var(--tbx-sunken)); color: var(--tbx-link); border-inline-end: 1px solid var(--tbx-line); }
.tbx-cite-src .icon { width: 12px; height: 12px; stroke-width: 2.5; }
.tbx-cite-name { padding: 0 6px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 18ch; }
.tbx-cite-page { padding: 0 6px; border-inline-start: 1px solid var(--tbx-line); color: var(--tbx-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.tbx-cite-bad { cursor: help; }
.tbx-cite-bad .tbx-cite-src { background: var(--tbx-danger-wash, rgba(214, 57, 57, .12)); color: var(--tbx-danger, #d63939); }
.tbx-cite-bad .tbx-cite-name { text-decoration: line-through; color: var(--tbx-muted); }
/* The Upload drawer's drop zone (documents) */
.tbx-drop { border: 1px dashed var(--tbx-line-strong); border-radius: var(--tbx-r); padding: var(--tbx-6); text-align: center; background: var(--tbx-sunken); cursor: pointer; }
.tbx-drop:hover, .tbx-drop.is-over { border-color: var(--tbx-link); background: var(--tbx-link-wash, var(--tbx-sunken)); }
.tbx-drop input[type=file] { position: absolute; width: 1px; height: 1px; opacity: 0; overflow: hidden; }
.tbx-var-bad .tbx-var-src { background: var(--tbx-danger-wash); color: var(--tbx-danger); }
.tbx-td-point { min-width: 200px; }
/* The data point page: a cell unlike most types, the Else cell, the coverage meter, a Named in row. */
.tbx-unlike { text-decoration: underline dotted; text-underline-offset: 3px; cursor: help; }
.tbx-abbr { text-decoration: underline dotted; text-underline-offset: 3px; cursor: help; }
.tbx-else { display: inline-flex; flex-direction: column; gap: 4px; align-items: flex-start; white-space: nowrap; }
.tbx-else-line { display: inline-flex; gap: 4px; align-items: center; cursor: help; }
.tbx-rw { display: inline-flex; width: 14px; height: 14px; align-items: center; justify-content: center; border-radius: 3px; background: var(--tbx-sunken); color: var(--tbx-muted); font-size: 9px; font-weight: 700; line-height: 1; flex: none; }
.tbx-meter { display: inline-block; width: 56px; height: 6px; border-radius: 3px; background: var(--tbx-sunken); overflow: hidden; vertical-align: middle; box-shadow: inset 0 0 0 1px var(--tbx-line); }
.tbx-meter i { display: block; height: 100%; background: var(--tbx-ink-2); }
.tbx-named { display: grid; grid-template-columns: 96px minmax(0, 1fr); gap: var(--tbx-5); align-items: baseline; padding: var(--tbx-3) var(--tbx-6); border-top: 1px solid var(--tbx-line-faint); font-size: var(--tbx-fs-sm); }
.card-header + .tbx-named { border-top: 0; }
.tbx-facet .form-check-label { font-weight: 400; }
/* The protocol tabs (datamodel/type_map): a stat card, the offset check boxes, the bit strips (16 cells, or
   four bytes of 8), a mask with its hex, the function code cells, a collapsible register group. */
.tbx-stat { display: grid; grid-template-columns: 44px minmax(0, 1fr); column-gap: 10px; padding: var(--tbx-3) var(--tbx-6); border-top: 1px solid var(--tbx-line-faint); align-items: baseline; }
.card-header + .tbx-stat { border-top: 0; }
.tbx-stat-n { text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; font-size: var(--tbx-fs-md); }
.tbx-tone-bad { color: var(--tbx-danger); }
.tbx-tone-warn { color: var(--tbx-warn); }
.tbx-tone-muted { color: var(--tbx-muted); }
.tbx-req { color: var(--tbx-danger); margin-inline-start: 2px; }
.tbx-offsets { margin: 0; padding-inline-start: var(--tbx-5); }
.tbx-lbl { font-size: var(--tbx-fs-micro); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--tbx-muted); }
.tbx-oc { text-align: center; width: 60px; white-space: nowrap; }
.tbx-box { display: inline-flex; width: 16px; height: 16px; border-radius: 3px; border: 1.5px solid var(--tbx-muted); color: var(--tbx-muted); align-items: center; justify-content: center; font-size: 11px; font-weight: 700; line-height: 1; vertical-align: middle; }
.tbx-box.warn { border-color: var(--tbx-warn); background: var(--tbx-warn-wash); }
.tbx-mask { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.tbx-mask code { font-size: var(--tbx-fs-sm); cursor: help; }
.tbx-strip { display: inline-grid; grid-template-columns: repeat(16, 4px); gap: 1px; }
.tbx-strip-1 { grid-template-columns: 4px; }
.tbx-strip i, .tbx-s32 i { display: block; width: 4px; height: 12px; border-radius: 1px; background: transparent; box-shadow: inset 0 0 0 1px var(--tbx-line); }
.tbx-strip i.on, .tbx-s32 i.on { background: var(--tbx-ink-2); box-shadow: none; }
.tbx-strip i.mine, .tbx-s32 i.mine { background: var(--tbx-heat); box-shadow: none; }
.tbx-s32 { display: inline-flex; gap: 3px; }
.tbx-byte { display: inline-grid; grid-template-columns: repeat(8, 3px); gap: 1px; }
.tbx-s32 i { width: 3px; }
.tbx-reg { font-variant-numeric: tabular-nums; font-weight: 600; cursor: help; }
.tbx-fc { font-family: var(--tbx-font-mono); font-size: var(--tbx-fs-sm); white-space: nowrap; }
.tbx-cd { font-family: var(--tbx-font-mono); font-size: var(--tbx-fs-sm); white-space: nowrap; cursor: help; }
.tbx-cd-warn { color: var(--tbx-warn); background: var(--tbx-warn-wash); border-radius: 3px; padding: 1px 4px; }
.tbx-cd-bad { color: var(--tbx-danger); background: var(--tbx-danger-wash); border-radius: 3px; padding: 1px 4px; }
.tbx-cd-muted { color: var(--tbx-muted); }
.tbx-map-sub > td { background: var(--tbx-sunken); }
.tbx-map-group[aria-expanded="false"] ~ .tbx-map-sub { display: none; }
.tbx-map-toggle { padding: 0 4px; gap: 4px; }
.tbx-map-toggle .icon { transition: transform var(--tbx-speed) var(--tbx-ease); transform: rotate(90deg); }
.tbx-map-toggle[aria-expanded="false"] .icon { transform: rotate(0deg); }
.tbx-stp-n { display: inline-flex; width: 18px; height: 18px; border-radius: 50%; background: var(--tbx-sunken); color: var(--tbx-muted); font-size: var(--tbx-fs-micro); font-weight: 700; align-items: center; justify-content: center; }
.tbx-steps td { vertical-align: top; }
/* The object types device tree (datamodel/object_type_list): a chevron that turns when open, parts indented
   under their device with a connector, a note after a group heading. */
.tbx-tree-toggle { width: 24px; height: 24px; padding: 0; }
.tbx-tree-toggle .icon { transition: transform 150ms ease-in-out; }
.tbx-tree-toggle[aria-expanded="true"] .icon { transform: rotate(90deg); }
.tbx-tree-type { display: flex; align-items: center; gap: var(--tbx-3); min-width: 0; }
.tbx-tree-part .tbx-tree-type { padding-inline-start: 14px; }
.tbx-tree-part { background: var(--tbx-surface); }
.tbx-tree-connector { flex: none; width: 12px; height: 14px; margin-top: -10px; border-left: 1px solid var(--tbx-line-strong); border-bottom: 1px solid var(--tbx-line-strong); border-bottom-left-radius: 3px; }
.tbx-group-note { margin-inline-start: var(--tbx-3); font-weight: 400; text-transform: none; letter-spacing: 0; color: var(--tbx-muted); }
/* Checks (Library): the R | W outcome columns, a Worth a look card under the rail, the drawer's outcome cards */
.tbx-rw-col { width: 76px; white-space: nowrap; }
.tbx-sub-head th { padding-top: 2px; padding-bottom: 4px; font-size: var(--tbx-fs-micro); }
.tbx-look { padding: var(--tbx-3) var(--tbx-4); border-top: 1px solid var(--tbx-line-faint); font-size: var(--tbx-fs-sm); }
.tbx-look-rail { margin-top: var(--tbx-4); }
.tbx-ocard { display: flex; gap: var(--tbx-3); align-items: flex-start; margin: 0 0 var(--tbx-2); padding: var(--tbx-2) var(--tbx-3); border: 1px solid var(--tbx-line); border-radius: var(--tbx-r); cursor: pointer; }
.tbx-inline-when:not([hidden]) { display: inline-flex; gap: var(--tbx-2); align-items: center; }
.tbx-ocard:has(input:checked) { border-color: var(--tbx-heat); background: var(--tbx-hover); }
/* Bit strips for packed and mask sets (datamodel/_bits): the big strip with bit numbers, the mini one in a list,
   a swatch per row; eight colours, by row index. */
.tbx-bitstrip { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 2px; }
.tbx-bitgap { width: 8px; }
.tbx-bitcell { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.tbx-bit { width: 26px; height: 26px; padding: 0; border: 1px solid var(--tbx-line); border-radius: 3px; background: var(--tbx-sunken); color: var(--tbx-muted); font-size: var(--tbx-fs-micro); font-variant-numeric: tabular-nums; cursor: default; }
.tbx-bit:not([disabled]) { cursor: pointer; }
.tbx-bit:not([disabled]):hover { border-color: var(--tbx-line-strong); }
.tbx-bitno { font-size: var(--tbx-fs-micro); color: var(--tbx-muted); }
.tbx-bitstrip-sm .tbx-bit { width: 16px; height: 18px; font-size: 9px; }
.tbx-bitstrip-sm .tbx-bitgap { width: 5px; }
.tbx-bitstrip-sm .tbx-bitbreak { flex-basis: 100%; height: 4px; }
.tbx-bitstrip-sm .tbx-bitno { font-size: 9px; }
.tbx-bit.tbx-bit-mine { background: var(--tbx-heat) !important; color: #fff; border-color: transparent; }
.tbx-bit.tbx-bit-other { background: var(--tbx-line-strong); color: var(--tbx-muted); border-color: transparent; }
.tbx-bit.tbx-bit-mine.tbx-bit-other { background: var(--tbx-warn) !important; }
.tbx-ministrip { display: inline-flex; align-items: center; gap: 1px; vertical-align: middle; }
.tbx-ministrip i { display: block; width: 5px; height: 12px; border-radius: 1px; background: transparent; box-shadow: inset 0 0 0 1px var(--tbx-line); }
.tbx-minigap { width: 3px; }
.tbx-swatch { display: inline-block; width: 12px; height: 12px; border-radius: 2px; vertical-align: middle; box-shadow: inset 0 0 0 1px var(--tbx-line); }
.tbx-bit-c0 { background: #3b82f6 !important; color: #fff; box-shadow: none; border-color: transparent; }
.tbx-bit-c1 { background: #f59e0b !important; color: #fff; box-shadow: none; border-color: transparent; }
.tbx-bit-c2 { background: #10b981 !important; color: #fff; box-shadow: none; border-color: transparent; }
.tbx-bit-c3 { background: #8b5cf6 !important; color: #fff; box-shadow: none; border-color: transparent; }
.tbx-bit-c4 { background: #ef4444 !important; color: #fff; box-shadow: none; border-color: transparent; }
.tbx-bit-c5 { background: #06b6d4 !important; color: #fff; box-shadow: none; border-color: transparent; }
.tbx-bit-c6 { background: #ec4899 !important; color: #fff; box-shadow: none; border-color: transparent; }
.tbx-bit-c7 { background: #84cc16 !important; color: #fff; box-shadow: none; border-color: transparent; }
.tbx-bitrows td { vertical-align: top; }
.tbx-banner { border-left: 3px solid var(--tbx-heat); }
.tbx-two-lines { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.tbx-values td { vertical-align: top; }
.tbx-warn-field { border-color: var(--tbx-warn) !important; }
/* The data point tree editor (datamodel/_def_views) */
.tbx-tree-name { max-width: 260px; }
.tbx-tree-over { box-shadow: inset 0 2px 0 var(--tbx-link); }
.tbx-tree-dragging { opacity: 0.45; }
.tbx-value-gone td > div > input { opacity: 0.45; text-decoration: line-through; }
.tbx-th-abbr { text-align: center; width: 1%; padding-inline: 6px !important; white-space: nowrap; }
.tbx-th-abbr abbr { text-decoration: underline dotted; text-underline-offset: 3px; cursor: help; }
.tbx-td-abbr { text-align: center; font-variant-numeric: tabular-nums; padding-inline: 4px !important; }
.tbx-td-abbr .text-secondary { color: var(--tbx-faint) !important; }

/* ---------- 6. Forms ------------------------------------------------------------- */
/* On phones the action row stays pinned to the bottom, so Save is always
   reachable. Put it on the .card-footer that holds the form's buttons. */
@media (max-width: 767.98px) {
  .tbx-form-actions {
    position: sticky;
    bottom: 0;
    z-index: 3;
    padding-bottom: calc(var(--tbx-4) + env(safe-area-inset-bottom));
    background: var(--tbx-raise);
    box-shadow: 0 -1px 0 var(--tbx-line);
  }
}

/* ---------- 7. Toasts ------------------------------------------------------------
   Tabler's toast, themed as the dark slab in tacklebox-theme.css. A toast
   carries data-bs-theme="dark", so tokens inside it resolve to their dark
   values. These rules place the pieces Tacklebox.toast() adds.             */
.tbx-toast-body { display: flex; gap: var(--tbx-4); align-items: center; }
.tbx-toast-icon { display: inline-flex; flex: none; }
.tbx-toast-ok .tbx-toast-icon   { color: var(--tbx-ok); }
.tbx-toast-warn .tbx-toast-icon { color: var(--tbx-warn); }
.tbx-toast-message { flex: 1; }
.tbx-toast-action {
  flex: none;
  padding: 0;
  font-weight: 600;
  color: var(--tbx-heat-on-inverse);
  background: none;
  border: 0;
}
.tbx-toast-action:hover { text-decoration: underline; }
.toast .btn-close { --tblr-btn-close-color: var(--tbx-on-inverse); }

/* ---------- 8. Reduced motion ------------------------------------------------------
   Tabler already switches its own transitions off. This covers ours.       */
@media (prefers-reduced-motion: reduce) {
  [data-tbx-reorder-item].is-settling { transition: none; }
}

/* ---------- 9. Color chips ----------------------------------------------------------
   The chips (components/tbx/_colors) are Tabler's .form-colorinput; the check
   on a chosen one is drawn by tacklebox-theme.css (2.x). Two chips are ours.

   "My own color", a chip like the presets: the label's own background is the
   rainbow ring; the native color input sits inside it and shows the chosen
   color; the usual .form-colorinput-color span lies on top, transparent, and
   draws the border, the check and the focus ring exactly as for a preset.
   tacklebox.js makes picking a color select the chip.                        */
.tbx-swatch-custom {
  border-radius: var(--tblr-border-radius);
  background: conic-gradient(
    var(--tbx-cat-red), var(--tbx-cat-orange), var(--tbx-cat-yellow), var(--tbx-cat-lime),
    var(--tbx-cat-green), var(--tbx-cat-teal), var(--tbx-cat-cyan), var(--tbx-cat-azure),
    var(--tbx-cat-blue), var(--tbx-cat-indigo), var(--tbx-cat-purple), var(--tbx-cat-pink),
    var(--tbx-cat-red));
}
.tbx-swatch-custom-picker {
  position: absolute;
  inset: 3px;
  width: calc(100% - 6px);
  height: calc(100% - 6px);
  padding: 0;
  border: 0;
  border-radius: 2px;
  background: none;
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
}
.tbx-swatch-custom-picker::-webkit-color-swatch-wrapper { padding: 0; }
.tbx-swatch-custom-picker::-webkit-color-swatch { border: 0; border-radius: 2px; }
.tbx-swatch-custom-picker::-moz-color-swatch { border: 0; border-radius: 2px; }
.tbx-swatch-custom .form-colorinput-color {
  position: relative;
  background: transparent;
  pointer-events: none;
}
.tbx-swatch-custom-picker:focus-visible ~ .form-colorinput-color {
  border-color: var(--tblr-primary);
  outline: var(--tblr-focus-ring, var(--tblr-focus-ring-width) solid var(--tblr-focus-ring-color));
  outline-offset: var(--tblr-focus-ring-offset);
}

/* The photo chip (the avatar picker): the person's own picture, cropped to the
   chip. An image has no one color to snap a check to, so it keeps Tabler's
   white check and gets a dark edge and a soft shadow, to read on any photo. */
.tbx-swatch-photo { background-size: cover; background-position: center; }
.tbx-swatch-photo::before {
  filter: drop-shadow(0 0 1px rgb(0 0 0 / 0.9)) drop-shadow(0 1px 2px rgb(0 0 0 / 0.6));
}

/* ---------- 10. Signed-out pages --------------------------------------------------
   Sign in, request access, password reset: the mark and the name above the
   card, as the sidebar sets them (the name lowercase, in the title cut).    */
.tbx-signed-out-brand { font-size: var(--tbx-fs-lg); font-weight: 600; text-transform: lowercase; font-variation-settings: var(--tbx-font-title); letter-spacing: var(--tbx-track-title); }
.tbx-signed-out-brand svg { height: 1.5rem; width: auto; }

/* ---- The object type's App tab (addendum 4, item 33) ----------------------------------------------------------
   Two columns that stack below about 992px: the definitions the type binds (grouped, a status badge each) and
   Worth a look on the left; the chosen definition's card on the right (tacklebox.js [data-tbx-roles] switches
   the panels). .tbx-fill is the hook drawer's "How each type gets it" grid. */
.tbx-app { display: flex; flex-wrap: wrap; gap: var(--tbx-6); align-items: flex-start; }
.tbx-app-left { flex: 1 1 300px; max-width: 380px; min-width: 0; }
.tbx-app-right { flex: 999 1 560px; min-width: 0; }
@media (max-width: 991.98px) { .tbx-app-left { max-width: none; } }
.tbx-app-hdr { padding: var(--tbx-2) var(--tbx-6); background: var(--tbx-sunken); font-size: var(--tbx-fs-micro); font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--tbx-ink-2); border-top: 1px solid var(--tbx-line-faint); }
.tbx-app-nav .list-group-item { padding: 8px var(--tbx-6); }
.tbx-app-nav .list-group-item.active { z-index: 0; }
.tbx-app-badge { display: inline-flex; align-items: center; gap: 3px; font-variant-numeric: tabular-nums; }
.tbx-app-dhead { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--tbx-4); padding: 14px var(--tbx-6) var(--tbx-4); flex-wrap: wrap; }
.tbx-app-note { margin: 0 var(--tbx-6) var(--tbx-4); padding: var(--tbx-3) var(--tbx-4); border-radius: var(--tbx-r); background: var(--tbx-sunken); font-size: var(--tbx-fs-sm); color: var(--tbx-ink-2); }
.tbx-app-table td, .tbx-app-table th { vertical-align: middle; }
.tbx-app-omitted { background: var(--tbx-sunken); }
.tbx-app-lists { padding: var(--tbx-4) var(--tbx-6); border-top: 1px solid var(--tbx-line-faint); }
.tbx-fill { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: var(--tbx-2) var(--tbx-4); font-size: var(--tbx-fs-sm); align-items: baseline; }
