/* This stylesheet is used exclusively for overrides in behavior that should apply
  across the entire site. Anything specific, or new classes, should go in it's own file */

/* .sf-toolbar.sf-toolbar {
  display: none !important;
} */

/* ---- Theme bridge -------------------------------------------------------
   Every --lens-* variable is emitted per-theme by templates/theme.css.twig,
   scoped to [data-theme="..."]. NOTHING in this file may define one, and nothing
   in this file may branch on which theme is active: a theme that wants a
   treatment off supplies the "off" value (`none`, `transparent`, `0`) instead.
   That is the entire mechanism, and it is what makes a third theme a PHP map
   with no CSS attached. See docs/design/theming.md.

   What lives here is the BRIDGE: Tabler's own variables pointed at ours, so
   Tabler's thousands of derived rules follow the theme without being rewritten.
   Adding a --tblr-* alias here is cheap; hardcoding a value is what broke this
   the first time. */
:root {
  --das-card-status-size: .25rem;
  --das-modal-status-size: .15rem;

  --tblr-font-sans-serif: var(--lens-font-sans);
  --tblr-font-monospace: var(--lens-font-mono);

  /* Radius. Tabler has five steps and Ledger flattens them all to 0 while Air
     wants 10px on a panel and 8px on a control -- so the steps map onto the two
     roles we actually distinguish rather than being scaled arithmetically. */
  --tblr-border-radius: var(--lens-radius-control);
  --tblr-border-radius-sm: var(--lens-radius-chip);
  --tblr-border-radius-lg: var(--lens-radius-surface);
  --tblr-border-radius-xl: var(--lens-radius-surface);
  --tblr-border-radius-xxl: var(--lens-radius-surface);
  --tblr-border-radius-pill: var(--lens-radius-pill);

  --tblr-body-font-size: var(--lens-font-size-base);
  --tblr-body-line-height: var(--lens-line-height-base);
  --tblr-font-size-h1: var(--lens-font-size-h1);
  --tblr-font-size-h2: var(--lens-font-size-h2);
  --tblr-font-size-h3: var(--lens-font-size-h3);
  --tblr-font-size-h4: var(--lens-font-size-h4);
  --tblr-font-size-h5: var(--lens-font-size-h5);
  --tblr-font-size-h6: var(--lens-font-size-h6);
  --tblr-font-weight-normal: 400;
  --tblr-font-weight-medium: 500;
  --tblr-font-weight-semibold: 600;
  /* Ledger never goes past 600 in UI text; 700 is the wordmark alone. A theme
     that disagrees says so in its own map. */
  --tblr-font-weight-bold: var(--lens-font-weight-bold);

  /* AG Grid want's to play by it's own rules. That's not allowed. */
  --ag-toggle-button-switch-background-color: var(--tblr-white);
  --ag-checkbox-checked-shape-color: var(--tblr-white);
  --ag-data-background-color: var(--tblr-body-bg);
}

body {
  font-family: var(--tblr-font-sans-serif);
  /* background-attachment: fixed so a gradient maps to the VIEWPORT rather than to
     the body box. The app shell is a vh-100 flex column with its own scrollers, so
     the body box is viewport-height anyway -- but on the short public pages an
     unfixed gradient would compress into whatever the content happened to be. */
  background: var(--lens-body-bg);
  background-attachment: fixed;
}
/* Thin icons */
svg.thin>g {
  stroke-width: 1;
}

/* Flip Utils */
.flip-x {
  transform: scaleX(-1) !important;
}
.flip-y {
  transform: scaleY(-1) !important;
}

/* Typography */
.hr-link {
  color: var(--tblr-secondary);
}

.hr-link:hover {
  color: var(--tblr-primary);
  text-decoration: none;
}

/* Card stamp fix, we have icons at 1.5em */
.card .card-stamp .card-stamp-icon>svg {
  height:1em !important;
  width:1em !important;
}

/* Card Status fixes
   Sized directly rather than off --tblr-card-border-radius with the overspill
   masked back down, which is Tabler's trick for following a rounded corner: at
   a radius of 0 that collapses the bar to nothing. */
div.card>div.card-status-bottom,
div.card>div.card-status-top {
    height: var(--das-card-status-size);
}
div.card>div.card-status-start,
div.card>div.card-status-end {
    width: var(--das-card-status-size);
}

/* Modal Status fixes -- same reasoning as the card statuses above */
div.modal .modal-status {
    height: var(--das-modal-status-size);
}

/* Override dropdown item icon color, as it is set to secondary, overriding a color of secondary from the dropdown-item */
.dropdown-item-icon {
  color: inherit !important;
}

/* Should be relative to the containers font-size. */
.dropdown-menu {
  --tblr-dropdown-font-size: 0.875em;
}

/* Extra card sizes */
.card-xs>.card-body {
    padding: 0.5rem;
}

