/*
 * The two dashboards, the balance chip in the client top bar, and the bar that
 * says an admin is viewing somebody else's panel.
 *
 * Plain CSS for the same reason as wallet.css, order-cards.css, service-page.css,
 * contact.css and tickets.css: neither panel has a Vite build and both serve
 * Filament's pre-compiled app.css, so `class="flex gap-4"` written in a Blade view
 * here is inert markup. Anything bespoke brings its own rules.
 *
 * Registered on *both* panels — the second file to be, after tickets.css — because
 * both dashboards are built from the same three shapes: a chip, a stack of
 * attention lines, and a list of rows. In ClientPanelProvider and in
 * AdminPanelProvider:
 *
 *     Css::make('dashboard', resource_path('css/dashboard.css'))
 *
 * which `php artisan filament:assets` copies to public/css/app/dashboard.css.
 * Editing this file therefore needs that command re-run — composer's
 * post-autoload-dump does it too, by way of `filament:upgrade`.
 *
 * Every colour is a variable FilamentColor writes into :root at runtime
 * (--gray-*, --primary-*, --success-*, --warning-*, --danger-*, --info-*) and
 * every size comes from the theme block in app.css (--radius-xl, --text-sm), so
 * both dashboards track whichever palette the operator chose and its dark mode
 * rather than defining a second one. That matters more here than on a
 * single-panel stylesheet: the two panels can be branded to different primaries,
 * and this file is the one thing their dashboards share. Dark mode is the `.dark`
 * class on <html>.
 *
 * The namespace is `db-`, kept apart from `tk-`, `ct-`, `wl-`, `oc-` and `sv-`
 * because all of them load on every client page and a shared prefix would let a
 * rule written for a dashboard silently restyle a server.
 */

/* ------------------------------------------------------------------ *
 * The balance chip in the top bar
 *
 * Sits inside Filament's own `.fi-topbar-end`, which is already a flex row with
 * a 1rem column gap, so this styles the chip itself and nothing around it. It
 * is deliberately quiet: the topbar's job is navigation, and a figure that
 * shouted would compete with the page under it every time.
 * ------------------------------------------------------------------ */

.db-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.375rem 0.625rem;
    border-radius: var(--radius-lg, 0.5rem);
    font-size: var(--text-sm, 0.875rem);
    font-weight: 600;
    line-height: 1.25rem;
    white-space: nowrap;
    text-decoration: none;
    color: var(--gray-700);
    background-color: var(--gray-50);
    box-shadow: inset 0 0 0 1px var(--gray-200);
    transition:
        background-color 75ms ease,
        box-shadow 75ms ease;
}

.db-chip:hover {
    background-color: var(--gray-100);
    box-shadow: inset 0 0 0 1px var(--gray-300);
}

.db-chip:focus-visible {
    outline: 2px solid var(--primary-500);
    outline-offset: 2px;
}

.dark .db-chip {
    color: var(--gray-200);
    background-color: color-mix(in oklab, var(--gray-50) 6%, transparent);
    box-shadow: inset 0 0 0 1px var(--gray-700);
}

.dark .db-chip:hover {
    background-color: color-mix(in oklab, var(--gray-50) 10%, transparent);
    box-shadow: inset 0 0 0 1px var(--gray-600);
}

/* Overdrawn is a state of the account rather than an error in the page, so the
   chip tints and reddens — the same restraint wallet.css uses for .wl-is-short.
   It is not a warning banner and it must not read as one on every page. */
.db-chip--danger {
    color: var(--danger-700);
    background-color: color-mix(in oklab, var(--danger-500) 8%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--danger-500) 25%, transparent);
}

.db-chip--danger:hover {
    background-color: color-mix(in oklab, var(--danger-500) 14%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--danger-500) 35%, transparent);
}

.dark .db-chip--danger {
    color: var(--danger-300);
    background-color: color-mix(in oklab, var(--danger-400) 12%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--danger-400) 30%, transparent);
}

.dark .db-chip--danger:hover {
    background-color: color-mix(in oklab, var(--danger-400) 18%, transparent);
}

/* Two classes deep on purpose. Filament's <x-filament::icon> stamps its own
   `fi-size-md` (1.25rem) onto the svg, which is a single class and would
   otherwise win or lose on source order alone — a coin flip that depends on
   which stylesheet the panel happens to emit last. `.db-chip .db-chip-icon`
   settles it by specificity instead. */
