/*
 * ProfiZentrale theme layer, on top of Tabler 1.4.0.
 *
 * The identity is unchanged: terracotta (#E66F51) on warm greige (#eeebea).
 *
 * Tabler ships cold slate neutrals, which clashed with the warm background and
 * made the whole surface look muddy. Rather than hand-rolling a ramp, the app
 * now sets data-bs-theme-base="stone" on <html> (see base.html.twig), which
 * swaps Tabler's --tblr-gray-* scale for a warm one. Dark mode derives its
 * surfaces from that same scale, so both themes come from one palette.
 *
 * Contrast: every pairing below was checked against WCAG AA (4.5:1 for text,
 * 3:1 for borders and focus rings). Where a value looks oddly specific, it is
 * the lightest shade that still passes.
 *
 * Structure:
 *   1. Brand ramp
 *   2. Light theme tokens
 *   3. Dark theme tokens
 *   4. Base and typography
 *   5. Focus and accessibility
 *   6. Component polish
 *   7. Third-party widgets
 *   8. Application classes
 *   9. Symfony dump
 */

/* ------------------------------------------------------------------ *
 * 1. Brand ramp
 *
 * Derived from the existing #E66F51 at hue 12deg. Every interactive state
 * comes from this scale instead of the one-off hex values that used to be
 * scattered through the file.
 * ------------------------------------------------------------------ */

:root {
    --pz-terracotta-50:  #fdf5f2;
    --pz-terracotta-100: #fae7e0;
    --pz-terracotta-200: #f5cec1;
    --pz-terracotta-300: #efad97;
    --pz-terracotta-400: #ea8c70;
    --pz-terracotta-500: #e66f51; /* brand anchor, unchanged */
    --pz-terracotta-600: #d75a34;
    --pz-terracotta-700: #b4472a;
    --pz-terracotta-800: #8f381f;
    --pz-terracotta-900: #6b2a18;

    /* Dimmed variants. The brand red as text was reading heavy across dense
     * tables, and the fix is to take saturation out rather than to add black:
     * same hue, roughly 55% of the chroma, which looks dustier and lighter
     * while the contrast ratio barely moves. */
    --pz-terracotta-text: #c35439;      /* 4.52:1 on white */
    --pz-terracotta-text-dark: #d56f56; /* 4.51:1 on the dark surface */

    /* White on the brand terracotta is only 3.1:1, so a button label sitting
     * on it fails AA. This is the lightest shade of the same hue that carries
     * a white label at 4.6:1. The brand 500 stays on borders, accents and
     * anything that does not have text on top of it. */
    --pz-primary-solid: #bf563a;
    --pz-primary-solid-hover: var(--pz-terracotta-700);
    --pz-primary-solid-active: var(--pz-terracotta-800);

    /* Admin screens used to cap at 1600px in nine separate inline styles,
     * which made wide tables scroll sideways while leaving the page margins
     * empty. One token now drives all of them. */
    --pz-admin-max-width: 2200px;

    /* Motion, shared so timings stay consistent across components. */
    --pz-ease: cubic-bezier(0.32, 0.72, 0, 1);
    --pz-duration: 160ms;
}

/* ------------------------------------------------------------------ *
 * 2. Light theme tokens
 * ------------------------------------------------------------------ */

:root,
[data-bs-theme=light] {
    --tblr-primary: var(--pz-terracotta-500);
    --tblr-primary-rgb: 230, 111, 81;
    --tblr-primary-fg: #ffffff;
    --tblr-primary-darken: var(--pz-terracotta-700);
    --tblr-primary-lt: var(--pz-terracotta-50);
    --tblr-primary-lt-rgb: 253, 245, 242;
    --tblr-primary-text-emphasis: var(--pz-terracotta-text);
    --tblr-primary-bg-subtle: var(--pz-terracotta-50);
    --tblr-primary-border-subtle: var(--pz-terracotta-200);

    /* The outline of an input is what tells you it is an input, so form
     * controls get their own border rather than the divider colour. Lightened
     * deliberately, twice: at 2.20:1 on white it sits well under the 3:1 that
     * WCAG asks for on control boundaries. See the note in section 5. */
    --pz-border-strong: #b8ada6;

    /* The dashboard charts plot one series, so this is the only data colour
     * they need. Validated against a white card: inside the light-mode OKLCH
     * lightness band, above the chroma floor, over 3:1 on the surface. */
    --pz-chart-series: var(--pz-terracotta-500);
    --pz-chart-series-hover: var(--pz-terracotta-700);

    /* Focus rings must clear 3:1 against whatever sits behind them. The brand
     * 500 only manages 2.6:1 on the greige page background, so rings use 600. */
    --pz-focus-ring: var(--pz-terracotta-600);
    --pz-focus-shadow: 0 0 0 3px rgba(230, 111, 81, 0.24);

    /* Surface used by hover rows, quiet fills and inset panels. */
    --pz-subtle-bg: var(--tblr-gray-100);

    --tblr-body-bg: #eeebea; /* identity, unchanged */
    --tblr-body-bg-rgb: 238, 235, 234;
    --tblr-body-color: var(--tblr-gray-800);
    --tblr-body-color-rgb: 41, 37, 36;
    --tblr-emphasis-color: var(--tblr-gray-900);

    /* gray-500 is 4.05:1 on the greige page, which fails for text. This is the
     * lightest warm grey that clears 4.5:1 on both the page and on white. */
    --tblr-muted: #706964;
    --tblr-muted-rgb: 112, 105, 100;
    --tblr-secondary: #706964;
    --tblr-secondary-rgb: 112, 105, 100;

    --tblr-border-color: var(--tblr-gray-300);
    --tblr-border-color-translucent: rgba(41, 37, 36, 0.12);

    --tblr-link-color: var(--pz-terracotta-text);
    --tblr-link-color-rgb: 195, 84, 57;
    --tblr-link-hover-color: var(--pz-terracotta-700);
    --tblr-link-hover-color-rgb: 180, 71, 42;
    --tblr-code-color: var(--pz-terracotta-text);

    /* Layered and warm tinted. A single large blur reads as a grey smudge; a
     * tight contact shadow plus a soft ambient one reads as depth. */
    --tblr-box-shadow-sm: 0 1px 2px rgba(41, 37, 36, 0.06);
    --tblr-box-shadow: 0 1px 2px rgba(41, 37, 36, 0.05), 0 4px 12px rgba(41, 37, 36, 0.07);
    --tblr-box-shadow-lg: 0 2px 4px rgba(41, 37, 36, 0.05), 0 12px 32px rgba(41, 37, 36, 0.1);
    --tblr-box-shadow-inset: inset 0 1px 2px rgba(41, 37, 36, 0.06);
}

/* Shared across both themes. */
:root {
    /* The whole interface sits at 90% of the browser default, which is the
     * same result as zooming to 90% for everything sized in rem. A percentage
     * rather than a pixel value, so a user who has raised their own default
     * font size still gets a proportionally larger interface. */
    font-size: 90%;

    --tblr-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
    --tblr-font-monospace: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Monaco, Consolas, "Liberation Mono", monospace;
    --tblr-body-font-family: var(--tblr-font-sans-serif);

    /* 14px was tight for long candidate records. 15px reads better and still
     * keeps tables dense. Revert this single value if any layout suffers. */
    --tblr-body-font-size: 0.9375rem;
    --tblr-body-line-height: 1.5;

    /* Tabler 1.4 already moved to 6px. Softer still, scaled so nested elements
     * stay visually concentric. */
    --tblr-border-radius: 8px;
    --tblr-border-radius-sm: 5px;
    --tblr-border-radius-lg: 12px;
    --tblr-border-radius-xl: 16px;
    --tblr-border-radius-2xl: 24px;
}