.card-xxs>.card-body {
    padding: 0.25rem;
}

/* Icon size classes  */
/* These supposedly exist, but we don't have them. */
.icon-1 {
  height: 1em !important;
  width: 1em !important;
}

.icon-2 {
  height: 2em !important;
  width: 2em !important;
}

.icon-3 {
  height: 3em !important;
  width: 3em !important;
}

.icon-4 {
  height: 4em !important;
  width: 4em !important;
}

.icon-5 {
  height: 5em !important;
  width: 5em !important;
}

/* .dropdown-item-icon has a w/h of 1.25REM, not EM, like I suspect they intended. 1.25REM doesn't make any sense. */
/* It won't scale with the size of the option text, or any text above it. */
/* This dirty little trick (doubling the class) adds to the specificity, so it'll get the important override over the other one */
.dropdown-item-icon.dropdown-item-icon {
    width: 1.25em !important;
    height: 1.25em !important;
}

/* Why? This is easily accessible through bootstrap, it doesn't need to have `flex-grow: 1` on every child. */
.nav-segmented .nav-link.nav-link {
  flex-grow: 0;
}

/* Why do the spinners shrink? How would that possibly be helpful? They don't even have a ratio property for this to work correctly. It just squishes them */
/* (This could be aspect-ratio:1 instead, and might even work better) */
.spinner-border, .spinner-grow {
  flex-shrink: 0;
  /* aspect-ratio: 1; */
}

/* Ehhhhh, maybe */
/* .hr-text {
  font-size: inherit !important;
} */

/* They set a line height of 1, which causes text in the statuses to be offset about 2px lower than it should be */
/* This fixes it with a specificity override */
.status.status {
  line-height: 1.25
}

/* .no-spinner class to remove webkit spin buttons on number input */
input[type=number].no-spinner::-webkit-inner-spin-button, 
input[type=number].no-spinner::-webkit-outer-spin-button { 
    -webkit-appearance: none;
    appearance: none;
    margin: 0; 
}

/* Firefox Override for .no-spinner */
input[type=number].no-spinner {
  -moz-appearance:textfield;
}

/* Utilities for Dynamic Viewport Sizing, in the style of bootstrap */
.dvh-100 {
  height: 100dvh;
}

.dvw-100 {
  width: 100dvw;
}

/* Fix for form check inputs */
.form-check-input {
  border: var(--tblr-border-width) var(--tblr-border-style) rgba(var(--tblr-border-color-rgb), 0.75) !important;
}

/* Fix for invalid form state. Button was a. way too big, b. based off rem for no reason. */
.form-control.is-invalid, .was-validated .form-control:invalid {
  background-size: 1.5em 1.5em;    
  background-position: right 1em center;
}

/* Fix underline on <a> popover targets */ 
a.form-help {
  text-decoration: none;
}

/* Changing it from z-index: 1020, because these render on top of dropdowns. */
.sticky-top {
  z-index: 500 !important;
}

.sticky-bottom {
  z-index: 500 !important;
}

/* The ever-delightful fenceposting issues  */
table.table>tbody>tr:last-child {
  border-bottom-style: hidden;
}

/* ---- Ledger: tables ----------------------------------------------------
   Rows are ruled on the TOP edge, which lets a table sit directly under a
   section rule without doubling it, and leaves the last row open rather than
   closed off by a trailing line.

   The rule is --lens-row-rule, a step fainter than the hairline used elsewhere:
   at 1px everything reads as the same weight, so anything heavier is
   indistinguishable from the section rule that opens the card and the page loses
   its hierarchy. Just enough to track a row by, no more.

   No zebra -- the rules and tabular numerals do that job, and striping fights the
   status chips for attention on every other row. */
.table > :not(caption) > * > * {
  padding: var(--lens-cell-pad-y) var(--lens-cell-pad-x);
  border-bottom: 0;
  border-top: 1px solid var(--lens-row-rule);
}

/* Flush to the column edge, matching the sections above and below. */
.table > :not(caption) > * > *:first-child { padding-left: var(--lens-cell-edge-pad-x); }
.table > :not(caption) > * > *:last-child { padding-right: var(--lens-cell-edge-pad-x); }

/* ...except on a table whose rows can be hovered. The hover background is
   painted on the cells, so with the edge padding zeroed the first cell's text
   and the last cell's chip sit exactly on the edge of the band. Give those two
   cells their padding back and the band reads as a band. Same specificity as the
   rule above (0,2,1), so this has to stay below it to win.

   Static tables keep the flush edge: nothing draws a box around their rows, so
   the figures should line up with the section rule and the page title. */
.table-hover > :not(caption) > * > *:first-child { padding-left: max(var(--lens-cell-edge-pad-x), var(--lens-cell-pad-x)); }
.table-hover > :not(caption) > * > *:last-child { padding-right: max(var(--lens-cell-edge-pad-x), var(--lens-cell-pad-x)); }