.db-chip .db-chip-icon {
    width: 1rem;
    height: 1rem;
    flex-shrink: 0;
    color: var(--gray-400);
}

.dark .db-chip .db-chip-icon {
    color: var(--gray-500);
}

.db-chip--danger .db-chip-icon {
    color: var(--danger-500);
}

.dark .db-chip--danger .db-chip-icon {
    color: var(--danger-400);
}

/* tabular-nums so a balance that changes between page loads does not shuffle its
   own digits sideways in a bar that is otherwise identical on every screen. */
.db-chip-value {
    font-variant-numeric: tabular-nums;
}

/* Under 30rem the bar is tight — the hamburger, the logo, the bell and the
   avatar are all competing already. The icon carries the meaning there and the
   figure stays, because the figure is the whole point of the chip; what goes is
   the padding around it. */
@media (max-width: 30rem) {
    .db-chip {
        padding: 0.25rem 0.375rem;
        font-size: var(--text-xs, 0.75rem);
    }

    .db-chip-icon {
        display: none;
    }
}

/* ------------------------------------------------------------------ *
 * A link in a section heading
 *
 * "View all" beside a heading, in the <x-slot name="afterHeader"> the section
 * component offers. Quiet until hovered: it is an escape hatch from a summary,
 * not the thing the section is for.
 * ------------------------------------------------------------------ */

.db-section-link {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    font-size: var(--text-sm, 0.875rem);
    font-weight: 600;
    line-height: 1.25rem;
    white-space: nowrap;
    text-decoration: none;
    color: var(--primary-600);
}

.db-section-link:hover {
    color: var(--primary-500);
}

.db-section-link:focus-visible {
    outline: 2px solid var(--primary-500);
    outline-offset: 2px;
    border-radius: var(--radius-md, 0.375rem);
}

.dark .db-section-link {
    color: var(--primary-400);
}

.dark .db-section-link:hover {
    color: var(--primary-300);
}

/* Two deep for the same reason as .db-chip-icon: <x-filament::icon> stamps its
   own fi-size-md, which is one class and would otherwise be settled by source
   order. */
.db-section-link .db-section-link-icon,
.db-empty-action .db-section-link-icon {
    width: 0.875rem;
    height: 0.875rem;
    flex-shrink: 0;
}

/* ------------------------------------------------------------------ *
 * Attention lines
 *
 * A tinted strip per thing that wants doing. The tint is the whole of the
 * signalling — no left border, no icon badge — because these stack, and four
 * bordered strips in a column reads as a form rather than as a list of
 * sentences.
 * ------------------------------------------------------------------ */

.db-lines {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.db-line {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    padding: 0.75rem 0.875rem;
    border-radius: var(--radius-lg, 0.5rem);
    background-color: color-mix(in oklab, var(--gray-500) 6%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--gray-500) 12%, transparent);
}

/* The action sits at the end of the row on a wide screen and drops under the
   text on a narrow one, where a button squeezed against a paragraph would take
   the paragraph down to three words a line. */
.db-line-text {
    flex: 1 1 16rem;
    min-width: 0;
}

.db-line-title {
    font-size: var(--text-sm, 0.875rem);
    font-weight: 600;
    line-height: 1.25rem;
    color: var(--gray-950);
}

.dark .db-line-title {
    color: white;
}

.db-line-body {
    margin-top: 0.125rem;
    font-size: var(--text-sm, 0.875rem);
    line-height: 1.375rem;
    color: var(--gray-600);
}

.dark .db-line-body {
    color: var(--gray-400);
}

.db-line .db-line-icon {
    width: 1.25rem;
    height: 1.25rem;
    flex-shrink: 0;
    /* Nudged to sit on the title's cap height rather than its line box. */
    margin-top: 0.0625rem;
    color: var(--gray-400);
}

.dark .db-line .db-line-icon {
    color: var(--gray-500);
}

