/**
 * Component styles — the vocabulary new screens are built from.
 *
 * `compat.css` restyles what already exists. This defines what does not: a small
 * set of `.sx-*` classes that carry a MEANING, so a blade asks for `sx-money`
 * rather than for `text-right` plus a font-variant declaration plus a colour.
 *
 * ---
 *
 * WHY THESE ARE GLOBAL RATHER THAN SCOPED.
 *
 * The plan's `.sx` wrapper exists to stop new styling leaking into un-migrated
 * screens, and that matters for any rule that redefines a class Bootstrap already
 * owns — `.form-control`, `.btn`, `.table`. Every one of those lives in
 * `compat.css`, deliberately, behind the `UI_REFRESH` switch.
 *
 * Nothing here redefines an existing class. `sx-money` and `sx-card` do not
 * appear anywhere in the 1,389 legacy blades, so there is nothing to leak into,
 * and a scope would only mean every component had to be wrapped before it worked.
 *
 * ---
 *
 * WHAT DECIDED THE ORDER THEY WERE BUILT IN: I wrote the same
 * "does the control account tie?" banner by hand four times today — on the
 * ageing screen, the fixed asset register, the vendor bill queue and the VAT
 * return. `sx-reconciliation` is that, once. A component library earns its place
 * by removing the fourth copy, not by existing.
 */

/* -------------------------------------------------------------------
   Surfaces
   ------------------------------------------------------------------- */

.sx-card {
    background-color: rgb(var(--sx-surface));
    border: var(--sx-hairline) solid rgb(var(--sx-border));
    border-radius: var(--sx-radius);
    box-shadow: none;
    color: rgb(var(--sx-text));
}

.sx-card__header {
    align-items: baseline;
    border-bottom: var(--sx-hairline) solid rgb(var(--sx-border));
    display: flex;
    flex-wrap: wrap;
    gap: var(--sx-space-2);
    justify-content: space-between;
    padding: var(--sx-panel-pad);
}

.sx-card__title {
    color: rgb(var(--sx-text));
    font-size: var(--sx-text-lg);
    font-weight: var(--sx-weight-medium);
    margin: 0;
}

.sx-card__subtitle {
    color: rgb(var(--sx-text-muted));
    font-size: var(--sx-text-sm);
}

.sx-card__body {
    padding: var(--sx-panel-pad);
}

/* A table fills its card edge to edge; padding around a table wastes the width
   an ERP needs most. */
.sx-card__body--flush {
    padding: 0;
}

/* -------------------------------------------------------------------
   Money — the component this library exists for
   -------------------------------------------------------------------

   Every amount in this product should render through it. Three things it does
   that hand-written markup keeps forgetting:

   equal-width digits, so a column can be scanned;
   a negative that is coloured AND parenthesised, because colour alone fails for
   the eight percent of men who cannot distinguish it;
   bidi isolation, so an amount inside an Arabic sentence does not reorder.
   ------------------------------------------------------------------- */

.sx-money {
    direction: ltr;
    display: inline-block;
    font-feature-settings: 'tnum' 1;
    font-variant-numeric: tabular-nums;
    unicode-bidi: isolate;
    white-space: nowrap;
}

.sx-money--negative {
    color: rgb(var(--sx-amount-negative));
}

.sx-money--zero {
    color: rgb(var(--sx-amount-zero));
}

.sx-money--debit { color: rgb(var(--sx-debit)); }
.sx-money--credit { color: rgb(var(--sx-credit)); }

.sx-money--large {
    font-size: var(--sx-text-2xl);
    font-weight: var(--sx-weight-bold);
}

.sx-money__currency {
    color: rgb(var(--sx-text-muted));
    font-size: 0.85em;
    margin-inline-start: 0.25em;
}

/* -------------------------------------------------------------------
   Status
   -------------------------------------------------------------------

   Reads the semantic tokens, so a draft is grey and an overdue is red because
   that is what those words MEAN — not because somebody picked a Bootstrap
   contextual class that happened to look right.
   ------------------------------------------------------------------- */