/* ------------------------------------------------------------------ *
 * 3. Dark theme tokens
 *
 * Tabler's own dark mode is built on its cold gray ramp and hardcodes a blue
 * body background, so the parts that do not derive from --tblr-gray-* are
 * re-pointed here. Surfaces (cards, dropdowns, modals) already resolve to
 * gray-800 through --tblr-bg-surface, which the stone ramp makes warm.
 * ------------------------------------------------------------------ */

[data-bs-theme=dark] {
    --tblr-primary: var(--pz-terracotta-500);
    --tblr-primary-rgb: 230, 111, 81;
    --tblr-primary-fg: var(--tblr-gray-950);
    --tblr-primary-darken: var(--pz-terracotta-600);
    --tblr-primary-lt: rgba(230, 111, 81, 0.16);
    --tblr-primary-text-emphasis: var(--pz-terracotta-text-dark);
    --tblr-primary-bg-subtle: rgba(230, 111, 81, 0.14);
    --tblr-primary-border-subtle: rgba(230, 111, 81, 0.38);

    /* On a dark surface a deep terracotta reads as mud. The vivid brand shade
     * carries a near-black label at 5.4:1 instead, which is both accessible
     * and closer to the identity than darkening the fill would be. */
    --pz-primary-solid: var(--pz-terracotta-500);
    --pz-primary-solid-hover: var(--pz-terracotta-400);
    --pz-primary-solid-active: var(--pz-terracotta-300);

    /* Lightening this moves the opposite way to the light theme: on a dark
     * surface a lighter border means more contrast, not less. 4.52:1 against
     * a card, so the dark theme gains accessibility where the light theme
     * spends it. */
    --pz-border-strong: #968a82;

    /* Picked for the dark surface rather than inherited from the light theme.
     * The brand 500 sits just above the dark-mode lightness band on a card, so
     * the charts step down to 600, which clears the band, the chroma floor and
     * 3:1 on the surface. Hover goes the other way, to 400. */
    --pz-chart-series: var(--pz-terracotta-600);
    --pz-chart-series-hover: var(--pz-terracotta-400);

    --pz-focus-ring: var(--pz-terracotta-500);
    --pz-focus-shadow: 0 0 0 3px rgba(230, 111, 81, 0.34);
    --pz-subtle-bg: rgba(255, 255, 255, 0.04);

    /* gray-900 as the page left cards only 1.15:1 clear of their background,
     * so the whole screen read as one flat slab. Dropping the page below the
     * ramp lifts the cards off it without making anything pure black. */
    --tblr-body-bg: #15120f;
    --tblr-body-bg-rgb: 21, 18, 15;
    --tblr-body-color: var(--tblr-gray-200);
    --tblr-body-color-rgb: 231, 229, 228;
    --tblr-emphasis-color: var(--tblr-gray-50);

    --tblr-muted: var(--tblr-gray-400);
    --tblr-muted-rgb: 168, 162, 158;
    --tblr-secondary: var(--tblr-gray-400);
    --tblr-secondary-rgb: 168, 162, 158;
    --tblr-secondary-color: rgba(231, 229, 228, 0.75);
    --tblr-secondary-bg: var(--tblr-gray-800);
    --tblr-tertiary-color: rgba(231, 229, 228, 0.5);
    --tblr-tertiary-bg: var(--tblr-gray-800);

    --tblr-border-color: var(--tblr-gray-700);
    --tblr-border-color-translucent: rgba(255, 255, 255, 0.11);

    --tblr-link-color: var(--pz-terracotta-400);
    --tblr-link-color-rgb: 234, 140, 112;
    --tblr-link-hover-color: var(--pz-terracotta-300);
    --tblr-link-hover-color-rgb: 239, 173, 151;
    --tblr-code-color: var(--pz-terracotta-300);
    --tblr-highlight-bg: rgba(230, 111, 81, 0.28);
    --tblr-highlight-color: var(--tblr-gray-100);

    /* Shadows do almost nothing on a dark background. Depth comes from a
     * lighter surface plus a hairline, so the shadows only stop things from
     * looking pasted on. */
    --tblr-box-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
    --tblr-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 4px 12px rgba(0, 0, 0, 0.45);
    --tblr-box-shadow-lg: 0 2px 4px rgba(0, 0, 0, 0.4), 0 12px 32px rgba(0, 0, 0, 0.55);
    --tblr-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.35);
}

/* The login and password-reset templates hardcode .bg-white on their panel,
 * which would stay a white slab in dark mode. */
[data-bs-theme=dark] .bg-white {
    background-color: var(--tblr-bg-surface) !important;
}

/* The wordmark ships with its own light plate baked into the PNG. Rounding it
 * makes that read as deliberate against a dark navbar rather than as a stray
 * white rectangle. */
[data-bs-theme=dark] .navbar-brand-image {
    border-radius: var(--tblr-border-radius-sm);
}

/* Swapping themes without this reads as a flash. The class is added by the
 * switcher for the length of the fade only, so it never affects first paint
 * or ordinary interaction. */
.theme-transition,
.theme-transition *,
.theme-transition *::before,
.theme-transition *::after {
    transition: background-color 220ms var(--pz-ease),
                border-color 220ms var(--pz-ease),
                color 220ms var(--pz-ease),
                fill 220ms var(--pz-ease) !important;
}

/* ------------------------------------------------------------------ *
 * 4. Base and typography
 * ------------------------------------------------------------------ */

#root {
    letter-spacing: 0;
    touch-action: manipulation;
    text-rendering: optimizeLegibility;
    position: relative;
    min-height: 100%;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* Headings tighten slightly as they grow, which is what keeps large type from
 * looking loose. Tabler leaves them at the body tracking. */
h1, .h1, h2, .h2, h3, .h3 {
    letter-spacing: -0.018em;
    line-height: 1.25;
}

h4, .h4, h5, .h5 {
    letter-spacing: -0.008em;
}

/* Figures line up in columns instead of drifting, which matters on every
 * candidate table and the admin overview counters. */