.db-line-action {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    flex-shrink: 0;
    margin-inline-start: auto;
    padding: 0.375rem 0.625rem;
    border-radius: var(--radius-lg, 0.5rem);
    font-size: var(--text-sm, 0.875rem);
    font-weight: 600;
    line-height: 1.25rem;
    white-space: nowrap;
    text-decoration: none;
    color: var(--gray-700);
    background-color: var(--gray-50);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--gray-500) 20%, transparent);
    transition: background-color 75ms ease;
}

.db-line-action:hover {
    background-color: white;
}

.db-line-action:focus-visible {
    outline: 2px solid var(--primary-500);
    outline-offset: 2px;
}

.dark .db-line-action {
    color: var(--gray-200);
    background-color: color-mix(in oklab, var(--gray-50) 8%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--gray-50) 16%, transparent);
}

.dark .db-line-action:hover {
    background-color: color-mix(in oklab, var(--gray-50) 14%, transparent);
}

.db-line-action .db-line-action-icon {
    width: 0.875rem;
    height: 0.875rem;
    flex-shrink: 0;
}

/* One block per tone. Written out rather than generated from a list, because
   each modifier needs its own icon colour and its own dark-mode title, and a
   loop would need a preprocessor this file deliberately does not have. */
.db-line--danger {
    background-color: color-mix(in oklab, var(--danger-500) 8%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--danger-500) 20%, transparent);
}

.db-line--danger .db-line-icon {
    color: var(--danger-500);
}

.db-line--danger .db-line-title {
    color: var(--danger-700);
}

.dark .db-line--danger {
    background-color: color-mix(in oklab, var(--danger-400) 12%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--danger-400) 24%, transparent);
}

.dark .db-line--danger .db-line-icon {
    color: var(--danger-400);
}

.dark .db-line--danger .db-line-title {
    color: var(--danger-300);
}

.db-line--warning {
    background-color: color-mix(in oklab, var(--warning-500) 9%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--warning-500) 22%, transparent);
}

.db-line--warning .db-line-icon {
    color: var(--warning-600);
}

.db-line--warning .db-line-title {
    color: var(--warning-700);
}

.dark .db-line--warning {
    background-color: color-mix(in oklab, var(--warning-400) 12%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--warning-400) 24%, transparent);
}

.dark .db-line--warning .db-line-icon {
    color: var(--warning-400);
}

.dark .db-line--warning .db-line-title {
    color: var(--warning-300);
}

.db-line--info {
    background-color: color-mix(in oklab, var(--info-500) 8%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--info-500) 20%, transparent);
}

.db-line--info .db-line-icon {
    color: var(--info-500);
}

.db-line--info .db-line-title {
    color: var(--info-700);
}

.dark .db-line--info {
    background-color: color-mix(in oklab, var(--info-400) 11%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--info-400) 22%, transparent);
}

.dark .db-line--info .db-line-icon {
    color: var(--info-400);
}

.dark .db-line--info .db-line-title {
    color: var(--info-300);
}

/* ------------------------------------------------------------------ *
 * Status badges
 *
 * Deliberately the same shape as .sv-badge in service-page.css rather than a
 * shared class: that file is client-only and this one loads on both panels, so
 * an admin page importing .sv-badge would be the two panels reaching into each
 * other through CSS. The tint percentages match so that a server described on
 * the dashboard and the same server described on its own page do not look like
 * two different states.
 * ------------------------------------------------------------------ */

.db-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.25rem 0.5rem;
    border-radius: var(--radius-lg, 0.5rem);
    font-size: var(--text-xs, 0.75rem);
    font-weight: 600;
    line-height: 1rem;
    white-space: nowrap;
    color: var(--gray-700);
    background-color: color-mix(in oklab, var(--gray-500) 10%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--gray-500) 18%, transparent);
}

.dark .db-badge {
    color: var(--gray-300);
}

/* currentColor, so a modifier only has to set the text colour and the dot
   follows it. */
.db-dot {
    width: 0.375rem;
    height: 0.375rem;
    flex-shrink: 0;
    border-radius: 9999px;
    background-color: currentColor;
}

.db-badge--gray {
    color: var(--gray-700);
    background-color: color-mix(in oklab, var(--gray-500) 10%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--gray-500) 18%, transparent);
}

.dark .db-badge--gray {
    color: var(--gray-300);
}

.db-badge--success {
    color: var(--success-700);
    background-color: color-mix(in oklab, var(--success-500) 12%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--success-500) 22%, transparent);
}

