/* =============================================================================
   NoExcel — theme overrides on top of KeenThemes Craft.

   Layered as:
     1. Tokens          — brand colour + the semantic aliases Craft reads
     2. Typography      — Inter (LTR) / Noto Nastaliq Urdu (RTL)
     3. Layout          — aside shell
     4. Navigation      — sidebar menu, section labels
     5. Surfaces        — cards
     6. Data            — tables, numerals
     7. Forms           — controls, sticky action bar
     8. Feedback        — empty states, focus, motion

   Rules: no literal hex outside the token block (§1) — everything else reads a
   variable so dark mode inverts for free. Logical properties only
   (inline-start/end, never left/right) — the Urdu locale is RTL.
   ============================================================================= */

/* -----------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */

:root {
    --brand-primary-rgb: 53, 104, 221;
    --bs-primary: #3568dd;
    --bs-primary-active: #2d59bf;
    --bs-primary-hover: #4b79e3;
    --bs-text-primary: #3568dd;
    --bs-menu-link-color-hover: #3568dd;
    --bs-menu-link-color-active: #2d59bf;
    --bs-component-active-bg: #3568dd;
    --bs-primary-light: #e1e9fb;
    --bs-scrolltop-bg-color: #3568dd;
    --bs-scrolltop-bg-color-hover: #2d59bf;
    --bs-component-hover-color: #3568dd;
    --bs-link-color: #3568dd;
    --bs-link-hover-color: #2d59bf;
    --bs-focus-ring-color: rgba(var(--brand-primary-rgb), 0.25);

    /* Borders. One hue, three intensities — hairline separates, strong frames,
       focus signals. Low-alpha so an edge is findable without being loud. */
    --nx-border-hairline: rgba(0, 0, 0, 0.06);
    --nx-border: rgba(0, 0, 0, 0.1);
    --nx-border-strong: rgba(0, 0, 0, 0.16);

    /* Elevation. Borders-first theme, so a card lifts with a 1px ring plus two
       whisper-quiet depths rather than a drop shadow. */
    --nx-shadow-card:
        0 0 0 1px var(--nx-border-hairline), 0 1px 2px -1px rgba(0, 0, 0, 0.06),
        0 2px 6px rgba(0, 0, 0, 0.03);
    --nx-shadow-card-hover:
        0 0 0 1px rgba(var(--brand-primary-rgb), 0.25),
        0 4px 10px -2px rgba(0, 0, 0, 0.08), 0 10px 24px rgba(0, 0, 0, 0.05);

    /* Radius scale — inputs/badges, cards and overlays. */
    --nx-radius-sm: 0.475rem;
    --nx-radius-lg: 0.9rem;

    /* Motion. ease-out only; ease-in stalls the frame the user is watching. */
    --nx-ease: cubic-bezier(0.23, 1, 0.32, 1);
    --nx-duration-fast: 120ms;
    --nx-duration: 180ms;
}

/* Dark mode: shadows barely read on dark surfaces, so elevation collapses to a
   brighter ring and the border hues invert. */
[data-bs-theme="dark"] {
    --nx-border-hairline: rgba(255, 255, 255, 0.06);
    --nx-border: rgba(255, 255, 255, 0.1);
    --nx-border-strong: rgba(255, 255, 255, 0.18);
    --nx-shadow-card: 0 0 0 1px rgba(255, 255, 255, 0.07);
    --nx-shadow-card-hover: 0 0 0 1px rgba(var(--brand-primary-rgb), 0.5);
    --bs-primary-light: rgba(var(--brand-primary-rgb), 0.16);

    /* The brand blue is mixed for a white page and does not survive the move to a
       dark one: #3568dd reads 3.57:1 against the card (#15171C) and 3.78:1 against
       the page (#0F1014), so every link and every text-primary label in the app
       failed WCAG AA for body text in dark mode. #6a92e8 is the same hue lifted
       until it clears — 5.88:1 and 6.24:1 respectively.

       --bs-primary itself deliberately stays #3568dd: it paints filled surfaces,
       where the pairing that matters is white-on-brand, and that is 5.03:1 in both
       modes. Lightening it would weaken the buttons to fix the links. */
    --bs-link-color: #6a92e8;
    --bs-link-hover-color: #8aabee;
    --bs-text-primary: #6a92e8;
    --bs-component-hover-color: #6a92e8;
    --bs-menu-link-color-hover: #6a92e8;
    --bs-menu-link-color-active: #8aabee;
}