.table-striped > tbody > tr:nth-of-type(odd) > * {
  background: transparent;
}

.table-hover > tbody > tr:hover > * {
  background: var(--lens-row-hover);
}

/* Column heads are micro-labels, and the head is separated from the body by
   the heavier rule -- it is a section boundary, not another row. */
.table thead th {
  font-size: var(--lens-font-size-h6);
  font-weight: 600;
  letter-spacing: var(--lens-thead-tracking);
  text-transform: uppercase;
  color: var(--lens-thead-color);
  border-top: 0;
  border-bottom: 1px solid var(--lens-rule);
  /* Tabler fills the head with bg-surface-tertiary purely to separate it from
     the body. The rule below it already does that, so a static head can be
     transparent and let the page show through. */
  background: var(--lens-thead-bg);
}

/* ---- Ledger: micro-labels ----------------------------------------------
   Tabler's own uppercase label class, retuned to Ledger's step -- 11.5px / 600
   / 0.06em / tertiary, instead of its 12px / 500 / 0.04em / secondary. It is
   already uppercase, so that is not restated.

   This is the general-purpose micro-label. .datagrid-title (lens.css) and the
   table column heads above carry the same treatment because they are the two
   places Tabler hardcodes its own; a NEW label should compose .subheader rather
   than grow a fourth copy of these declarations. */
.subheader {
  font-size: var(--lens-font-size-h6);
  font-weight: 600;
  letter-spacing: var(--lens-thead-tracking);
  color: var(--lens-thead-color);
}

/* ---- Ledger: AG Grid ---------------------------------------------------
   The grid is themed in assets/ag_grid_theme.js -- these are the two things
   its theming API has no parameter for. */
.ag-header-cell-text {
  text-transform: uppercase;
  letter-spacing: var(--lens-thead-tracking);
}

.ag-cell {
  font-variant-numeric: tabular-nums;
}

/* A sticky head is the exception, and its fill is load-bearing: a table that
   scrolls (opt in with header:class="sticky-top") has rows moving UNDER the column
   labels, so the head must be opaque or you read both at once. Themed, because what
   is "behind" the head differs -- Ledger's card is transparent on the sheet, Air's is
   a panel. Never --tblr-body-bg directly: in a boxed theme that paints the page
   colour inside the card. */
.table thead.sticky-top th {
  background: var(--lens-thead-sticky-bg);
  position: relative;
  /* Fixes gap between table top and sticky row top */
  top: -1px;
}

/* ---- Ledger: cards are sections, not boxes -----------------------------
   This is the whole idea of the design. A section is announced by a rule
   across the top of the column and then gets out of the way -- no border on
   the other three sides, no fill, no elevation. The page is one sheet of
   paper with rules drawn on it, and boxing each section back up is what makes
   it read as a generic dashboard instead.

   Padding is vertical only, so content stays flush to the column edge and
   figures in adjacent sections line up down the page. */
.card {
  border: var(--lens-section-border);
  /* The top edge is its own token so a RULED theme can draw only this one and a
     BOXED theme can repeat its border here. Ledger sets section-border to 0 and
     this to a hairline; Air sets both to the same 1px. */
  border-top: var(--lens-section-rule);
  border-radius: var(--lens-radius-surface);
  background: var(--lens-section-bg);
  box-shadow: var(--lens-section-shadow);
}

/* The frosted backdrop of a glass theme, on a pseudo-element rather than on
   .card itself.

   backdrop-filter makes the element it is declared on a containing block for
   every `position: fixed` descendant, and a stacking context for all of them.
   On .card that reparents anything fixed inside a section TO the section: a
   modal nested in a card would open inside the card, and a dropdown overflowing
   one card would paint under the next.

   z-index: -1 puts the blur behind the card's own translucent fill, so the tint
   layers over the frost instead of sitting beside it. .card is `position:
   relative` in Tabler and declares no ::before of its own. Ledger's filter is
   `none`, so this paints nothing there at all. */
.card::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  backdrop-filter: var(--lens-section-filter);
  pointer-events: none;
}

.card > .card-body,
.card > .card-header,
.card > .card-footer {
  padding-left: var(--lens-section-pad-x);
  padding-right: var(--lens-section-pad-x);
  background: transparent;
}

/* Vertical padding is a theme decision too: Ledger takes Tabler's default and
   Air runs 18px. Ledger's token is `var(--tblr-card-spacer-y)` rather than a
   literal, so it stays whatever Tabler ships rather than pinning to a copy. */
.card > .card-body {
  padding-top: var(--lens-section-pad-y);
  padding-bottom: var(--lens-section-pad-y);
}