.dark .db-badge--success {
    color: var(--success-300);
}

/* The one piece of motion on a healthy row — a soft halo on the running dot,
   the same as .sv-badge--success gets on the service page. Nothing else here
   glows, which is what makes it mean "up". */
.db-badge--success .db-dot {
    box-shadow: 0 0 0 0.1875rem color-mix(in oklab, var(--success-500) 22%, transparent);
}

.db-badge--warning {
    color: var(--warning-700);
    background-color: color-mix(in oklab, var(--warning-500) 12%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--warning-500) 22%, transparent);
}

.dark .db-badge--warning {
    color: var(--warning-300);
}

.db-badge--danger {
    color: var(--danger-700);
    background-color: color-mix(in oklab, var(--danger-500) 12%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--danger-500) 22%, transparent);
}

.dark .db-badge--danger {
    color: var(--danger-300);
}

.db-badge--info {
    color: var(--info-700);
    background-color: color-mix(in oklab, var(--info-500) 12%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--info-500) 22%, transparent);
}

.dark .db-badge--info {
    color: var(--info-300);
}

/* ------------------------------------------------------------------ *
 * Server rows
 *
 * The whole strip is the link. Cells declare their own flex-basis and the row
 * wraps, so this reflows from one line to two to a stack without a single
 * media query — which matters because the widget is full-width on a dashboard
 * whose column count Filament decides, not this file.
 * ------------------------------------------------------------------ */

.db-servers {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.db-server {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem 1.25rem;
    padding: 0.75rem 0.875rem;
    border-radius: var(--radius-lg, 0.5rem);
    text-decoration: none;
    background-color: color-mix(in oklab, var(--gray-500) 4%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--gray-500) 12%, transparent);
    transition:
        background-color 75ms ease,
        box-shadow 75ms ease;
}

.db-server:hover {
    background-color: color-mix(in oklab, var(--gray-500) 8%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--gray-500) 22%, transparent);
}

.db-server:focus-visible {
    outline: 2px solid var(--primary-500);
    outline-offset: 2px;
}

.dark .db-server {
    background-color: color-mix(in oklab, var(--gray-50) 5%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--gray-50) 12%, transparent);
}

.dark .db-server:hover {
    background-color: color-mix(in oklab, var(--gray-50) 9%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--gray-50) 20%, transparent);
}

/* object-fit, because these are operator-supplied PNGs of no guaranteed aspect
   ratio and a stretched distribution mark looks like a broken page. */
.db-server-logo {
    width: 1.75rem;
    height: 1.75rem;
    flex-shrink: 0;
    object-fit: contain;
}

/* Grows to take the slack, so the badges stay against the right edge on a wide
   row and the name is what gives way rather than the figures. */
.db-server-main {
    display: flex;
    flex-direction: column;
    flex: 1 1 11rem;
    min-width: 0;
}