.sx-badge {
    align-items: center;
    border: var(--sx-hairline) solid transparent;
    border-radius: var(--sx-radius-pill);
    display: inline-flex;
    font-size: var(--sx-text-xs);
    font-weight: var(--sx-weight-medium);
    gap: 0.35em;
    line-height: 1.4;
    padding: 2px 9px;
    white-space: nowrap;
}

.sx-badge::before {
    background-color: currentColor;
    border-radius: 50%;
    content: '';
    height: 6px;
    width: 6px;
}

.sx-badge--draft    { background: rgb(var(--sx-status-draft) / 0.12);    color: rgb(var(--sx-status-draft)); }
.sx-badge--pending  { background: rgb(var(--sx-status-pending) / 0.14);  color: rgb(var(--sx-status-pending)); }
.sx-badge--held     { background: rgb(var(--sx-status-held) / 0.14);     color: rgb(var(--sx-status-held)); }
.sx-badge--approved { background: rgb(var(--sx-status-approved) / 0.12); color: rgb(var(--sx-status-approved)); }
.sx-badge--posted   { background: rgb(var(--sx-status-posted) / 0.12);   color: rgb(var(--sx-status-posted)); }
.sx-badge--overdue  { background: rgb(var(--sx-status-overdue) / 0.12);  color: rgb(var(--sx-status-overdue)); }
.sx-badge--void     { background: rgb(var(--sx-status-void) / 0.12);     color: rgb(var(--sx-status-void)); }
.sx-badge--accent   { background: rgb(var(--sx-accent) / 0.10);          color: rgb(var(--sx-accent)); }

/* -------------------------------------------------------------------
   Reconciliation — the accounting-specific one
   -------------------------------------------------------------------

   "Does this tie?" is the question every control screen in this product exists
   to answer, and it must be answered ABOVE the list rather than below it. An
   ageing that does not tie to its control account is a list, not a
   reconciliation, and a reader who has already scrolled the list has already
   believed it.
   ------------------------------------------------------------------- */

.sx-reconciliation {
    border: var(--sx-hairline) solid rgb(var(--sx-border));
    border-inline-start-width: 3px;
    border-radius: var(--sx-radius);
    display: flex;
    flex-wrap: wrap;
    gap: var(--sx-space-2) var(--sx-space-6);
    margin-bottom: var(--sx-space-4);
    padding: var(--sx-space-3) var(--sx-space-4);
}

.sx-reconciliation--agrees {
    background-color: rgb(var(--sx-success-500) / 0.06);
    border-color: rgb(var(--sx-success-500) / 0.30);
    border-inline-start-color: rgb(var(--sx-success-600));
}

.sx-reconciliation--disagrees {
    background-color: rgb(var(--sx-danger-500) / 0.06);
    border-color: rgb(var(--sx-danger-500) / 0.30);
    border-inline-start-color: rgb(var(--sx-danger-600));
}

/* Nothing to compare is not the same as agreeing, and saying "balanced" when
   both sides are zero is how a green tick stops meaning anything. */
.sx-reconciliation--empty {
    background-color: rgb(var(--sx-surface-sunken));
    border-inline-start-color: rgb(var(--sx-border-strong));
}

.sx-reconciliation__figure {
    display: flex;
    flex-direction: column;
    gap: 1px;
}

.sx-reconciliation__label {
    color: rgb(var(--sx-text-muted));
    font-size: var(--sx-text-xs);
    letter-spacing: 0.02em;
    text-transform: uppercase;
}

.sx-reconciliation__value {
    font-feature-settings: 'tnum' 1;
    font-size: var(--sx-text-lg);
    font-variant-numeric: tabular-nums;
    font-weight: var(--sx-weight-medium);
}

.sx-reconciliation__note {
    color: rgb(var(--sx-text-muted));
    flex-basis: 100%;
    font-size: var(--sx-text-sm);
}

/* -------------------------------------------------------------------
   Page header
   ------------------------------------------------------------------- */

.sx-page-header {
    align-items: flex-end;
    display: flex;
    flex-wrap: wrap;
    gap: var(--sx-space-3);
    justify-content: space-between;
    margin-bottom: var(--sx-space-4);
}