/* -----------------------------------------------------------------------------
   2. Typography
   -------------------------------------------------------------------------- */

@font-face {
    font-family: "Noto Nastaliq Urdu";
    src: url("/preCompiledAssets/fonts/Noto_Nastaliq_Urdu/static/NotoNastaliqUrdu-Regular.ttf")
        format("truetype");
    font-display: swap;
}

body {
    font-family: "Inter";
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* Headings tighten as they grow — default tracking on a 28px heading reads like
   a document, not an interface. */
h1,
h2,
h3,
.h1,
.h2,
.h3 {
    letter-spacing: -0.02em;
    text-wrap: balance;
}

p,
.text-muted,
.form-text {
    text-wrap: pretty;
}

html[dir="rtl"] body,
html[dir="rtl"] input,
html[dir="rtl"] button,
html[dir="rtl"] textarea,
html[dir="rtl"] select {
    font-family: "Noto Nastaliq Urdu", "Inter", sans-serif;
}

/* Nastaliq has tall ascenders/descenders and needs the extra leading, and the
   negative tracking above is wrong for it. */
html[dir="rtl"] body {
    line-height: 1.8;
}

html[dir="rtl"] h1,
html[dir="rtl"] h2,
html[dir="rtl"] h3,
html[dir="rtl"] .h1,
html[dir="rtl"] .h2,
html[dir="rtl"] .h3 {
    letter-spacing: normal;
    line-height: 1.9;
}

html[dir="rtl"] .card-title,
html[dir="rtl"] .carousel-item,
html[dir="rtl"] .form-control,
html[dir="rtl"] .form-select,
html[dir="rtl"] .btn,
html[dir="rtl"] .menu-title,
html[dir="rtl"] .badge {
    line-height: 1.8;
}

html[dir="rtl"] .card-title,
html[dir="rtl"] .carousel-item {
    padding-bottom: 0.15em;
}

/* Directional glyphs must mirror in RTL — neither Bootstrap Icons nor Font
   Awesome flip themselves, so a "back" arrow points forward in Urdu. */
html[dir="rtl"] .bi-chevron-right,
html[dir="rtl"] .bi-chevron-left,
html[dir="rtl"] .bi-arrow-right,
html[dir="rtl"] .bi-arrow-left,
html[dir="rtl"] .bi-box-arrow-up-right,
html[dir="rtl"] .fa-arrow-left,
html[dir="rtl"] .fa-arrow-right {
    display: inline-block;
    transform: scaleX(-1);
}

/* -----------------------------------------------------------------------------
   3. Layout — page shell
   -------------------------------------------------------------------------- */

/* The aside is a column: logo (fixed) + menu (scrolls). Expressed with flex
   rather than a hardcoded viewport calculation so it survives a wrapped logo or
   an impersonation bar. */
.aside {
    display: flex;
    flex-direction: column;
    border-inline-end: 1px solid var(--nx-border-hairline);
}

.aside-menu {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

.aside-menu .menu {
    flex: 1 1 auto;
    min-height: 0;
    margin: 0;
    padding-block: 0.5rem 1rem;
}

/* Primary nav at the top, account/support pinned to the bottom, the gap between
   them absorbing the slack. */
.aside-menu .menu .hover-scroll-y {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.aside-menu .menu .hover-scroll-y > .menu-section:last-child {
    margin-block-start: auto;
    padding-block-start: 0.75rem;
    border-block-start: 1px solid var(--nx-border-hairline);
}

.aside-menu .menu .hover-scroll-y::-webkit-scrollbar {
    width: 6px;
}

.aside-menu .menu .hover-scroll-y::-webkit-scrollbar-track {
    background: transparent;
}

.aside-menu .menu .hover-scroll-y::-webkit-scrollbar-thumb {
    background: var(--nx-border);
    border-radius: 3px;
}

.aside-menu .menu .hover-scroll-y:hover::-webkit-scrollbar-thumb {
    background: var(--nx-border-strong);
}

.header {
    border-block-end: 1px solid var(--nx-border-hairline);
}

/* Craft ships min-w-1px … min-w-1000px but no min-w-0, so every `min-w-0` in the markup (the
   sticky form bar, stat_tile, the product form) was a silent no-op: a flex item kept its default
   `min-width: auto`, could not shrink below its longest unbroken word, and `.text-truncate` inside
   it never kicked in — a 255-character product name with no spaces pushed the bar off-screen
   (#154). Named like Craft's own utility on purpose, so markup that assumes it exists keeps working. */
.min-w-0 {
    min-width: 0 !important;
}

/* Keyboard users get to the table/form without tabbing the whole sidebar. */
.nx-skip-link {
    position: absolute;
    inset-inline-start: 1rem;
    top: -100px;
    z-index: 200;
    padding: 0.65rem 1rem;
    border-radius: var(--nx-radius-sm);
    background-color: var(--bs-primary);
    color: var(--bs-light);
    font-weight: 600;
    transition: top var(--nx-duration) var(--nx-ease);
}

.nx-skip-link:focus {
    top: 1rem;
    color: var(--bs-light);
}

/* -----------------------------------------------------------------------------
   4. Navigation — sidebar
   -------------------------------------------------------------------------- */

/* Section label: the theme ships the hook but Craft leaves it unstyled at this
   size. Groups the nav into Business / Administration instead of one long list. */
.aside-menu .menu-section-label {
    padding: 0.75rem 0.85rem 0.35rem;
    font-size: 0.7rem;
    font-weight: 600;
    line-height: 1.4;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--bs-gray-500);
}

html[dir="rtl"] .aside-menu .menu-section-label {
    letter-spacing: normal;
    text-transform: none;
    font-size: 0.78rem;
}

.aside-menu .menu-link {
    transition:
        background-color var(--nx-duration-fast) var(--nx-ease),
        color var(--nx-duration-fast) var(--nx-ease);
}

/* The collapsible-group toggle is a real <button> so it is keyboard-operable —
   KTMenu binds `[data-kt-menu-trigger] > .menu-link` regardless of the element,
   and Craft's <span> version cannot take focus. Strip the native button chrome
   so it renders identically to a plain menu link. */
.aside-menu button.menu-link {
    width: 100%;
    margin: 0;
    border: 0;
    background: none;
    font: inherit;
    color: inherit;
    text-align: start;
}

/* Active item earns a leading marker as well as a tint — colour alone is a weak
   signal, and it is the one thing the user scans for on every page load. */
.aside-menu .menu-item .menu-link.active {
    position: relative;
    font-weight: 600;
}

.aside-menu .menu-item .menu-link.active::before {
    content: "";
    position: absolute;
    inset-inline-start: 0;
    top: 50%;
    transform: translateY(-50%);
    width: 3px;
    height: 1.25rem;
    border-radius: 0 3px 3px 0;
    background-color: var(--bs-primary);
}

html[dir="rtl"] .aside-menu .menu-item .menu-link.active::before {
    border-radius: 3px 0 0 3px;
}

.aside-menu .menu-icon {
    flex: 0 0 1.75rem;
}

.aside-logo {
    border-block-end: 1px solid var(--nx-border-hairline);
}

/* -----------------------------------------------------------------------------
   5. Surfaces — cards
   -------------------------------------------------------------------------- */

.card {
    border-radius: var(--nx-radius-lg);
    box-shadow: var(--nx-shadow-card);
}

/* Concentric radius: a card body flush against a rounded parent needs the inner
   radius reduced by its padding, or the corners read as mismatched. */
.card > .card-header:first-child {
    border-start-start-radius: var(--nx-radius-lg);
    border-start-end-radius: var(--nx-radius-lg);
}

.card-header .card-title {
    font-weight: 600;
    color: var(--bs-gray-900);
}

/* Cards that are themselves a link (settings hub, dashboard shortcuts). */
a > .card,
.card.hover-scale {
    transition:
        box-shadow var(--nx-duration) var(--nx-ease),
        transform var(--nx-duration) var(--nx-ease);
}

a:hover > .card,
.card.hover-scale:hover {
    box-shadow: var(--nx-shadow-card-hover);
    transform: translateY(-2px);
}

a:focus-visible > .card {
    box-shadow: var(--nx-shadow-card-hover);
    transform: translateY(-2px);
}

/* -----------------------------------------------------------------------------
   6. Data — tables and numerals
   -------------------------------------------------------------------------- */

/* Header row demotes to a label so the data leads. Size, weight, colour and
   case come from utility classes on the <tr> in the template
   (`text-gray-500 fw-bold fs-7 text-uppercase`), not from here: Craft's
   `.table:not(.table-bordered) th` forces those four properties to `inherit` at a
   higher specificity, and the utilities win because they carry !important. Only
   what that rule doesn't claim belongs in this block. */
.table > thead > tr > th {
    letter-spacing: 0.04em;
    white-space: nowrap;
    vertical-align: middle;
}

/* Nastaliq is a connected script — letter-spacing breaks the joins. */
html[dir="rtl"] .table > thead > tr > th {
    letter-spacing: normal;
}

/* Row height is the single biggest readability lever on a dense listing —
   table-sm alone packs rows too tight to scan. */
.table > tbody > tr > td {
    padding-block: 0.7rem;
    vertical-align: middle;
}

.table-hover > tbody > tr {
    transition: background-color var(--nx-duration-fast) var(--nx-ease);
}

/* Every figure the user compares down a column gets fixed-width digits, so the
   decimal points line up and the column stops shivering on re-sort. */
.table td,
.table th,
.fs-2hx,
.fs-2x,
.fs-2,
.badge {
    font-variant-numeric: tabular-nums;
}

/* Row actions follow the theme's standard KTMenu pattern, without a custom
   wrapper class that breaks the current layout. */
.menu-link.text-danger {
    color: var(--bs-danger) !important;
}

.menu-link.text-danger:hover,
.menu-link.text-danger:focus-visible {
    background-color: rgba(var(--bs-danger-rgb), 0.08);
}

/* The inline (non-dropdown) variant of admin/components/row_action.html.twig.
   The component has always emitted this class and it has never been defined, so a
   destructive inline action was red only by accident of the text-danger utility on
   its child icon, and had no hover state at all — the one action where the user most
   deserves confirmation that they are about to hit the right control. */
.nx-row-action-danger {
    color: var(--bs-danger);
    border-radius: var(--nx-radius-sm);
    transition: background-color var(--nx-duration-fast) var(--nx-ease);
}

.nx-row-action-danger:hover,
.nx-row-action-danger:focus-visible {
    background-color: rgba(var(--bs-danger-rgb), 0.08);
}

/* Keep every table row-action menu compact regardless of its utility width. */
.table td > .menu.menu-sub.menu-sub-dropdown {
    width: 180px !important;
}

/* Chart-of-accounts sections: Move Up/Down swap two rows over AJAX (see account_section/index.js),
   which briefly adds/removes bg-light-primary on the moved row to flash it as visible feedback in
   place of the page reload that used to make the change obvious on its own. */
#account_sections_table tbody tr {
    transition: background-color 0.6s ease;
}

/* DataTables chrome: the length/search/info row is theme-styled but the paging
   control sits too close to the table on a card-flush body. */
.dataTables_wrapper .dataTables_paginate,
.dataTables_wrapper .dataTables_info,
.dataTables_wrapper .dataTables_length {
    padding-block-start: 0.5rem;
}

/* DataTables sort indicators. assets/nx-datatable.js injects `.nx-sort` (an up and a down caret,
   laid out and muted with utility classes) into every sortable header. Only what a utility class
   cannot express lives here: switching off Keen's own pseudo-element arrows, and turning the
   caret matching the <th>'s `sorting_asc` / `sorting_desc` state primary. */
table.dataTable > thead > tr > th.sorting::before,
table.dataTable > thead > tr > th.sorting::after,
table.dataTable > thead > tr > th.sorting_asc::before,
table.dataTable > thead > tr > th.sorting_asc::after,
table.dataTable > thead > tr > th.sorting_desc::before,
table.dataTable > thead > tr > th.sorting_desc::after {
    display: none !important;
}

table.dataTable > thead > tr > .sorting_asc .nx-sort > .bi-caret-up-fill,
table.dataTable > thead > tr > .sorting_desc .nx-sort > .bi-caret-down-fill {
    /* !important: the carets carry `text-gray-300`, itself !important, which this must outrank. */
    color: var(--bs-primary) !important;
}

/* Wide listings scroll inside the card rather than widening the page.
   Note: DataTables' bootstrap4 integration injects its own `.table-responsive`
   around the table, so DataTable-backed listings already scroll. The wrapper in
   the templates is what covers the tables that are *not* DataTables — the chart
   of accounts tree, the company detail payments table — and is a harmless
   no-op where DataTables has already handled it. */

/* -----------------------------------------------------------------------------
   7. Forms
   -------------------------------------------------------------------------- */

.form-control,
.form-select {
    border-radius: var(--nx-radius-sm);
}

a {
    color: var(--bs-primary);
}

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

.form-check-input[type="checkbox"]:indeterminate {
    background-color: var(--bs-primary-active);
    border-color: var(--bs-primary-active);
}

.form-check-label {
    color: var(--bs-gray-800);
}

/* A field group inside a card body: label reads as a label, not as body copy. */
.form-label {
    font-weight: 600;
    color: var(--bs-gray-700);
    margin-bottom: 0.4rem;
}

/* Report section chevron: points down when open, sideways when collapsed (flipped in RTL). */
.nx-report-toggle i {
    transition: transform var(--nx-duration-fast) var(--nx-ease);
}

.nx-report-toggle[aria-expanded="false"] i {
    transform: rotate(-90deg);
}

[dir="rtl"] .nx-report-toggle[aria-expanded="false"] i {
    transform: rotate(90deg);
}

/* Keyboard-reachable hint icon (form_inputs/* partials). */
.nx-hint {
    color: var(--bs-gray-500);
    border-radius: 50%;
    transition: color var(--nx-duration-fast) var(--nx-ease);
}

.nx-hint:hover,
.nx-hint:focus-visible {
    color: var(--bs-primary);
}

/* Active/inactive switch (admin/components/active_switch.html.twig): the label shows the word for
   the state the switch is in. Both words are in the markup; :checked picks one, so it flips
   without JS. */
.nx-state-switch .form-check-input:checked ~ .form-check-label .nx-state-off,
.nx-state-switch
    .form-check-input:not(:checked)
    ~ .form-check-label
    .nx-state-on {
    display: none;
}

/* Document line-item grid. The column widths were inline `style` attributes repeated across the
   four editor templates and their two row partials, so a column could be 180px in one document type
   and 200px in another for no reason anyone remembered. `min-width` rather than `width` on the
   numeric columns: they hold inputs that must not collapse, but may grow on a wide screen. */
.nx-line-col-product,
.nx-line-col-account,
.nx-line-col-description {
    width: 200px;
}

.nx-line-col-qty {
    min-width: 90px;
}

.nx-line-col-discount {
    min-width: 100px;
}

.nx-line-col-rate {
    min-width: 110px;
}

.nx-line-col-money {
    min-width: 120px;
}

.nx-line-col-price {
    min-width: 160px;
}

/* form_errors() renders a field's errors as a bare <ul>; in a 90px line-grid cell its 2rem indent and
   bullet squeezed "This value should be positive." down to a word per line. */
.table td .invalid-feedback > ul {
    padding: 0;
    margin: 0;
    list-style: none;
}

/* Avatar/logo uploader placeholder. Was a <style> block inside
   form_inputs/image_input.html.twig, re-emitted on every page that renders the partial. The paths
   are stable: public/preCompiledAssets/ is served directly and is not digested by Asset Mapper,
   which is why the @font-face above can address it the same way. */
.image-input-placeholder {
    background-image: url("/preCompiledAssets/images/blank-image.svg");
}

[data-bs-theme="dark"] .image-input-placeholder {
    background-image: url("/preCompiledAssets/images/blank-image-dark.svg");
}

/* A raw API response shown back to the user — the FBR/PRA reply on a failed submission.
   Long unbroken values (tokens, URLs) would otherwise force the modal to scroll sideways. */
.nx-json-dump {
    white-space: pre-wrap;
    word-break: break-word;
    padding: 1rem;
    border-radius: var(--nx-radius-sm);
    background-color: var(--bs-gray-100);
    margin-bottom: 0;
}

/* Sticky save bar. Sits above the page content, so it needs a real edge to stop
   the table/form underneath appearing to bleed through it while scrolling.

   The background must match the *page*, not the body. --bs-app-bg-color does not
   exist in this Craft build, so the previous value fell through to --bs-body-bg —
   identical to --bs-page-bg in light mode, which is why nobody noticed, but #15171C
   against a #0F1014 page in dark mode, which rendered the bar as a lighter band
   floating over the content it is supposed to sit flush with. */
.nx-form-actions {
    background-color: var(--bs-page-bg, var(--bs-body-bg));
    border-block-end: 1px solid var(--nx-border-hairline);
}

/* Only the save pair gets the wide hit target. Scoped to the two attributes rather
   than to .btn, because document editors put approve / void / print / send-to-FBR
   controls in this bar too — including icon-only ones, which a 7rem floor would
   stretch into lozenges. */
.nx-form-actions [data-page-form-button],
.nx-form-actions [data-page-form-button-stay] {
    min-width: 7rem;
}

/* Section heading inside a form card — the previous <hr> + <h5> pair became a
   flex item in the row grid and broke the column rhythm. */
.nx-form-section {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-block-start: 0.5rem;
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--bs-gray-500);
}