.db-server-name {
    font-size: var(--text-sm, 0.875rem);
    font-weight: 600;
    line-height: 1.25rem;
    color: var(--gray-950);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dark .db-server-name {
    color: white;
}

.db-server-meta {
    font-size: var(--text-xs, 0.75rem);
    line-height: 1.125rem;
    color: var(--gray-500);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dark .db-server-meta {
    color: var(--gray-400);
}

/* Fixed basis and no growth: three cells that grew unevenly would put the same
   fact in a different place on every row, which is the one thing a list of
   rows exists to avoid. */
.db-server-cell {
    display: flex;
    flex-direction: column;
    flex: 0 1 9rem;
    min-width: 0;
}

.db-server-label {
    font-size: 0.6875rem;
    font-weight: 600;
    line-height: 1rem;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--gray-400);
}

.dark .db-server-label {
    color: var(--gray-500);
}

.db-server-value {
    font-size: var(--text-sm, 0.875rem);
    font-weight: 500;
    line-height: 1.25rem;
    color: var(--gray-950);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dark .db-server-value {
    color: white;
}

.db-server-value--quiet {
    font-weight: 400;
    color: var(--gray-600);
}

.dark .db-server-value--quiet {
    color: var(--gray-400);
}

.db-server-value--warning {
    color: var(--warning-700);
}

.dark .db-server-value--warning {
    color: var(--warning-400);
}

.db-server-value--danger {
    color: var(--danger-700);
}

.dark .db-server-value--danger {
    color: var(--danger-400);
}

/* Monospaced and selectable. This is the one string on the row somebody copies
   into a terminal, and a proportional font is where a 1 and an l stop being
   distinguishable. */
.db-server-ip {
    font-family: var(--font-mono, ui-monospace, monospace);
    font-size: 0.8125rem;
    user-select: all;
}

.db-server-note {
    font-size: var(--text-xs, 0.75rem);
    line-height: 1.125rem;
    color: var(--gray-500);
    font-variant-numeric: tabular-nums;
}

.dark .db-server-note {
    color: var(--gray-400);
}

.db-server-badges {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.375rem;
    flex-shrink: 0;
    margin-inline-start: auto;
}

.db-servers-more {
    margin-top: 0.75rem;
    font-size: var(--text-xs, 0.75rem);
    line-height: 1.125rem;
    color: var(--gray-500);
}

.dark .db-servers-more {
    color: var(--gray-400);
}

.db-servers-more-link {
    font-weight: 600;
    text-decoration: none;
    color: var(--primary-600);
}

.db-servers-more-link:hover {
    text-decoration: underline;
}

.dark .db-servers-more-link {
    color: var(--primary-400);
}

/* ------------------------------------------------------------------ *
 * Nothing here yet
 *
 * Only used where an empty section is a question worth answering — a customer
 * with no servers. Not used by the attention panel, which hides itself instead.
 * ------------------------------------------------------------------ */

.db-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 1.5rem 1rem;
    text-align: center;
}

.db-empty .db-empty-icon {
    width: 2rem;
    height: 2rem;
    color: var(--gray-300);
}

.dark .db-empty .db-empty-icon {
    color: var(--gray-600);
}

.db-empty-title {
    margin-top: 0.75rem;
    font-size: var(--text-sm, 0.875rem);
    font-weight: 600;
    line-height: 1.25rem;
    color: var(--gray-950);
}

.dark .db-empty-title {
    color: white;
}

.db-empty-body {
    margin-top: 0.25rem;
    max-width: 24rem;
    font-size: var(--text-sm, 0.875rem);
    line-height: 1.375rem;
    color: var(--gray-500);
}

.dark .db-empty-body {
    color: var(--gray-400);
}

/* The one filled button in this stylesheet. Everything else here reports, and
   this is the only place the panel is asking for something to be done. */
.db-empty-action {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    margin-top: 1rem;
    padding: 0.5rem 0.875rem;
    border-radius: var(--radius-lg, 0.5rem);
    font-size: var(--text-sm, 0.875rem);
    font-weight: 600;
    line-height: 1.25rem;
    text-decoration: none;
    color: white;
    background-color: var(--primary-600);
    transition: background-color 75ms ease;
}

.db-empty-action:hover {
    background-color: var(--primary-500);
}

.db-empty-action:focus-visible {
    outline: 2px solid var(--primary-500);
    outline-offset: 2px;
}

/* ------------------------------------------------------------------ *
 * Node capacity
 *
 * Admin side only, but it lives here because dashboard.css is registered on
 * both panels and splitting one stylesheet in two to keep four selectors apart
 * would cost a second HTTP request on every page of both panels.
 *
 * A block per node rather than a row, because a node carries three meters and a
 * count and there is no reading order that fits those across a line — least of
 * all in the half-width column this widget occupies. Same surface treatment as
 * .db-server so the two dashboards feel like one product.
 * ------------------------------------------------------------------ */

.db-nodes {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.db-node {
    display: flex;
    flex-direction: column;
    gap: 0.625rem;
    padding: 0.875rem;
    border-radius: var(--radius-lg, 0.5rem);
    text-decoration: none;
    background-color: color-mix(in oklab, var(--gray-500) 4%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--gray-500) 12%, transparent);
    transition:
        background-color 75ms ease,
        box-shadow 75ms ease;
}

.db-node:hover {
    background-color: color-mix(in oklab, var(--gray-500) 8%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--gray-500) 22%, transparent);
}

.db-node:focus-visible {
    outline: 2px solid var(--primary-500);
    outline-offset: 2px;
}

.dark .db-node {
    background-color: color-mix(in oklab, var(--gray-50) 5%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--gray-50) 12%, transparent);
}