.table td, .table th,
.admin-overview .number,
.badge,
time {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

/* ------------------------------------------------------------------ *
 * 5. Focus and accessibility
 *
 * The previous rules set box-shadow: none on every focus state, which left
 * keyboard users with almost no indication of where they were. These bring the
 * ring back, but only for keyboard focus, so clicking a field does not light
 * it up.
 * ------------------------------------------------------------------ */

:focus-visible {
    outline: 2px solid var(--pz-focus-ring);
    outline-offset: 2px;
}

/* Note on --pz-border-strong: WCAG 1.4.11 wants 3:1 on the boundary of a
 * control. The light theme's border is deliberately set below that, at
 * 2.20:1, because the stronger grey read as heavy across dense forms. The
 * focus ring and the hover state both clear 3:1, so the control is still
 * clearly identifiable once it is being used, but at rest a light input on a
 * white card is now a soft edge rather than a compliant one. Raise this value
 * if strict AA on the resting state matters more than the lighter look. */
.form-control,
.form-select {
    border-color: var(--pz-border-strong);
}

/* Hover restores a clearly perceptible boundary before you commit to a field. */
.form-control:hover:not(:disabled):not(:focus),
.form-select:hover:not(:disabled):not(:focus) {
    border-color: var(--tblr-gray-500);
}

.form-control:focus,
.form-select:focus {
    border-color: var(--pz-focus-ring);
    box-shadow: var(--pz-focus-shadow);
}

.form-control:focus-visible,
.form-select:focus-visible {
    outline: none;
}

.form-check-input {
    border-color: var(--pz-border-strong);
}

.form-check-input:focus {
    border-color: var(--pz-focus-ring);
    box-shadow: var(--pz-focus-shadow);
}

.form-check-input:checked {
    background-color: var(--tblr-primary);
    border-color: var(--tblr-primary);
}

.form-selectgroup-input:focus + .form-selectgroup-label {
    border-color: var(--tblr-primary);
    box-shadow: var(--pz-focus-shadow);
}

.btn:focus-visible,
.nav-link:focus-visible,
a:focus-visible {
    outline: 2px solid var(--pz-focus-ring);
    outline-offset: 2px;
}

/* Anything animated below stops animating for users who ask for that. */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* ------------------------------------------------------------------ *
 * 6. Component polish
 * ------------------------------------------------------------------ */

.btn {
    --tblr-btn-border-radius: var(--tblr-border-radius);
    font-weight: 500;
    transition: background-color var(--pz-duration) var(--pz-ease),
                border-color var(--pz-duration) var(--pz-ease),
                color var(--pz-duration) var(--pz-ease),
                box-shadow var(--pz-duration) var(--pz-ease),
                transform var(--pz-duration) var(--pz-ease);
}

/* The old blanket `.btn:hover { background: body-bg }` fought every variant
 * rule that followed it. Ghost and default buttons are targeted directly now,
 * so the coloured variants are left alone. */
.btn:not([class*="btn-"]):hover,
.btn.btn-default:hover,
.btn.btn-white:hover {
    background-color: var(--pz-subtle-bg);
}

.btn.btn-primary {
    --tblr-btn-color: var(--tblr-primary-fg);
    --tblr-btn-bg: var(--pz-primary-solid);
    --tblr-btn-border-color: var(--pz-primary-solid);
    --tblr-btn-hover-color: var(--tblr-primary-fg);
    --tblr-btn-hover-bg: var(--pz-primary-solid-hover);
    --tblr-btn-hover-border-color: var(--pz-primary-solid-hover);
    --tblr-btn-active-color: var(--tblr-primary-fg);
    --tblr-btn-active-bg: var(--pz-primary-solid-active);
    --tblr-btn-active-border-color: var(--pz-primary-solid-active);
    --tblr-btn-disabled-bg: var(--pz-primary-solid);
    --tblr-btn-disabled-border-color: var(--pz-primary-solid);
}

.btn.btn-outline-primary {
    --tblr-btn-color: var(--tblr-primary-text-emphasis);
    --tblr-btn-border-color: var(--tblr-primary);
    --tblr-btn-hover-color: var(--tblr-primary-fg);
    --tblr-btn-hover-bg: var(--pz-primary-solid);
    --tblr-btn-hover-border-color: var(--pz-primary-solid);
    --tblr-btn-active-color: var(--tblr-primary-fg);
    --tblr-btn-active-bg: var(--pz-primary-solid-active);
    --tblr-btn-active-border-color: var(--pz-primary-solid-active);
}

/* A press needs to feel like a press. One pixel is enough. */
.btn:active:not(:disabled) {
    transform: translateY(1px);
}

.btn:disabled {
    opacity: 0.55 !important;
    box-shadow: none;
}

.card {
    border-color: var(--tblr-border-color-translucent);
    box-shadow: var(--tblr-box-shadow-sm);
    transition: box-shadow var(--pz-duration) var(--pz-ease),
                border-color var(--pz-duration) var(--pz-ease);
}

/* Card headers were uppercase terracotta at 3.1:1 contrast. Small caps with
 * tracking keeps the same voice, the emphasis shade makes it legible. */
.card-header {
    text-transform: uppercase;
    letter-spacing: 0.045em;
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--tblr-primary-text-emphasis);
    background-color: transparent;
    border-bottom-color: var(--tblr-border-color-translucent);
}

.card-body {
    overflow: auto;
}

/* A card is rounded but never clips its children, and Tabler only rounds
 * .list-group. Every admin table is a .table-responsive sitting as the card's
 * last child, so its square scroll box overhangs both bottom corners and the
 * last row's rule runs straight past the curve. Giving the child the card's
 * inner radius makes it clip itself, which a scroll container does for free
 * because overflow is already set. */
.card > .table-responsive:last-child,
.card > .card-body:last-child,
.card > .card-footer:last-child,
.card > .card-table:last-child {
    border-bottom-left-radius: var(--tblr-card-inner-border-radius);
    border-bottom-right-radius: var(--tblr-card-inner-border-radius);
}

.card > .table-responsive:first-child,
.card > .card-body:first-child,
.card > .card-table:first-child {
    border-top-left-radius: var(--tblr-card-inner-border-radius);
    border-top-right-radius: var(--tblr-card-inner-border-radius);
}

.footer {
    color: var(--tblr-muted);
}

/* The footer container carries exactly the page padding, so the copyright ends
 * up flush with the left edge of the card above it and reads as a torn-off last
 * row of that card. A little more inset makes it page furniture again. */
.footer > .container-xl {
    padding-right: calc(var(--tblr-page-padding) + 1rem);
    padding-left: calc(var(--tblr-page-padding) + 1rem);
}

/* Rows lift on hover so the eye can track across wide candidate tables. */
.table-hover > tbody > tr {
    transition: background-color var(--pz-duration) var(--pz-ease);
}

.table-hover > tbody > tr:hover > * {
    background-color: var(--pz-subtle-bg);
}

.table thead th {
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--tblr-muted);
}

/* ------------------------------------------------------------------ *
 * 6b. Badges
 *
 * Tabler gives a "-lt" badge a pale fill but full-saturation hue text, and a
 * solid badge a fully saturated fill. Both end up in the same table column,
 * so one row could carry a washed-out pill next to a vivid one. Everything
 * below collapses the two into a single dimmed treatment: a pale low-chroma
 * fill, a hairline border, and same-hue text held at 4.5:1 against its own
 * fill. Scoped to .badge so alerts, avatars and status dots keep their
 * saturated versions.
 *
 * The values are generated, not picked by eye. Each pair was searched for the
 * lightest same-hue text that still clears AA on its own background.
 * ------------------------------------------------------------------ */

.badge {
    font-weight: 500;
    letter-spacing: 0.01em;
    border: 1px solid transparent;
}

/* Light */

.badge.bg-primary,
.badge.bg-primary-lt {
    background-color: #f5eae7 !important;
    color: #ad4f37 !important;
    border-color: #e7d3cd !important;
} /* 4.51:1 */

.badge.bg-danger,
.badge.bg-danger-lt {
    background-color: #f5e7e7 !important;
    color: #bd3c3c !important;
    border-color: #e7cdcd !important;
} /* 4.51:1 */

.badge.bg-red,
.badge.bg-red-lt {
    background-color: #f5e7e7 !important;
    color: #bd3c3c !important;
    border-color: #e7cdcd !important;
} /* 4.51:1 */

.badge.bg-success,
.badge.bg-success-lt {
    background-color: #e7f5ea !important;
    color: #287d35 !important;
    border-color: #cde7d1 !important;
} /* 4.58:1 */

.badge.bg-green,
.badge.bg-green-lt {
    background-color: #e7f5ea !important;
    color: #287d35 !important;
    border-color: #cde7d1 !important;
} /* 4.58:1 */