.card > .card-header {
  border-bottom: 0;
  padding-top: var(--lens-section-header-pad-y);
  padding-bottom: calc(var(--lens-section-header-pad-y) / 2);
  min-height: 0;
}

.card > .card-footer {
  border-top: 1px solid var(--lens-hairline);
}

/* A section title is a real heading -- 19px, sentence case, ink. The uppercase
   micro-label treatment belongs to stat-tile labels and table column heads
   only; using it here flattens the page, because then nothing on it is a
   heading and every section looks like a footnote. */
.card > .card-header .card-title {
  font-size: var(--lens-section-title-size);
  font-weight: 600;
  letter-spacing: var(--lens-section-title-tracking);
  color: var(--lens-section-title-color);
  margin: 0;
}

/* Some surfaces genuinely are panels -- dropdowns, modals, popovers float
   above the sheet and still need an edge and a fill to sit on.

   --tblr-bg-surface, not --tblr-white. They are the same colour in light, but
   naming the role rather than the literal is what makes these follow the theme:
   a floating panel has to be a step LIGHTER than the body in dark, and reading
   "white" here invites someone to re-point it at a literal later. */
.dropdown-menu,
.modal-content,
.popover,
.offcanvas {
  border: var(--lens-panel-border);
  border-radius: var(--lens-radius-surface);
  background: var(--lens-panel-bg);
  box-shadow: var(--lens-panel-shadow);
  backdrop-filter: var(--lens-panel-filter);
}

/* Cards used as a real surface opt back in. */
.card.card-boxed {
  border: var(--lens-panel-border);
  background: var(--lens-panel-bg);
  box-shadow: var(--lens-panel-shadow);
}

.card.card-boxed > .card-body,
.card.card-boxed > .card-header,
.card.card-boxed > .card-footer {
  padding-left: max(var(--lens-section-pad-x), 1rem);
  padding-right: max(var(--lens-section-pad-x), 1rem);
}

/* ---- Ledger: buttons ---------------------------------------------------
   13.5px / 600, square. Matches the body size rather than shrinking, because
   these sit inline with figures in toolbars. */
.btn {
  font-size: var(--lens-btn-font-size);
  font-weight: var(--lens-btn-font-weight);
  border-radius: var(--lens-radius-control);
}

/* The one filled action on a view. Both comps step it up a weight from an ordinary
   button; Air additionally lifts it off the page with a shadow, where Ledger sets the
   token to `none` and it stays flat. */
.btn-primary {
  font-weight: var(--lens-btn-primary-weight);
  box-shadow: var(--lens-btn-primary-shadow);
}

/* ---- Ledger: status chips ----------------------------------------------
   The comp pads a chip 8px either side (`padding: 0 8px` in the lists, 0 9px in
   the entity header). Tabler's badge ships 0.5em, which is 5.8px at our 11.5px
   chip text -- tight enough that the tint reads as a highlight behind the word
   rather than as a chip. Set here rather than per call site so every badge in
   the app agrees; padding-inline only, so the vertical rhythm is untouched. */
.badge {
  padding-inline: var(--lens-chip-pad-x);
  border-radius: var(--lens-radius-chip);
  /* Air sets its chips in uppercase with tracking; Ledger leaves the tint to do
     the work and passes `none`/`normal`. */
  text-transform: var(--lens-chip-transform);
  letter-spacing: var(--lens-chip-tracking);
}

/* ---- Ledger: form controls ---------------------------------------------
   The only elements that keep a border on all four sides. Ledger draws the
   box a step darker than the row hairlines so an input reads as something you
   can type in, rather than as another ruled row. */
.form-control,
.form-select,
.input-group-text {
  border: var(--lens-control-border);
  border-radius: var(--lens-radius-control);
  background-color: var(--lens-control-bg);
}

/* Override for Tabler trying to compensate for scrollbars. Almost all browsers handle this correctly now */
@media (min-width: 992px) {
  :host, :root {
    margin-left: 0 !important;
  }
}

/* Bootstrap doesn't have a utility for this, but it'll be very helpful */
.stable-gutter {
  scrollbar-gutter: stable;
}