.dark .db-node:hover {
    background-color: color-mix(in oklab, var(--gray-50) 9%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--gray-50) 20%, transparent);
}

/* Wraps, because a long node name beside two badges is the ordinary case in a
   half-width column and truncating the name would hide which node this is. */
.db-node-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}

.db-node-name {
    font-size: var(--text-sm, 0.875rem);
    font-weight: 600;
    line-height: 1.25rem;
    color: var(--gray-950);
}

.dark .db-node-name {
    color: white;
}

.db-node-badges {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.375rem;
}

/* The service cap, which no meter above it can express. Quiet by default and
   red at the limit, because at the limit it is the only reason the node is
   refusing orders. */
.db-node-guests {
    font-size: var(--text-xs, 0.75rem);
    line-height: 1rem;
    color: var(--gray-500);
}

.dark .db-node-guests {
    color: var(--gray-400);
}

.db-node-guests--danger {
    font-weight: 600;
    color: var(--danger-600);
}

.dark .db-node-guests--danger {
    color: var(--danger-400);
}

/* ------------------------------------------------------------------ *
 * Meters
 *
 * A label and a percentage on one line, the bar under it, the raw figures under
 * that. Deliberately not a <progress>: its rendering is the browser's to decide
 * and Firefox, Safari and Chrome disagree about every part of it, including
 * whether the fill can be recoloured at all.
 *
 * The track keeps its inset ring in both schemes so a 0% bar is still visibly a
 * bar. Without it an empty meter reads as a gap in the layout.
 * ------------------------------------------------------------------ */

.db-meter {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}

.db-meter-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.5rem;
}

.db-meter-label {
    font-size: var(--text-xs, 0.75rem);
    font-weight: 500;
    line-height: 1rem;
    color: var(--gray-500);
}

.dark .db-meter-label {
    color: var(--gray-400);
}

/* Tabular figures so three stacked percentages line up on the decimal rather
   than shifting as the digits change. */
.db-meter-value {
    font-size: var(--text-xs, 0.75rem);
    font-weight: 600;
    line-height: 1rem;
    font-variant-numeric: tabular-nums;
    color: var(--gray-950);
}

.dark .db-meter-value {
    color: white;
}

.db-meter-track {
    position: relative;
    height: 0.375rem;
    border-radius: 9999px;
    overflow: hidden;
    background-color: color-mix(in oklab, var(--gray-500) 12%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--gray-500) 8%, transparent);
}

.dark .db-meter-track {
    background-color: color-mix(in oklab, var(--gray-50) 12%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--gray-50) 8%, transparent);
}

/* The width is an inline style, because it is data — a number from the database
   and not one of a fixed set of states a class could name. min-width keeps a
   1% allocation visible as a sliver rather than rounding it away to nothing. */
.db-meter-fill {
    display: block;
    height: 100%;
    min-width: 0.125rem;
    border-radius: 9999px;
    transition: width 150ms ease;
}

/* Two classes deep throughout: <x-filament::icon> and Filament's own utilities
   stamp single-class rules on these elements, and a single-class rule here
   would tie and be settled by stylesheet order rather than by intent. */
.db-meter .db-meter-fill--success {
    background-color: var(--success-500);
}

.db-meter .db-meter-fill--warning {
    background-color: var(--warning-500);
}

.db-meter .db-meter-fill--danger {
    background-color: var(--danger-500);
}

/* Unknown capacity. Rendered at zero width anyway, so this only shows through
   the min-width sliver — grey, so it cannot be mistaken for a healthy reading. */
.db-meter .db-meter-fill--quiet {
    background-color: var(--gray-400);
}

.db-meter-detail {
    font-size: var(--text-xs, 0.75rem);
    line-height: 1rem;
    color: var(--gray-500);
    font-variant-numeric: tabular-nums;
}

.dark .db-meter-detail {
    color: var(--gray-400);
}