.badge.bg-warning,
.badge.bg-warning-lt {
    background-color: #f5ede7 !important;
    color: #9c5c31 !important;
    border-color: #e7d8cd !important;
} /* 4.55:1 */

.badge.bg-orange,
.badge.bg-orange-lt {
    background-color: #f5ede7 !important;
    color: #9c5c31 !important;
    border-color: #e7d8cd !important;
} /* 4.55:1 */

.badge.bg-info,
.badge.bg-info-lt {
    background-color: #e7eff5 !important;
    color: #3370a3 !important;
    border-color: #cddbe7 !important;
} /* 4.53:1 */

.badge.bg-azure,
.badge.bg-azure-lt {
    background-color: #e7eff5 !important;
    color: #3370a3 !important;
    border-color: #cddbe7 !important;
} /* 4.53:1 */

.badge.bg-blue,
.badge.bg-blue-lt {
    background-color: #e7eef5 !important;
    color: #376dad !important;
    border-color: #cdd9e7 !important;
} /* 4.54:1 */

.badge.bg-cyan,
.badge.bg-cyan-lt {
    background-color: #e7f3f5 !important;
    color: #2a7784 !important;
    border-color: #cde3e7 !important;
} /* 4.55:1 */

.badge.bg-teal,
.badge.bg-teal-lt {
    background-color: #e7f5f1 !important;
    color: #277c63 !important;
    border-color: #cde7df !important;
} /* 4.51:1 */

.badge.bg-indigo,
.badge.bg-indigo-lt {
    background-color: #e7eaf5 !important;
    color: #4a62c6 !important;
    border-color: #cdd2e7 !important;
} /* 4.54:1 */

.badge.bg-purple,
.badge.bg-purple-lt {
    background-color: #f3e7f5 !important;
    color: #a23bbb !important;
    border-color: #e2cde7 !important;
} /* 4.53:1 */

.badge.bg-pink,
.badge.bg-pink-lt {
    background-color: #f5e7ec !important;
    color: #b93a67 !important;
    border-color: #e7cdd6 !important;
} /* 4.54:1 */

.badge.bg-yellow,
.badge.bg-yellow-lt {
    background-color: #f5f0e7 !important;
    color: #89682b !important;
    border-color: #e7decd !important;
} /* 4.54:1 */

.badge.bg-lime,
.badge.bg-lime-lt {
    background-color: #f0f5e7 !important;
    color: #577926 !important;
    border-color: #dce7cd !important;
} /* 4.54:1 */

.badge.bg-secondary,
.badge.bg-secondary-lt {
    background-color: #f5ede7 !important;
    color: #726b66 !important;
    border-color: #e7d8cd !important;
} /* 4.53:1 */

.badge.bg-muted,
.badge.bg-muted-lt {
    background-color: #f5ede7 !important;
    color: #726b66 !important;
    border-color: #e7d8cd !important;
} /* 4.53:1 */

.badge.bg-dark,
.badge.bg-dark-lt {
    background-color: #f5efe7 !important;
    color: #716c65 !important;
    border-color: #e7dbcd !important;
} /* 4.56:1 */

/* Dark */

[data-bs-theme=dark] .badge.bg-primary,
[data-bs-theme=dark] .badge.bg-primary-lt {
    background-color: #37231d !important;
    color: #d67259 !important;
    border-color: #624037 !important;
} /* 4.51:1 */

[data-bs-theme=dark] .badge.bg-danger,
[data-bs-theme=dark] .badge.bg-danger-lt {
    background-color: #371d1d !important;
    color: #d96868 !important;
    border-color: #623737 !important;
} /* 4.52:1 */

[data-bs-theme=dark] .badge.bg-red,
[data-bs-theme=dark] .badge.bg-red-lt {
    background-color: #371d1d !important;
    color: #d96868 !important;
    border-color: #623737 !important;
} /* 4.52:1 */

[data-bs-theme=dark] .badge.bg-success,
[data-bs-theme=dark] .badge.bg-success-lt {
    background-color: #1d3721 !important;
    color: #2eaf42 !important;
    border-color: #37623e !important;
} /* 4.52:1 */

[data-bs-theme=dark] .badge.bg-green,
[data-bs-theme=dark] .badge.bg-green-lt {
    background-color: #1d3721 !important;
    color: #2eaf42 !important;
    border-color: #37623e !important;
} /* 4.52:1 */

[data-bs-theme=dark] .badge.bg-warning,
[data-bs-theme=dark] .badge.bg-warning-lt {
    background-color: #37281d !important;
    color: #d07d45 !important;
    border-color: #624837 !important;
} /* 4.52:1 */

[data-bs-theme=dark] .badge.bg-orange,
[data-bs-theme=dark] .badge.bg-orange-lt {
    background-color: #37281d !important;
    color: #d07d45 !important;
    border-color: #624837 !important;
} /* 4.52:1 */

[data-bs-theme=dark] .badge.bg-info,
[data-bs-theme=dark] .badge.bg-info-lt {
    background-color: #1d2b37 !important;
    color: #4d96d2 !important;
    border-color: #374f62 !important;
} /* 4.55:1 */

[data-bs-theme=dark] .badge.bg-azure,
[data-bs-theme=dark] .badge.bg-azure-lt {
    background-color: #1d2b37 !important;
    color: #4d96d2 !important;
    border-color: #374f62 !important;
} /* 4.55:1 */

[data-bs-theme=dark] .badge.bg-blue,
[data-bs-theme=dark] .badge.bg-blue-lt {
    background-color: #1d2937 !important;
    color: #5891d5 !important;
    border-color: #374b62 !important;
} /* 4.51:1 */

[data-bs-theme=dark] .badge.bg-cyan,
[data-bs-theme=dark] .badge.bg-cyan-lt {
    background-color: #1d3337 !important;
    color: #2ea5b8 !important;
    border-color: #375c62 !important;
} /* 4.55:1 */

[data-bs-theme=dark] .badge.bg-teal,
[data-bs-theme=dark] .badge.bg-teal-lt {
    background-color: #1d372f !important;
    color: #2bad86 !important;
    border-color: #376255 !important;
} /* 4.53:1 */

[data-bs-theme=dark] .badge.bg-indigo,
[data-bs-theme=dark] .badge.bg-indigo-lt {
    background-color: #1d2237 !important;
    color: #7085db !important;
    border-color: #373f62 !important;
} /* 4.54:1 */

[data-bs-theme=dark] .badge.bg-purple,
[data-bs-theme=dark] .badge.bg-purple-lt {
    background-color: #321d37 !important;
    color: #bf68d5 !important;
    border-color: #5a3762 !important;
} /* 4.50:1 */

[data-bs-theme=dark] .badge.bg-pink,
[data-bs-theme=dark] .badge.bg-pink-lt {
    background-color: #371d26 !important;
    color: #d9658e !important;
    border-color: #623746 !important;
} /* 4.54:1 */

[data-bs-theme=dark] .badge.bg-yellow,
[data-bs-theme=dark] .badge.bg-yellow-lt {
    background-color: #372e1d !important;
    color: #c08d30 !important;
    border-color: #625337 !important;
} /* 4.52:1 */

[data-bs-theme=dark] .badge.bg-lime,
[data-bs-theme=dark] .badge.bg-lime-lt {
    background-color: #2c371d !important;
    color: #74aa2a !important;
    border-color: #506237 !important;
} /* 4.50:1 */