/* ---- Ledger: scrollbars -------------------------------------------------
   Ported from the comp, which specifies this on its one scrolling region
   (`[data-scroll="sidebar"]`); global here because every scroller in the app
   wants the same treatment.

   The thumb is the brand blue at a low alpha on a transparent track -- the
   sheet shows through and the only thing drawn is the grip. Square, like
   everything else. The alpha is what keeps it quiet: at 0.2 it reads as a
   smudge on the paper rather than a control competing with the figures.

   rgba(var(--tblr-primary-rgb), …) rather than the comp's literal
   rgba(23,80,158,…): that IS #17509E, i.e. --tblr-primary, and naming the token
   means it lifts to #6E9FE0 in dark rather than staying an invisible navy on
   the #0B1B2D body.

   `*`, not `:root`, and this is the whole trick -- Tabler already ships
   `*{scrollbar-color: …}`. A declaration matching an element directly beats an
   inherited one, so a rule on :root only ever reaches the viewport scrollbar
   and every inner scroller keeps Tabler's. Same specificity, later file, so
   ours wins on order.

   The two syntaxes are NOT interchangeable and the split below is load-bearing.
   `scrollbar-color`/`-width` are the standard properties and all Firefox has,
   but they only recolour the browser's own scrollbar -- you get its shape, and
   Chrome's `thin` is a rounded pill with stepper arrows. Ledger is square, so
   Chrome and Safari are handed to ::-webkit- instead, which does control shape.
   Chrome ignores those pseudo-elements the moment either standard property is
   set to something other than `auto`, hence the reset in the @supports block. */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--lens-scrollbar-thumb) transparent;
}

/* WebKit only. Firefox doesn't match ::-webkit-scrollbar as a selector, so it
   never enters this block and keeps the standard properties above. */
@supports selector(::-webkit-scrollbar) {
  * {
    scrollbar-width: auto;
    scrollbar-color: auto;
  }
}

::-webkit-scrollbar {
  width: var(--lens-scrollbar-size);
  height: var(--lens-scrollbar-size);
}

::-webkit-scrollbar-track,
::-webkit-scrollbar-corner {
  background: transparent;
}

/* The three resets are all undoing Tabler, which draws its thumb as a 1rem
   rounded pill filled by an inset box-shadow rather than a background -- leave
   any of them and our colour paints underneath its shadow and never shows.

   background-clip: padding-box against a transparent border is what insets the
   grip from the outer edge: an 8px track carrying a 6px thumb, so it doesn't
   sit hard against the window frame. Tabler borders all four sides at 5px,
   which would collapse the thumb entirely in an 8px track, so the border is
   zeroed first and then re-applied on the one edge that faces out. */
::-webkit-scrollbar-thumb {
  border: 0;
  border-radius: var(--lens-scrollbar-radius);
  box-shadow: none;
  background: var(--lens-scrollbar-thumb);
  background-clip: padding-box;
}

::-webkit-scrollbar-thumb:vertical {
  border-right: 2px solid transparent;
}

::-webkit-scrollbar-thumb:horizontal {
  border-bottom: 2px solid transparent;
}

/* Hover is on the scrolling element, not on the thumb: the grip should surface
   as soon as the pointer is over the region it scrolls, not only once you hit
   the 8px strip. */
:hover::-webkit-scrollbar-thumb {
  box-shadow: none;
  background: var(--lens-scrollbar-thumb-hover);
  background-clip: padding-box;
}

::-webkit-scrollbar-thumb:active {
  box-shadow: none;
  background: var(--lens-scrollbar-thumb-active);
  background-clip: padding-box;
}

/* Man, come on, why is every z-index just set to 1000? */
.card-tabs .nav-tabs {
  z-index: 999;
}

/* ---- Tabbed card -------------------------------------------------------
   Bootstrap builds the active tab as a box with its bottom edge knocked out and
   relies on the bordered card beneath to close the shape. Nothing here does
   that: the strip, the tab and the pane are three separately themed surfaces,
   so a ruled theme can draw a hairline with an underlined label on it while a
   boxed one welds a lid onto the panel below.

   Every declaration below is a token. `margin-bottom: -1px` is the exception --
   it lands the tab's own bottom edge on the strip's rule instead of beside it,
   which is structural rather than a look.

   The bottom edge is addressed apart from the other three throughout, because
   in both vocabularies it is the edge carrying the state: a ruled theme draws
   the current-tab marker on it, a boxed one knocks it out so the lid opens into
   the pane. --lens-tab-marker-* is that edge under either reading. */
/* .card-tabs zeroes the strip's rule, because in Tabler the card's own top
   border is that line. A ruled card has no such border, so the strip draws its
   own -- which means matching that specificity to win it back. */
.nav-tabs,
.card-tabs .nav-tabs {
  border-bottom: var(--lens-tab-strip-border);
  background: var(--lens-tab-strip-bg);
  padding-inline: var(--lens-tab-strip-pad-x);
}

.nav-tabs .nav-item .nav-link {
  border: var(--lens-tab-border);
  border-bottom: var(--lens-tab-marker-size) solid var(--lens-tab-marker-idle);
  margin-bottom: -1px;
  border-radius: var(--lens-tab-radius) var(--lens-tab-radius) var(--lens-tab-radius-bottom) var(--lens-tab-radius-bottom);
  /* The macro's link is already a flex row with align-items:center, so a
     min-height centres the label without a line-height to keep in step. */
  min-height: var(--lens-tab-height);
  padding: 0 var(--lens-tab-pad-x);
  background: var(--lens-tab-bg);
  color: var(--lens-tab-fg);
  font-weight: var(--lens-tab-weight);
}