/* ------------------------------------------------------------------ *
 * The impersonation bar
 *
 * An admin viewing a customer's panel is looking at a screen designed to be
 * indistinguishable from the customer's own, and every button on it really
 * works. So the state is stated permanently, and it is the one thing in this
 * stylesheet allowed to be loud.
 *
 * Fixed to the bottom rather than static at the top, which is a consequence of
 * the anchor rather than a preference: the partial renders on
 * PanelsRenderHook::BODY_START, the first child of <body>, and Filament's own
 * topbar is sticky — so a static bar above it would scroll away while the topbar
 * stayed, leaving a warning that is only true for the first three seconds. The
 * bottom edge also keeps it out of the topbar's z-stack and off the path of a
 * modal overlay.
 *
 * Warning rather than danger. Nothing has gone wrong; a state that shouts "error"
 * every second of an ordinary support call teaches an operator to stop reading it.
 * ------------------------------------------------------------------ */

.db-impersonating {
    position: fixed;
    inset-inline: 0;
    bottom: 0;
    z-index: 40;
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.625rem 1rem;
    font-size: var(--text-sm, 0.875rem);
    line-height: 1.25rem;
    color: var(--warning-900);
    background-color: var(--warning-100);
    box-shadow: 0 -1px 0 0 var(--warning-300);
}

.dark .db-impersonating {
    color: var(--warning-100);
    /* A tint of the warning hue rather than warning-900 itself: the bar sits over
       a near-black page, and the filled family at that end is bright enough to
       glare across the full width of a screen. */
    background-color: color-mix(in srgb, var(--warning-500) 22%, var(--gray-950));
    box-shadow: 0 -1px 0 0 color-mix(in srgb, var(--warning-500) 45%, transparent);
}

/* Two deep for the same reason as .db-chip-icon: <x-filament::icon> stamps its
   own single-class sizing rule on the element. */
.db-impersonating .db-impersonating-icon {
    flex: none;
    width: 1.25rem;
    height: 1.25rem;
    color: var(--warning-600);
}

.dark .db-impersonating .db-impersonating-icon {
    color: var(--warning-400);
}

/* Takes the slack so the button stays against the trailing edge, and wraps
   rather than truncating: the sentence names an account, and a name cut off
   mid-word is the one part of this bar that has to survive a narrow screen. */
.db-impersonating-text {
    flex: 1 1 auto;
    min-width: 0;
    margin: 0;
}

.db-impersonating-form {
    flex: none;
    margin: 0;
}

/* The way out, and the second filled button in this stylesheet. Filled on
   purpose: this is the action the bar is asking for, and a quiet outline beside
   a coloured warning reads as decoration. */
.db-impersonating-stop {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.375rem 0.75rem;
    border: 0;
    border-radius: var(--radius-lg, 0.5rem);
    font-size: var(--text-sm, 0.875rem);
    font-weight: 600;
    line-height: 1.25rem;
    white-space: nowrap;
    cursor: pointer;
    color: var(--warning-50);
    background-color: var(--warning-600);
    transition: background-color 75ms ease;
}

.db-impersonating-stop:hover {
    background-color: var(--warning-700);
}

.db-impersonating-stop:focus-visible {
    outline: 2px solid var(--warning-800);
    outline-offset: 2px;
}

.dark .db-impersonating-stop {
    color: var(--gray-950);
    background-color: var(--warning-400);
}

.dark .db-impersonating-stop:hover {
    background-color: var(--warning-300);
}

.dark .db-impersonating-stop:focus-visible {
    outline-color: var(--warning-200);
}

.db-impersonating-stop .db-impersonating-stop-icon {
    flex: none;
    width: 1rem;
    height: 1rem;
}

/* So a fixed bar never permanently covers the last row of a table. Scoped to a
   page that actually has one, which is what :has buys — a padding-bottom applied
   unconditionally would leave a strip of dead space under every customer's
   dashboard forever. */
body:has(.db-impersonating) {
    padding-bottom: 4rem;
}

/* Under 40rem the sentence and the button cannot share a line without the button
   squeezing the name, so they stack and the button spans the width — which is
   also the easiest target to hit on a phone. */
@media (max-width: 40rem) {
    .db-impersonating {
        flex-wrap: wrap;
        gap: 0.5rem;
    }

    .db-impersonating-text {
        flex-basis: calc(100% - 2rem);
    }

    .db-impersonating-form {
        flex: 1 1 100%;
    }

    .db-impersonating-stop {
        width: 100%;
        justify-content: center;
    }

    body:has(.db-impersonating) {
        padding-bottom: 7rem;
    }
}