[data-bs-theme=dark] .badge.bg-secondary,
[data-bs-theme=dark] .badge.bg-secondary-lt {
    background-color: #37281d !important;
    color: #97908c !important;
    border-color: #624937 !important;
} /* 4.50:1 */

[data-bs-theme=dark] .badge.bg-muted,
[data-bs-theme=dark] .badge.bg-muted-lt {
    background-color: #37281d !important;
    color: #97908c !important;
    border-color: #624937 !important;
} /* 4.50:1 */

[data-bs-theme=dark] .badge.bg-dark,
[data-bs-theme=dark] .badge.bg-dark-lt {
    background-color: #372b1d !important;
    color: #98938c !important;
    border-color: #624f37 !important;
} /* 4.51:1 */

.badge.badge-outline {
    background-color: transparent !important;
    border-color: currentColor !important;
}


.modal-content {
    border: none;
    box-shadow: var(--tblr-box-shadow-lg);
}

.modal-blur {
    margin-top: 0;
    background-color: rgba(12, 10, 9, 0.4);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    position: fixed;
}

.dropdown-menu {
    border-color: var(--tblr-border-color-translucent);
    box-shadow: var(--tblr-box-shadow);
}

a.list-group-item {
    transition: color var(--pz-duration) var(--pz-ease),
                background-color var(--pz-duration) var(--pz-ease);
}

a.list-group-item.active {
    color: var(--tblr-link-color) !important;
    background-color: transparent !important;
}

a.list-group-item:hover {
    color: var(--tblr-link-color);
}

a.nav-link {
    transition: color var(--pz-duration) var(--pz-ease);
}

a.nav-link:hover {
    color: var(--tblr-link-color) !important;
}

a.nav-link.active,
a.nav-link.active svg {
    color: var(--tblr-link-color) !important;
}

.nav-link-icon svg {
    color: var(--tblr-muted);
}

.icon-muted svg {
    color: var(--tblr-muted);
}

.icon-text svg {
    width: 1.1rem;
    height: 1.1rem;
}

/* Disable arrows and spinners on number inputs. */
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

input[type=number] {
    -moz-appearance: textfield;
}

/* ------------------------------------------------------------------ *
 * 7. Third-party widgets
 *
 * None of these know about Tabler's theme, so each one is re-pointed at the
 * shared tokens. That is what makes them follow dark mode.
 * ------------------------------------------------------------------ */

/* react-select takes its palette from the `theme` prop in
 * assets/components/form/Select.js, which now feeds it these same variables.
 * Only the focus ring is left to CSS, because react-select hardcodes it. */
.react-select__control--is-focused {
    border-color: var(--pz-focus-ring) !important;
    box-shadow: var(--pz-focus-shadow) !important;
}

.dz-message svg {
    width: 8rem;
    height: 8rem;
    stroke-width: 0.015rem;
}

.dz-button {
    background: none;
    box-shadow: none;
    border: none;
}

/*** Quill ***/

.quill .ql-toolbar {
    border-radius: var(--tblr-border-radius) var(--tblr-border-radius) 0 0;
    border-color: var(--tblr-border-color);
}

.quill .ql-container {
    border-radius: 0 0 var(--tblr-border-radius) var(--tblr-border-radius);
    border-color: var(--tblr-border-color);
}

.ql-snow a {
    color: var(--tblr-link-color);
}

.ql-editor {
    min-height: 8rem;
}

.ql-snow.ql-toolbar button:hover,
.ql-snow .ql-toolbar button:hover,
.ql-snow.ql-toolbar button:focus,
.ql-snow .ql-toolbar button:focus,
.ql-snow.ql-toolbar button.ql-active,
.ql-snow .ql-toolbar button.ql-active,
.ql-snow.ql-toolbar .ql-picker-label:hover,
.ql-snow .ql-toolbar .ql-picker-label:hover,
.ql-snow.ql-toolbar .ql-picker-label.ql-active,
.ql-snow .ql-toolbar .ql-picker-label.ql-active,
.ql-snow.ql-toolbar .ql-picker-item:hover,
.ql-snow .ql-toolbar .ql-picker-item:hover,
.ql-snow.ql-toolbar .ql-picker-item.ql-selected,
.ql-snow .ql-toolbar .ql-picker-item.ql-selected {
    color: var(--tblr-primary);
}

.ql-snow.ql-toolbar button:hover .ql-fill,
.ql-snow .ql-toolbar button:hover .ql-fill,
.ql-snow.ql-toolbar button:focus .ql-fill,
.ql-snow .ql-toolbar button:focus .ql-fill,
.ql-snow.ql-toolbar button.ql-active .ql-fill,
.ql-snow .ql-toolbar button.ql-active .ql-fill,
.ql-snow.ql-toolbar .ql-picker-label:hover .ql-fill,
.ql-snow .ql-toolbar .ql-picker-label:hover .ql-fill,
.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-fill,
.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-fill,
.ql-snow.ql-toolbar .ql-picker-item:hover .ql-fill,
.ql-snow .ql-toolbar .ql-picker-item:hover .ql-fill,
.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-fill,
.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-fill,
.ql-snow.ql-toolbar button:hover .ql-stroke.ql-fill,
.ql-snow .ql-toolbar button:hover .ql-stroke.ql-fill,
.ql-snow.ql-toolbar button:focus .ql-stroke.ql-fill,
.ql-snow .ql-toolbar button:focus .ql-stroke.ql-fill,
.ql-snow.ql-toolbar button.ql-active .ql-stroke.ql-fill,
.ql-snow .ql-toolbar button.ql-active .ql-stroke.ql-fill,
.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill,
.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill,
.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill,
.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill,
.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill,
.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill,
.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill,
.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill {
    fill: var(--tblr-primary);
}

.ql-snow.ql-toolbar button:hover .ql-stroke,
.ql-snow .ql-toolbar button:hover .ql-stroke,
.ql-snow.ql-toolbar button:focus .ql-stroke,
.ql-snow .ql-toolbar button:focus .ql-stroke,
.ql-snow.ql-toolbar button.ql-active .ql-stroke,
.ql-snow .ql-toolbar button.ql-active .ql-stroke,
.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke,
.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke,
.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke,
.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke,
.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke,
.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke,
.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke,
.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke,
.ql-snow.ql-toolbar button:hover .ql-stroke-miter,
.ql-snow .ql-toolbar button:hover .ql-stroke-miter,
.ql-snow.ql-toolbar button:focus .ql-stroke-miter,
.ql-snow .ql-toolbar button:focus .ql-stroke-miter,
.ql-snow.ql-toolbar button.ql-active .ql-stroke-miter,
.ql-snow .ql-toolbar button.ql-active .ql-stroke-miter,
.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke-miter,
.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke-miter,
.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter,
.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter,
.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke-miter,
.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke-miter,
.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter,
.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter {
    stroke: var(--tblr-primary);
}

/* Quill's snow theme is light only: it paints its icons with a hardcoded #444
 * and its pickers with a white background. */
[data-bs-theme=dark] .quill .ql-toolbar,
[data-bs-theme=dark] .quill .ql-container {
    background-color: var(--tblr-bg-surface);
}

[data-bs-theme=dark] .ql-snow .ql-stroke,
[data-bs-theme=dark] .ql-snow .ql-stroke-miter {
    stroke: var(--tblr-body-color);
}

[data-bs-theme=dark] .ql-snow .ql-fill,
[data-bs-theme=dark] .ql-snow .ql-stroke.ql-fill {
    fill: var(--tblr-body-color);
}