.sx-page-header__title {
    font-size: var(--sx-text-2xl);
    font-weight: var(--sx-weight-bold);
    margin: 0;
}

.sx-page-header__subtitle {
    color: rgb(var(--sx-text-muted));
    font-size: var(--sx-text-sm);
    margin-top: 2px;
}

.sx-page-header__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sx-space-2);
}

/* -------------------------------------------------------------------
   Stat tile — figures, not twelve identical coloured boxes
   ------------------------------------------------------------------- */

.sx-stat {
    background-color: rgb(var(--sx-surface));
    border: var(--sx-hairline) solid rgb(var(--sx-border));
    border-radius: var(--sx-radius);
    padding: var(--sx-space-4);
}

.sx-stat__label {
    color: rgb(var(--sx-text-muted));
    font-size: var(--sx-text-sm);
}

.sx-stat__value {
    font-feature-settings: 'tnum' 1;
    font-size: var(--sx-text-2xl);
    font-variant-numeric: tabular-nums;
    font-weight: var(--sx-weight-bold);
    margin-top: 2px;
}

.sx-stat__note {
    color: rgb(var(--sx-text-muted));
    font-size: var(--sx-text-xs);
    margin-top: var(--sx-space-1);
}

/* An exception card, for a command centre that shows what needs attention
   instead of what is fine. */
.sx-stat--exception {
    border-inline-start: 3px solid rgb(var(--sx-status-overdue));
}

/* -------------------------------------------------------------------
   Empty state
   -------------------------------------------------------------------

   Says WHY there is nothing, not just that there is nothing. "No records found"
   is the answer to a question nobody asked.
   ------------------------------------------------------------------- */

.sx-empty {
    color: rgb(var(--sx-text-muted));
    padding: var(--sx-space-6) var(--sx-space-4);
    text-align: center;
}

.sx-empty__title {
    color: rgb(var(--sx-text));
    font-weight: var(--sx-weight-medium);
}

.sx-empty__note {
    font-size: var(--sx-text-sm);
    margin-top: var(--sx-space-1);
}

/* -------------------------------------------------------------------
   Field
   ------------------------------------------------------------------- */

.sx-field {
    margin-bottom: var(--sx-space-3);
}

.sx-field__label {
    color: rgb(var(--sx-text-muted));
    display: block;
    font-size: var(--sx-text-sm);
    font-weight: var(--sx-weight-medium);
    margin-bottom: var(--sx-space-1);
}

.sx-field__required {
    color: rgb(var(--sx-danger-500));
}

.sx-field__help {
    color: rgb(var(--sx-text-muted));
    display: block;
    font-size: var(--sx-text-xs);
    margin-top: 2px;
}

.sx-field__error {
    color: rgb(var(--sx-danger-600));
    display: block;
    font-size: var(--sx-text-xs);
    margin-top: 2px;
}

/* -------------------------------------------------------------------
   Toolbar — the filter row above a list
   ------------------------------------------------------------------- */

.sx-toolbar {
    align-items: flex-end;
    display: flex;
    flex-wrap: wrap;
    gap: var(--sx-space-3);
    margin-bottom: var(--sx-space-4);
}

.sx-toolbar__spacer {
    margin-inline-start: auto;
}

/* -------------------------------------------------------------------
   Command palette — Ctrl+K / ⌘K
   -------------------------------------------------------------------

   A floating layer, so it is one of the few places a shadow is earned
   (see tokens: shadows belong to things that float). Reads only tokens,
   so it is dark-mode correct without a single override.
   ------------------------------------------------------------------- */

.sx-palette {
    display: none;
    inset: 0;
    position: fixed;
    z-index: 4000;
}

.sx-palette.is-open {
    display: block;
}

.sx-palette__backdrop {
    background: rgb(0 0 0 / 0.35);
    inset: 0;
    position: absolute;
}

.sx-palette__panel {
    background: rgb(var(--sx-surface));
    border: var(--sx-hairline) solid rgb(var(--sx-border));
    border-radius: var(--sx-radius-lg);
    box-shadow: var(--sx-shadow-modal);
    inset-inline-start: 50%;
    margin-inline-start: min(-19rem, -45vw);
    position: absolute;
    top: 12vh;
    width: min(38rem, 90vw);
}