.nx-form-section::after {
    content: "";
    flex: 1 1 auto;
    height: 1px;
    background-color: var(--nx-border-hairline);
}

html[dir="rtl"] .nx-form-section {
    letter-spacing: normal;
    text-transform: none;
    font-size: 0.85rem;
}

.filter-status-btn.active {
    font-weight: bold;
}

/* Tabs and pills */
.nav-line-tabs .nav-item .nav-link.active,
.nav-line-tabs .nav-item .nav-link.active i {
    color: var(--bs-primary-active);
}

.nav .nav-link {
    color: var(--bs-gray-700);
}

.nav .nav-link:hover,
.nav .nav-link:focus {
    color: var(--bs-primary);
}

.nav .nav-link.active,
.nav .show > .nav-link {
    color: var(--bs-primary-active);
}

.nav-pills .nav-link {
    color: var(--bs-gray-700);
}

.nav-pills .nav-link.active {
    font-weight: bold;
    background-color: var(--bs-primary-light);
    color: var(--bs-primary-active);
}

.nav-tabs .nav-item.show .nav-link,
.nav-tabs .nav-link.active {
    color: var(--bs-primary-active);
    font-weight: bold;
}

.menu-state-color .menu-item.show > .menu-link .menu-title {
    color: var(--bs-primary-active);
}