[data-bs-theme=dark] .ql-snow .ql-picker,
[data-bs-theme=dark] .ql-snow .ql-picker-label,
[data-bs-theme=dark] .ql-editor.ql-blank::before {
    color: var(--tblr-body-color);
}

[data-bs-theme=dark] .ql-snow .ql-picker-options {
    background-color: var(--tblr-bg-surface);
    border-color: var(--tblr-border-color);
}

[data-bs-theme=dark] .ql-snow .ql-tooltip {
    background-color: var(--tblr-bg-surface);
    border-color: var(--tblr-border-color);
    box-shadow: var(--tblr-box-shadow);
    color: var(--tblr-body-color);
}

[data-bs-theme=dark] .ql-snow .ql-tooltip input[type=text] {
    background-color: var(--tblr-body-bg);
    border-color: var(--pz-border-strong);
    color: var(--tblr-body-color);
}

/*** React Tabs ***/

.react-tabs__tab-list {
    border-bottom: none !important;
    margin: 0 20px !important;
    white-space: pre !important;
    overflow-x: auto !important;
    overflow-y: hidden !important;
    position: relative;
    top: 1px;
    scrollbar-width: thin;
}

.react-tabs__tab {
    padding: 10px 20px;
    margin-right: 10px;
    border-radius: var(--tblr-border-radius) var(--tblr-border-radius) 0 0;
    color: var(--tblr-muted);
    transition: background-color var(--pz-duration) var(--pz-ease),
                border-color var(--pz-duration) var(--pz-ease),
                color var(--pz-duration) var(--pz-ease);
}

.react-tabs__tab--selected {
    background-color: var(--tblr-bg-surface);
    border-color: var(--tblr-border-color);
    color: var(--tblr-primary-text-emphasis);
    font-weight: 500;
    z-index: 1;
}

.react-tabs__tab:hover:not(.react-tabs__tab--selected) {
    background-color: var(--pz-subtle-bg);
    border-color: var(--tblr-border-color);
    border-radius: var(--tblr-border-radius) var(--tblr-border-radius) 0 0;
    color: var(--tblr-body-color);
}

/* ------------------------------------------------------------------ *
 * 8. Application classes
 * ------------------------------------------------------------------ */

.facility-card {
    transition: border-color var(--pz-duration) var(--pz-ease),
                box-shadow var(--pz-duration) var(--pz-ease),
                transform var(--pz-duration) var(--pz-ease);
    color: var(--tblr-body-color) !important;
}

.facility-card:hover {
    border: 1px solid var(--tblr-primary);
    box-shadow: var(--tblr-box-shadow);
    transform: translateY(-2px);
    cursor: pointer;
}

/* Was a 300 character descendant chain that broke the moment any wrapper in
 * between changed. The class alone is enough. */
.facility-logo svg {
    width: 200px;
    height: 200px;
    stroke-width: 0.5px;
}

.job-categories span.form-selectgroup-label {
    color: var(--tblr-body-color) !important;
    transition: color var(--pz-duration) var(--pz-ease),
                border-color var(--pz-duration) var(--pz-ease),
                background-color var(--pz-duration) var(--pz-ease);
}

.job-categories span.form-selectgroup-label:hover {
    color: var(--tblr-link-color) !important;
    border-color: var(--tblr-link-color) !important;
    background-color: var(--tblr-primary-bg-subtle);
}

.scroll-offset {
    scroll-margin-top: 120px;
}

.checkbox-list-item {
    transition: background-color var(--pz-duration) var(--pz-ease),
                border-color var(--pz-duration) var(--pz-ease);
}

.checkbox-list-item:hover {
    border: 1px solid var(--tblr-border-color) !important;
    background-color: var(--pz-subtle-bg) !important;
}

.isInvalid {
    color: var(--tblr-danger) !important;
}

.no-hover-underline:hover {
    text-decoration: none;
}

.contractDateIcon {
    display: flex;
    justify-content: center;
}

.contractDateIcon svg {
    width: 120px;
    height: 120px;
    stroke-width: 0.75;
}

.text-gray {
    color: var(--tblr-muted);
}

/* Status tints. The border carries the signal, the fill stays quiet, so the
 * same rule reads correctly on either background. */
.bg-accepted {
    background-color: var(--tblr-success-bg-subtle);
    border-color: var(--tblr-success);
}

.bg-accepted-lt {
    background-color: var(--tblr-success-bg-subtle);
    border-color: var(--tblr-success-border-subtle);
}

.bg-rejected {
    background-color: var(--tblr-danger-bg-subtle);
    border-color: var(--tblr-danger);
}

.accordion-table {
    background-color: var(--tblr-bg-surface);
    border-top: 1px solid var(--tblr-border-color-translucent);
    border-radius: var(--tblr-border-radius);
}

.font-weight-regular {
    font-weight: var(--tblr-body-font-weight) !important;
}

.cursor-pointer:hover {
    cursor: pointer;
}

.accordion-item {
    transition: background-color var(--pz-duration) var(--pz-ease),
                border-color var(--pz-duration) var(--pz-ease);
}

.no-pointer-events {
    pointer-events: none;
}

.transcription::before,
.transcription::after {
    display: block;
    font-weight: bold;
    line-height: 0;
    opacity: 0.4;
    position: absolute;
    transition: opacity 0.5s var(--pz-ease);
    z-index: -1;
}

.transcription::before {
    content: "\201C";
    color: var(--tblr-gray-300);
    font-size: 7rem;
    top: 48px;
    left: 2px;
}

.transcription:hover::before {
    opacity: 1;
}

.transcription::after {
    content: "\201D";
    color: var(--tblr-gray-300);
    font-size: 4.5rem;
    bottom: 5px;
    right: 10px;
}

.transcription {
    background-color: var(--pz-subtle-bg);
    border: 1px solid var(--tblr-border-color-translucent);
    border-radius: var(--tblr-border-radius);
    cursor: pointer;
    font-family: Georgia, "Times New Roman", serif;
    font-style: italic;
    padding: 1rem;
    white-space: normal;
    position: relative;
    z-index: 1;
}

[data-bs-theme=dark] .transcription::before,
[data-bs-theme=dark] .transcription::after {
    color: var(--tblr-gray-600);
}

.transcription.collapsed {
    height: 50px;
    overflow: hidden;
    padding-right: 50px;
    text-overflow: ellipsis;
}

.transcription.expanded {
    height: auto;
    white-space: normal !important;
}

/* The admin dashboard used to be a 400px column of right-aligned numbers
 * inside 6rem of padding, which left most of the screen empty and gave the
 * figures no visual weight. It is a responsive grid of tiles now. */

/* The dashboard is the first thing an admin sees, so it gets more air than the
 * dense table screens behind it. */
.admin-overview.card-body {
    padding: 1.75rem 2rem 2rem;
}

.admin-overview .stat-section-title {
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--tblr-muted);
    margin-bottom: 1rem;
}

.stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 1.25rem;
}

/* Inset rather than raised: these sit on a card, so a white tile on a white
 * surface would disappear. The quiet fill reads as a well instead. */
.stat-tile {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.125rem;
    width: 100%;
    padding: 1.375rem 1.5rem;
    text-align: left;
    background-color: var(--pz-subtle-bg);
    border: 1px solid var(--tblr-border-color-translucent);
    border-radius: var(--tblr-border-radius-lg);
    color: inherit;
    cursor: pointer;
    transition: background-color var(--pz-duration) var(--pz-ease),
                border-color var(--pz-duration) var(--pz-ease),
                transform var(--pz-duration) var(--pz-ease);
}