.sx-palette__input {
    background: transparent;
    border: 0;
    border-bottom: var(--sx-hairline) solid rgb(var(--sx-border));
    color: rgb(var(--sx-text));
    font-size: var(--sx-text-lg);
    outline: none;
    padding: var(--sx-space-3) var(--sx-space-4);
    width: 100%;
}

.sx-palette__list {
    list-style: none;
    margin: 0;
    max-height: 50vh;
    overflow-y: auto;
    padding: var(--sx-space-1);
}

.sx-palette__item {
    align-items: baseline;
    border-radius: var(--sx-radius);
    cursor: pointer;
    display: flex;
    gap: var(--sx-space-2);
    justify-content: space-between;
    padding: var(--sx-space-2) var(--sx-space-3);
}

.sx-palette__item:hover,
.sx-palette__item.is-active {
    background: rgb(var(--sx-accent) / 0.10);
}

.sx-palette__title {
    color: rgb(var(--sx-text));
}

.sx-palette__group {
    color: rgb(var(--sx-text-muted));
    font-size: var(--sx-text-xs);
    white-space: nowrap;
}

.sx-palette__hint {
    border-top: var(--sx-hairline) solid rgb(var(--sx-border));
    color: rgb(var(--sx-text-muted));
    font-size: var(--sx-text-xs);
    padding: var(--sx-space-1) var(--sx-space-4);
    text-align: end;
}

/* ==========================================================================
   Primary action button
   ==========================================================================
   The screen's one affirmative action — "Add", "Save", "New" — written 88
   times across 81 blades as the same hand-rolled string:
   `tw-bg-gradient-to-r tw-from-indigo-600 tw-to-blue-500 tw-font-bold
   tw-text-white tw-border-none tw-rounded-full`.

   Three things were wrong with that. It is a HARDCODED indigo→blue gradient,
   so it ignores `--sx-accent` entirely: the brand colour can be changed in
   tokens.css and 81 screens keep the old one. It cannot follow the theme —
   white-on-indigo stays white-on-indigo in dark mode, where the rest of the
   page has inverted around it. And a full-radius gradient pill is the
   "brochure" register this design system explicitly rejects; an instrument
   panel does not decorate the button that commits a transaction.

   Kept deliberately: this styles only the SKIN. `tw-dw-btn` still supplies
   the button's box (padding, inline layout, sizing), and every behavioural
   hook alongside it — `btn-modal`, `pull-right`, spacing utilities — is
   untouched, because a restyle that also moves things is a restyle nobody
   can review. */
.sx-btn-primary {
    background: rgb(var(--sx-accent));
    border: var(--sx-hairline) solid rgb(var(--sx-accent));
    border-radius: var(--sx-radius);
    color: rgb(var(--sx-text-inverse));
    font-weight: 600;
}

.sx-btn-primary:hover,
.sx-btn-primary:focus,
.sx-btn-primary:active {
    background: rgb(var(--sx-accent-hover));
    border-color: rgb(var(--sx-accent-hover));
    color: rgb(var(--sx-text-inverse));
}

.sx-btn-primary:focus-visible {
    outline: 2px solid rgb(var(--sx-focus-ring));
    outline-offset: 2px;
}

/* A row that is the reason somebody opened the screen — a till that did not
   balance, a match that failed. Tinted, not shouted: the row still has to be
   readable, and a table where every exception screams is a table people stop
   scanning. The start-edge bar does the work colour alone cannot for a reader
   who cannot separate the tint from the stripe. */
.sx-row-exception > td {
    background: rgb(var(--sx-status-overdue) / 0.07);
}

.sx-row-exception > td:first-child {
    box-shadow: inset 3px 0 0 0 rgb(var(--sx-status-overdue));
}

/* Alpine hides x-cloak'd nodes until it has initialised; without this rule
   the preview flashes unstyled state on slow loads. */
[x-cloak] {
    display: none !important;
}