.nav-tabs .nav-item .nav-link:hover {
  background: var(--lens-tab-hover-bg);
  color: var(--lens-tab-hover-fg);
  border-color: var(--lens-tab-hover-border-color);
  border-bottom-color: var(--lens-tab-hover-marker);
}

.nav-tabs .nav-item .nav-link.active {
  background: var(--lens-tab-active-bg);
  color: var(--lens-tab-active-fg);
  font-weight: var(--lens-tab-active-weight);
  border-color: var(--lens-tab-active-border-color);
  border-bottom-color: var(--lens-tab-marker-color);
}

/* Tabler joins the strip into one segmented control: it squares the corners
   where two tabs meet and laps each tab a border-width over the last, so the
   run reads as one shape rather than a row of them. Both are the theme's call
   -- a ruled theme has no shape to join, a chipped one wants its tabs standing
   apart -- so the inner corner and the lap are tokens, and a theme that wants
   them separate answers with its own radius and a zero lap. */
.card-tabs .nav-tabs .nav-item:not(:first-child) .nav-link {
  border-top-left-radius: var(--lens-tab-radius-inner);
  border-bottom-left-radius: var(--lens-tab-radius-inner);
}

.card-tabs .nav-tabs .nav-item:not(:last-child) .nav-link {
  border-top-right-radius: var(--lens-tab-radius-inner);
  border-bottom-right-radius: var(--lens-tab-radius-inner);
}

.card-tabs .nav-tabs .nav-item + .nav-item {
  margin-left: var(--lens-tab-lap);
}

/* The bottom variant turns the tab upside down: the edge facing the pane is now
   the top one, so the marker and the weld travel with it and the radius lands on
   the two corners pointing away. Tabler already flips the geometry -- the lap,
   the inner corners, the -1px that laps the strip onto the pane -- so only the
   sides that name a physical edge above have to be restated. Matched to Tabler's
   own specificity, which is what lets these win. */
.card-tabs .nav-tabs-bottom {
  border-bottom: 0;
  border-top: var(--lens-tab-strip-border);
}

.card-tabs .nav-tabs-bottom .nav-item .nav-link {
  border-top: var(--lens-tab-marker-size) solid var(--lens-tab-marker-idle);
  border-bottom: var(--lens-tab-border);
  border-radius: var(--lens-tab-radius-bottom) var(--lens-tab-radius-bottom) var(--lens-tab-radius) var(--lens-tab-radius);
  /* The strip is lapped by the item's own negative top margin here, so the link
     must not also pull itself up. */
  margin-bottom: 0;
}

.card-tabs .nav-tabs-bottom .nav-item .nav-link:hover {
  border-color: var(--lens-tab-hover-border-color);
  border-top-color: var(--lens-tab-hover-marker);
}

.card-tabs .nav-tabs-bottom .nav-item .nav-link.active {
  border-color: var(--lens-tab-active-border-color);
  border-top-color: var(--lens-tab-marker-color);
}

/* The pane. A ruled theme answers "nothing" here, because the strip has already
   opened the section; a boxed one hands over its section treatment and the pane
   becomes the panel the tabs sit on.

   Selected as `.card.tab-pane` rather than `.tab-pane` to match the specificity
   of Tabler's own `.card-tabs .nav-tabs + .tab-content .card`, which squares the
   pane's left corners to weld it to the first tab. */
.card-tabs .tab-content > .card.tab-pane {
  border: var(--lens-tab-pane-border);
  border-radius: var(--lens-tab-pane-radius);
  background: var(--lens-tab-pane-bg);
  box-shadow: var(--lens-tab-pane-shadow);
}

/* The pane is a .card, so it inherits the blur .card::before carries. It needs
   its own, or a glass pane frosts twice over -- once as a card and once as a
   pane -- and a ruled one frosts at all. */
.card-tabs .tab-content > .card.tab-pane::before {
  backdrop-filter: var(--lens-tab-pane-filter);
}

/* A pane whose content is itself a card: one surface, not two. Structural in
   every theme -- whichever of the two draws the panel, the other draws nothing,
   and it is the outer one that owns the shape. */
.card.tab-pane > .card,
.card-tabs .tab-content > .card.tab-pane > .card {
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
}

.card.tab-pane > .card::before {
  backdrop-filter: none;
}

/* 
  Apparently forms don't inherit the primary color. No idea why that'd be. \
    They're just hardcoded to lighter verions of blue 
*/
/* Mixed toward --tblr-bg-surface rather than the `white` keyword. Identical in
   light, where the surface IS white; in dark the keyword pulled the focus ring
   toward #fff, i.e. brighter than any text on the page. */