.stat-tile:hover {
    background-color: var(--tblr-primary-bg-subtle);
    border-color: var(--tblr-primary);
    transform: translateY(-2px);
}

.stat-tile-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    margin-bottom: 0.625rem;
    border-radius: var(--tblr-border-radius);
    background-color: var(--tblr-primary-bg-subtle);
    color: var(--tblr-primary-text-emphasis);
}

.stat-tile-icon svg {
    width: 1.25rem;
    height: 1.25rem;
}

/* Lining figures at a large size need to sit on the same baseline grid across
 * tiles, so the count is tabular and the tracking is pulled in. */
.stat-tile-value {
    font-size: 1.875rem;
    font-weight: 600;
    line-height: 1.15;
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
    color: var(--tblr-emphasis-color);
}

.stat-tile-label {
    font-size: 0.8125rem;
    color: var(--tblr-muted);
}

/* Skeleton, so the grid does not collapse and reflow when the counts land. */
.stat-tile-loading {
    cursor: default;
    pointer-events: none;
}

.stat-tile-loading .stat-tile-icon,
.stat-tile-loading .stat-tile-value,
.stat-tile-loading .stat-tile-label {
    background-color: var(--pz-subtle-bg);
    border-radius: var(--tblr-border-radius-sm);
    color: transparent;
}

.stat-tile-loading .stat-tile-value {
    width: 4.5rem;
    height: 1.875rem;
    margin-bottom: 0.25rem;
}

.stat-tile-loading .stat-tile-label {
    width: 7rem;
    height: 0.8125rem;
}

/* ---- Weekly activity chart ---------------------------------------- *
 * One series, so no legend: the section heading names what is plotted. The
 * bars are divs rather than SVG because they have to reflow with the card, and
 * a viewBox would scale the axis text along with the geometry.
 * ------------------------------------------------------------------- */
.activity-chart-plot {
    position: relative;
    height: 180px;
}

/* Solid hairlines one step off the surface. Dashed rules read as a threshold
 * or a projection when they are only a grid. */
.activity-chart-gridline {
    position: absolute;
    left: 3rem;
    right: 0;
    border-top: 1px solid var(--tblr-border-color-translucent);
    pointer-events: none;
}

.activity-chart-tick {
    position: absolute;
    right: calc(100% + 0.625rem);
    transform: translateY(-50%);
    font-size: 0.6875rem;
    font-variant-numeric: tabular-nums;
    color: var(--tblr-muted);
}

.activity-chart-bars,
.activity-chart-axis {
    display: flex;
    align-items: flex-end;
    gap: 2px;
    margin-left: 3rem;
    height: 100%;
}

/* The slot is the hit target, not the bar. A quiet week is a two-pixel mark,
 * and hovering it should not require landing on those two pixels. */
.activity-chart-slot {
    position: relative;
    display: flex;
    flex: 1 1 0;
    align-items: flex-end;
    justify-content: center;
    height: 100%;
    cursor: default;
}

.activity-chart-bar {
    width: 100%;
    max-width: 24px;
    min-height: 2px;
    background-color: var(--pz-chart-series);
    /* Rounded at the data end, square where it meets the baseline. */
    border-radius: 4px 4px 0 0;
    transition: background-color var(--pz-duration) var(--pz-ease);
}

.activity-chart-bar.is-empty {
    min-height: 0;
}

.activity-chart-bar.is-hovered {
    background-color: var(--pz-chart-series-hover);
}

/* Only the busiest week carries a number. A value on all twelve is noise, and
 * the axis plus the tooltip already reach the rest. */
.activity-chart-peak {
    position: absolute;
    bottom: 100%;
    margin-bottom: 0.25rem;
    font-size: 0.6875rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    color: var(--tblr-body-color);
}

/* bottom is set per hover from the bar's own height, so the tooltip rides the
 * cap of the column it describes rather than floating above the whole plot. */
.activity-chart-tooltip {
    position: absolute;
    display: flex;
    flex-direction: column;
    padding: 0.375rem 0.625rem;
    transform: translateX(-50%);
    white-space: nowrap;
    pointer-events: none;
    background-color: var(--tblr-bg-surface);
    border: 1px solid var(--tblr-border-color);
    border-radius: var(--tblr-border-radius);
    box-shadow: var(--tblr-box-shadow-sm);
    z-index: 2;
}

.activity-chart-tooltip-label {
    font-size: 0.6875rem;
    color: var(--tblr-muted);
}

.activity-chart-tooltip-value {
    font-size: 0.875rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--tblr-emphasis-color);
}

/* Height comes from the labels, so the axis band can never be cut off by a
 * fixed plot height the way a nested-scroll card is. */
.activity-chart-axis {
    height: auto;
    padding-top: 0.5rem;
}

.activity-chart-axis-label {
    flex: 1 1 0;
    font-size: 0.6875rem;
    text-align: center;
    font-variant-numeric: tabular-nums;
    color: var(--tblr-muted);
}

.activity-chart-summary {
    margin-top: 0.75rem;
    margin-left: 3rem;
    font-size: 0.75rem;
    color: var(--tblr-muted);
}

/* ---- Bar breakdown ------------------------------------------------ *
 * Shared by the nationality list, the invitation funnel and the file actions.
 * Nominal categories, so every bar is the same colour: shading them by size
 * would encode the length a second time and spend the only free channel on
 * something the bar already says.
 * ------------------------------------------------------------------- */
.bar-breakdown {
    --bar-breakdown-label: 7rem;

    display: flex;
    flex-direction: column;
    gap: 0.875rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.bar-breakdown-row {
    display: grid;
    grid-template-columns: var(--bar-breakdown-label) 1fr auto;
    align-items: center;
    gap: 0.75rem;
}

/* A long nationality truncates rather than wrapping, which would break the
 * row rhythm. The full name stays in the title attribute. */
.bar-breakdown-label {
    overflow: hidden;
    font-size: 0.8125rem;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--tblr-body-color);
}

.bar-breakdown-track {
    height: 8px;
    background-color: var(--pz-subtle-bg);
    border-radius: 4px;
}

.bar-breakdown-bar {
    display: block;
    height: 100%;
    background-color: var(--pz-chart-series);
    border-radius: 4px;
}

/* Aligned in a column, so these are the one place tabular figures belong. */
.bar-breakdown-value {
    min-width: 3rem;
    font-size: 0.8125rem;
    font-weight: 600;
    text-align: right;
    font-variant-numeric: tabular-nums;
    color: var(--tblr-emphasis-color);
}

/* ---- Delivery meter ------------------------------------------------ *
 * Two classes, so the number leads and the bar only supports it. A pie of two
 * slices would be the wrong form outright.
 * ------------------------------------------------------------------- */
/* Capped, so a 93% fill does not stretch into a metre of bar on a wide screen
 * and lose the proportion it is meant to show. */
.delivery-meter {
    max-width: 28rem;
}

.delivery-meter-value {
    font-size: 2.25rem;
    font-weight: 600;
    line-height: 1.1;
    letter-spacing: -0.02em;
    color: var(--tblr-emphasis-color);
}

.delivery-meter-caption {
    margin-bottom: 1rem;
    font-size: 0.8125rem;
    color: var(--tblr-muted);
}

/* The track is a lighter step of the same idea rather than a neutral well, so
 * the shortfall reads as the rest of the bar and not as empty space. */