.border-primary {
    border-color: var(--bs-primary) !important;
}

.dz-preview .dz-image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* -----------------------------------------------------------------------------
   8. Feedback — empty states, focus, motion
   -------------------------------------------------------------------------- */

.nx-empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding-block: 3.5rem;
    padding-inline: 1.5rem;
}

.nx-empty-state__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 3.5rem;
    height: 3.5rem;
    margin-bottom: 1.25rem;
    border-radius: 50%;
    background-color: var(--bs-primary-light);
    color: var(--bs-primary);
    font-size: 1.5rem;
}

.nx-empty-state__title {
    font-size: 1.15rem;
    font-weight: 600;
    color: var(--bs-gray-900);
    margin-bottom: 0.35rem;
}

.nx-empty-state__body {
    max-width: 26rem;
    color: var(--bs-gray-600);
    margin-bottom: 1.25rem;
}

/* Chart placeholder while ApexCharts is fetching, so the card has a height and
   the dashboard doesn't reflow under the user. */
.nx-chart {
    min-height: 320px;
}

.nx-chart-placeholder {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    min-height: 320px;
    color: var(--bs-gray-500);
}

/* Focus. Never removed — only made consistent across the theme's mixed
   components, several of which ship their own weaker ring. */
:focus-visible {
    outline: 2px solid var(--bs-primary);
    outline-offset: 2px;
}