.form-control:focus {
  border-color: color-mix(in srgb, var(--tblr-primary), var(--tblr-bg-surface) 50%);
  background-color: color-mix(in srgb, var(--tblr-primary) 5%, transparent);
  box-shadow: var(--tblr-shadow-input), 0 0 0 .25rem rgba(var(--tblr-primary-rgb), .25);
}

/* ---- Chrome stacking ----------------------------------------------------
   `backdrop-filter` with any value other than `none` CREATES A STACKING CONTEXT.
   Tabler ships .navbar as position:relative with no z-index, so the moment a theme
   gives it a blur the bar becomes a stacking context at z-index:auto, every dropdown
   inside it is trapped there, and the content below paints over the open menu.

   So the chrome has to state where it sits rather than rely on being a plain static
   ancestor. 1030 is Bootstrap's own fixed-navbar layer: above the content and the
   rail, below modals (1055) and their backdrops.

   This is not Air-specific. Ledger passes `none` and creates no context today, but
   any theme adding a filter, transform, opacity or will-change here would land in
   the same place -- declaring the layer once rules out the whole class of it. */
.navbar {
  position: relative;
  z-index: 1030;
  background: var(--lens-chrome-bg);
  backdrop-filter: var(--lens-chrome-filter);
  box-shadow: inset 0 calc(-1 * var(--tblr-navbar-border-width)) 0 0 var(--lens-chrome-border);
}

/* Keep Tabler's borders on our color scheme */
.hr-text::after, .hr-text::before {
  background-color: var(--tblr-border-color-translucent);
}

/* Adding a quick helper for grouped badges */
.badge-group {
  display: flex;
  flex-direction: row;
}
.badge-group > .badge {
  border-radius: 0 !important;
  display: block;
}

.badge-group > .badge:first-child {
  border-top-left-radius: var(--tblr-border-radius) !important;
  border-bottom-left-radius: var(--tblr-border-radius) !important;
}

.badge-group > .badge:last-child {
  border-top-right-radius: var(--tblr-border-radius) !important;
  border-bottom-right-radius: var(--tblr-border-radius) !important;
}

/* Show an element in one scheme only -- the branded lockup is the reason these
   exist (see partials/_lockup.html.twig).

   The scheme resolves the same three ways it does in theme.css.twig, and for the
   same reason: a pinned data-scheme has to beat the OS, or someone who chose
   Light on a dark machine gets the knockout lockup on a white card. Keying off
   prefers-color-scheme alone gets that wrong.

   Every rule below only ever ADDS `display: none`. Hiding by default and
   revealing with `display: revert` would clobber whatever display a utility on
   the element had already set. */
:root[data-scheme="dark"] .light-only {
  display: none;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-scheme="light"]) .light-only {
    display: none;
  }
}

:root[data-scheme="light"] .dark-only {
  display: none;
}

@media (prefers-color-scheme: light) {
  :root:not([data-scheme="dark"]) .dark-only {
    display: none;
  }
}

/* Tabler ships these with no horizontal padding */
.btn.btn-icon.btn-sm {
  --btn-icon-btn-sm-padding: 0.5em;
  padding-left: var(--btn-icon-btn-sm-padding);
  padding-right: calc(var(--btn-icon-btn-sm-padding) - 1px);
}