.delivery-meter-track {
    height: 10px;
    background-color: var(--tblr-danger);
    border-radius: 5px;
    overflow: hidden;
}

.delivery-meter-fill {
    height: 100%;
    background-color: var(--tblr-success);
    /* Square on the right, so the boundary between the two states is a clean
     * edge instead of a curve that reads as the end of the bar. */
    border-radius: 5px 0 0 5px;
}

.delivery-meter-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 0.375rem 1.25rem;
    margin: 0.75rem 0 0;
    padding: 0;
    list-style: none;
    font-size: 0.8125rem;
    color: var(--tblr-muted);
}

.delivery-meter-legend li {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

/* The swatch carries the colour; the words beside it carry the meaning, so
 * the state never rests on colour alone. */
.delivery-meter-swatch {
    width: 10px;
    height: 10px;
    border-radius: 3px;
}

.delivery-meter-swatch.is-sent {
    background-color: var(--tblr-success);
}

.delivery-meter-swatch.is-failed {
    background-color: var(--tblr-danger);
}

/* card-table is built to sit flush against the edges of a card, so its row
 * rules run the full width of their container. Inside a rounded box that means
 * every line overshoots the corner radius and leaves a visible stub. Clipping
 * the wrapper is what makes the rules stop at the curve. */
.admin-overview .stat-table {
    border: 1px solid var(--tblr-border-color-translucent);
    border-radius: var(--tblr-border-radius-lg);
    overflow: hidden;
}

.admin-overview .stat-table .table {
    margin-bottom: 0;
}

.admin-overview .table > :not(caption) > * > td {
    padding-top: 0.25rem !important;
    padding-bottom: 0.25rem !important;
}

/* Build stamp under the dashboard. This was a hardcoded #f8f9fa strip, which
 * stayed a bright white band in dark mode. */
/* Rendered as the card's .card-footer, so Tabler already supplies the padding
 * and the top rule. Adding a border and a radius of its own drew a second box
 * inside the card whose fill overhung the rounded bottom corners. */
.app-version-bar {
    text-align: center;
    background-color: var(--pz-subtle-bg);
    color: var(--tblr-muted);
    font-family: var(--tblr-font-monospace);
    font-size: 11px;
}

.debug {
    background-color: var(--pz-subtle-bg);
    border-radius: var(--tblr-border-radius-sm);
    font-family: var(--tblr-font-monospace);
    font-size: 10px;
    padding: 0 5px;
    position: relative;
    top: 1px;
    vertical-align: middle;
}

/* ---- Support page -------------------------------------------------- *
 * The page somebody opens when something is already broken, so the prose sets
 * a comfortable measure and the diagnostics are structured enough to be
 * pasted into a ticket rather than described in prose.
 * ------------------------------------------------------------------- */

/* The one page here that gets read rather than scanned, so it sits further
 * inside its card than a table or a form would. */
.support-page {
    padding: 2rem;
}

@media (min-width: 992px) {
    .support-page {
        padding: 2.5rem;
    }
}

/* Long lines are the main thing that made this page tiring to read. 76ch is at
 * the top of the comfortable range, which fills the card on a wide screen
 * without letting a paragraph run the full width of a desktop. */
.support-prose {
    max-width: 76ch;
}

.support-prose h2 {
    margin-bottom: 0.75rem;
}

.support-prose h3 {
    margin-top: 2rem;
    font-size: 1rem;
}

.support-prose p {
    color: var(--tblr-body-color);
}

.support-lead {
    font-size: 1.0625rem;
    line-height: 1.6;
}

.support-card-title {
    font-size: 1rem;
    margin-bottom: 0.5rem;
}

/* The sidebar is no longer a stack of separate cards, so the rule takes over
 * the job the gap between them used to do. Only once the columns are actually
 * side by side: stacked on a phone a left border would point at nothing. */
@media (min-width: 992px) {
    .support-aside {
        padding-left: 2rem;
        border-left: 1px solid var(--tblr-border-color-translucent);
    }
}

.support-section + .support-section {
    margin-top: 2rem;
}

.support-contacts {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

/* A whole row is the hit target rather than the link text, which on a phone is
 * the difference between reaching support and mistyping a phone number. */
.support-contact {
    display: flex;
    align-items: center;
    gap: 0.875rem;
    padding: 0.75rem 0.875rem;
    text-decoration: none;
    background-color: var(--pz-subtle-bg);
    border: 1px solid var(--tblr-border-color-translucent);
    border-radius: var(--tblr-border-radius);
    color: inherit;
    transition: border-color var(--pz-duration) var(--pz-ease),
                background-color var(--pz-duration) var(--pz-ease);
}

.support-contact:hover {
    border-color: var(--tblr-primary);
    color: inherit;
    text-decoration: none;
}

.support-contact-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 2.25rem;
    height: 2.25rem;
    background-color: var(--tblr-primary-lt);
    border-radius: var(--tblr-border-radius);
    color: var(--tblr-primary-text-emphasis);
}

.support-contact-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.support-contact-label {
    font-size: 0.75rem;
    color: var(--tblr-muted);
}

/* A long address shortens rather than pushing the card wider. */
.support-contact-value {
    overflow: hidden;
    font-weight: 500;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.support-diagnostics-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 0.5rem;
}

.support-diagnostics-head .btn {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    flex: 0 0 auto;
}

.support-diagnostics {
    display: grid;
    grid-template-columns: minmax(5.5rem, auto) 1fr;
    gap: 0.5rem 1rem;
    margin: 0;
    font-size: 0.8125rem;
}

.support-diagnostics dt {
    font-weight: 400;
    color: var(--tblr-muted);
}

/* The user agent is one long unbroken token, so it has to be allowed to break
 * anywhere or it forces the whole card wider than its column. */
.support-diagnostics dd {
    margin: 0;
    overflow-wrap: anywhere;
}

.support-diagnostics dd.is-mono {
    font-family: var(--tblr-font-monospace);
    font-size: 0.6875rem;
    line-height: 1.5;
    color: var(--tblr-muted);
}

/* ------------------------------------------------------------------ *
 * 9. Symfony dump
 * ------------------------------------------------------------------ */

.sf-dump {
    background-color: var(--tblr-bg-surface) !important;
    color: var(--tblr-body-color) !important;
    margin-bottom: 0 !important;
    outline: none !important;
    padding: 25px !important;
    z-index: 1000 !important;
}

.sf-dump-default {
    background-color: var(--pz-subtle-bg) !important;
    border-radius: var(--tblr-border-radius-sm);
}

.sf-dump-public {
    color: #268f36 !important;
}

.sf-dump-protected {
    color: #d39e00 !important;
}

.sf-dump-private {
    color: var(--tblr-muted) !important;
}

.sf-dump-note {
    color: var(--tblr-primary-text-emphasis) !important;
}

.sf-dump-key {
    color: #0d7685 !important;
}

.sf-dump-str {
    color: #2f9e6e !important;
}

.sf-dump-ellipsis {
    max-width: unset !important;
}

.sf-dump-toggle {
    position: relative;
    top: -1px;
    left: 1px;
}

[data-bs-theme=dark] .sf-dump-public {
    color: #6fcf7f !important;
}

[data-bs-theme=dark] .sf-dump-protected {
    color: #e8c15a !important;
}

[data-bs-theme=dark] .sf-dump-key {
    color: #5cc3d6 !important;
}

[data-bs-theme=dark] .sf-dump-str {
    color: #6fd6a5 !important;
}