.btn:focus-visible,
.menu-link:focus-visible {
    /* !important: the theme sets `.menu-link { outline: 0 !important }`, so a
       plain rule here leaves sidebar links with no visible focus indicator. */
    outline: 2px solid var(--bs-primary) !important;
    outline-offset: 2px;
}

/* Press feedback — tactile confirmation the click landed. */
.btn:not(.disabled):not(:disabled):active {
    transform: scale(0.98);
}

.btn {
    transition:
        background-color var(--nx-duration-fast) var(--nx-ease),
        border-color var(--nx-duration-fast) var(--nx-ease),
        color var(--nx-duration-fast) var(--nx-ease),
        transform var(--nx-duration-fast) var(--nx-ease);
}

@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;
    }

    a:hover > .card,
    .card.hover-scale:hover,
    .btn:active {
        transform: none;
    }
}

/* Print settings editor (admin/settings/print/edit.html.twig): a row whose switch is off dims its heading/alignment controls. */
.nx-print-row:has(.nx-print-visible:not(:checked)) .nx-print-controls {
    opacity: 0.6;
}

/* Split auth shell (templates/front_end/security/_split_layout.html.twig) */
.nx-auth-aside {
    flex: 0 0 31%;
    max-width: 31%;
}
.nx-auth-illustration {
    max-width: 400px;
}
.nx-auth-illustration svg {
    width: 100%;
    height: auto;
    display: block;
}