@font-face {
  font-family: 'Phyrexian';
  src: url("../fonts/Phyrexian-53b3J1o.woff2") format('woff2');
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Elvish';
  src: url("../fonts/TengwarQuenya-Y_BQn7I.ttf");
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

/* Inter variable font (weight 100–900), served locally via AssetMapper */
@font-face {
  font-family: 'Inter';
  src: url("../fonts/Inter-0ks5kEi.woff2") format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/* The brand kit's two faces (issued 2026-08-17), self-hosted like Inter rather
   than pulled from fonts.googleapis.com: the kit's README suggests the Google
   <link>, but that is a third-party request on every page load and AssetMapper
   already fingerprints and far-future-caches whatever sits in assets/fonts.

   IBM Plex Sans is the interface face: both themes point `font-sans` at it, which
   reaches every page through --tblr-font-sans-serif in the bridge at the top of
   this file. Figures are untouched and stay Ubuntu Mono via --lens-font-mono.

   Arimo is the WORDMARK face and nothing in the UI asks for it. It is declared
   anyway because the lockup names it, and a day may come when the lockup is
   inlined into the document instead of served through an <img>. Note that the
   logo does NOT read either of these files today: an <img>-served SVG cannot
   fetch anything external, so it carries its own embedded subset instead (see
   branding/lens-lockup.svg). Changing a face here does not change the logo, and
   vice versa — the two have to be kept in step by hand.

   Both are the upstream variable fonts, subset to Latin (plus punctuation,
   currency and the arrows) — 31KB and 92KB against 215KB and 218KB for the full
   character set, which carries Cyrillic, Greek and Hebrew this app has no use
   for. unicode-range is what makes that safe rather than lossy: a glyph outside
   the range doesn't render as tofu, the browser just falls through to the next
   family in the stack for that character. Widen the range and re-run pyftsubset
   if that ever shows up somewhere it matters. */
@font-face {
  font-family: 'Arimo';
  src: url("../fonts/Arimo-M0vmOTj.woff2") format('woff2');
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0100-017F, U+2000-206F, U+20A0-20BF, U+2122, U+2190-2193, U+2212;
}

@font-face {
  font-family: 'IBM Plex Sans';
  src: url("../fonts/IBMPlexSans-c5_eyMM.woff2") format('woff2');
  font-weight: 100 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0100-017F, U+2000-206F, U+20A0-20BF, U+2122, U+2190-2193, U+2212;
}

/* Ubuntu Mono, the figure face. --tblr-font-monospace has named it since the
   theme landed, but nothing ever declared it, so every ledger figure fell back
   to ui-monospace and the TTF sat in assets/fonts unreferenced.

   Regular weight only — the browser synthesises the bold, which is all we ask of
   it (see docs/design/lens-ledger.md). */
@font-face {
  font-family: 'Ubuntu Mono';
  src: url("../fonts/UbuntuMono-m9RZl-U.ttf") format('truetype');
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}


/* A control appended to a form control -- the password reveal toggle, and
   anything else that sits inside an .input-group. It has to take the SAME
   border as the input it is joined to: --tblr-border-color is the hairline
   (#E4EAF3) used between rows, while a form control's box is
   --tblr-border-strong (#C3CDD9). Using the hairline here left a visible seam
   where the button met the input, and left the icon almost invisible, since
   this rule sets the glyph colour too. See docs/design/lens-ledger.md. */
.btn-outline-input {
  color: var(--tblr-secondary);
  border: var(--lens-control-border);
}

/* Pressed. The old pair was white-on-#E4EAF3, which is 1.3:1 -- the icon
   disappeared for as long as you held the button down. */
.btn-outline-input:active {
  background-color: var(--tblr-gray-100);
  color: var(--tblr-gray-900);
}

.btn-ag-grid {
  padding: 0.15em 0.4em;
  margin-bottom: 0.1em;
}
/* ---- Row actions --------------------------------------------------------
   One treatment for the icon buttons that live at the end of a table row, in
   both themes -- one verb gets one look, wherever the row is.

   Quiet by default and coloured on hover: a row action is a thing you reach for
   once you have found the row, so it must not compete with the row's own text,
   and a permanently-red trash on every line shouts louder than the names beside
   it. Hierarchy is the design rule this implements — one filled action per view,
   everything else plain (see docs/design/lens-ledger.md). */
.btn-action {
  --tblr-btn-padding-x: 0.375rem;
  --tblr-btn-padding-y: 0.375rem;
  color: var(--lens-tertiary);
  border: 0;
  background: transparent;
  border-radius: var(--lens-radius-control);
  line-height: 1;
}

.btn-action:hover,
.btn-action:focus-visible {
  color: var(--tblr-primary);
  background: var(--lens-row-hover);
}

.btn-action-danger:hover,
.btn-action-danger:focus-visible {
  color: var(--tblr-danger);
}

.btn-action > svg {
  width: 1.125em;
  height: 1.125em;
}

/* ---- Empty states -------------------------------------------------------
   Tabler sizes .empty for a whole blank page — 4rem of padding and a 2.5rem
   title. Dropped into a table cell, as every list here does, it produced a
   third of a screen of nothing with a heading bigger than the page title.
   Inside a table it should read as a quiet note where the rows would be. */
.table .empty {
  padding: 2rem 1rem;
}

.table .empty-title {
  font-size: var(--lens-font-size-h3);
  font-weight: 600;
  margin-bottom: 0.25rem;
}

.table .empty-body {
  font-size: var(--lens-font-size-base);
  color: var(--tblr-secondary);
}

.table .empty-icon {
  width: 1.75rem;
  height: 1.75rem;
  margin-bottom: 0.5rem;
  color: var(--lens-tertiary);
}

/* ---- Ghost buttons ------------------------------------------------------
   A button that is only a label until you touch it. Used for the entity links
   inside a drilldown, where a row of filled buttons would bury the figures they
   sit beside.

   This class did not exist -- Tabler ships .btn-ghost-primary and friends but no
   bare .btn-ghost, so `class="btn-ghost"` alongside variant="primary" rendered a
   solid filled button and had done for as long as it has been in the drilldown.
   Defined here so it means the same thing in both themes. */
.btn-ghost,
.btn.btn-ghost {
  background: transparent;
  border-color: transparent;
  color: var(--tblr-primary);
  box-shadow: none;
}

.btn-ghost:hover,
.btn-ghost:focus-visible {
  background: var(--lens-row-hover);
  border-color: transparent;
  color: var(--tblr-primary);
}