/* Semantic colour classes — the names the markup should use for colour.
 *
 * A Tailwind colour utility names a VALUE; these name a ROLE. The difference
 * matters when the role has to change: the muted-grey utility appeared 241
 * times in this tree, and there was no way to retone muted text without also
 * retoning every divider and disabled control that happened to be the same
 * grey. A role can be retoned here, once.
 *
 * Every class below points at a design token, so the value still has exactly
 * one definition (design-tokens.css) and the drift checks still see it.
 *
 * ---------------------------------------------------------------------------
 * WHY THIS SHEET LOADS LAST
 *
 * The Tailwind Play CDN injects its generated <style> at the END of <head>, so
 * a utility beats every equal-specificity rule in a linked project stylesheet.
 * Verified in a browser rather than assumed: with `.probe-project { color }`
 * linked after the CDN script, an element carrying both resolved to the
 * utility's colour.
 *
 * So replacing a utility with a class only preserves behaviour if the class
 * inherits the same cascade authority. Loading this sheet last among the
 * project stylesheets does that: these single-class rules now win every tie
 * against other project sheets, exactly as the utility did, and lose to the
 * same higher-specificity rules the utility lost to.
 *
 * Keep it last in base.html. Moving it earlier is a silent visual change.
 * ---------------------------------------------------------------------------
 *
 * Deliberately NO dark-mode rules here. The elements these replace often still
 * carry a `dark:` variant, which lives in Tailwind's sheet and still wins in
 * dark mode. Adding a dark rule here would fight it. Consolidating dark mode is
 * a separate, deliberate pass — this sheet is a pure like-for-like swap.
 */

/* Text ---------------------------------------------------------------------
 * Roles are the ones the tokens already name in design-tokens.css.
 */

.text-heading {
    color: var(--fg-1);
}

.text-body {
    color: var(--fg-body-strong);
}

/* Secondary body copy — supporting detail beside the main value. */
.text-secondary {
    color: var(--fg-3);
}

/* Muted text — labels, timestamps, units, help text.
 * Not named `.text-muted`: that is already taken by a Bootstrap holdover in
 * section-improvements.css painting --fg-placeholder on six auth templates,
 * which is a different colour doing a different job. */
.text-subtle {
    color: var(--fg-4);
}

/* Borders ------------------------------------------------------------------ */

.border-subtle {
    border-color: var(--border-base);
}

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

/* The soft page ground, used for inset panels and zebra rows. */
.surface-page {
    background-color: var(--bg-page);
}

/* ---------------------------------------------------------------------------
 * Second tier. Same rule as above: a role, defined once, against a token.
 *
 * Three of these were held back the first time because a project stylesheet
 * selected on the utility itself, so deleting it from the markup would have
 * dropped the rule. Those six selectors were rewritten to these class names in
 * the same change, which is the only way the swap stays safe.
 * ------------------------------------------------------------------------- */

/* Placeholder, disabled controls, and the icons that sit beside muted text.
 * One step fainter than .text-subtle. */
.text-faint {
    color: var(--fg-5);
}

/* Destructive intent — delete actions, error text in a form. */
.text-danger {
    color: var(--danger-fg);
}

/* Text on a dark or saturated ground, where the normal foreground would
 * disappear. */
.text-on-dark {
    color: var(--fg-on-dark);
}

/* The resting state on that ground: legible, but a step back from the item
 * that is actually selected. The sidebar's idle nav labels sat on Tailwind's
 * text-gray-300, a ramp the design system does not publish. */
.text-on-dark-muted {
    color: var(--nav-idle-fg);
}

/* The raised card ground the app is built from: tables, panels, modals.
 * Distinct from .surface-page, which is the recessed ground behind them. */
.surface-card {
    background-color: var(--bg-card);
}

/* A muted inset — hovered rows, disabled inputs, empty-state panels. */
.surface-muted {
    background-color: var(--status-neutral-bg);
}

/* A divider with more presence than .border-subtle: input outlines, the
 * edge of a control that has to read as interactive. */
.border-strong {
    border-color: var(--border-medium);
}

/* The faintest rule — separating rows inside a single group, where
 * .border-subtle would read as a section break. */
/* Row dividers. The same two greys as the border classes above, named for the
   job: a table or list separating its rows. Three spellings existed —
   divide-gray-200 (15), divide-gray-100 (8) and one divide-amber-200 — for
   what is one decision made twice.

   Lossless: --border-base is gray-200 and --status-neutral-bg is gray-100,
   byte for byte, so these are the same lines at a different name. */
.divide-subtle > :not([hidden]) ~ :not([hidden]) {
    border-top-width: 1px;
    border-color: var(--border-base);
}

.divide-faint > :not([hidden]) ~ :not([hidden]) {
    border-top-width: 1px;
    border-color: var(--status-neutral-bg);
}

.border-faint {
    border-color: var(--status-neutral-bg);
}

/* Success / healthy state in running text — the counterpart to .text-danger.
 * Added with it so a pair like ERROR_COUNT_ZERO_CSS / _NONZERO_CSS cannot end
 * up half semantic and half utility. */
.text-success {
    color: var(--success-mid);
}

/* ---------------------------------------------------------------------------
 * Hover affordances.
 *
 * These are the counterparts to the surfaces and text roles above: the same
 * roles, in the state a pointer is over them. They were left out of the earlier
 * sweeps because a plain class cannot carry a variant — but a RULE can, which
 * is the whole point, and it is why the tint was written out 78 times instead
 * of being decided once.
 *
 * Named for the role they hover TO, matching the resting classes above, so a
 * row that rests on .surface-card and hovers to .hover-surface reads as one
 * decision rather than two unrelated shades.
 * ------------------------------------------------------------------------- */

/* The standard hover tint: table rows, list items, ghost buttons. */
.hover-surface:hover {
    background-color: var(--bg-page);
}

/* A FILLED destructive ground, for the primary button of a confirm-destroy
 * dialog. Distinct from .btn-danger, which is the outline variant: an outline
 * reads as "you may", a fill reads as "this is the action". Modals carried
 * Tailwind's bg-red-600 / hover:bg-red-700 for it, a ramp the design system
 * does not publish. */
.surface-danger-solid {
    background-color: var(--danger-fg);
}

.surface-danger-solid:hover {
    background-color: var(--sev-high-fg);
}

/* A step firmer — used where the resting state is already the page ground. */
.hover-surface-muted:hover {
    background-color: var(--status-neutral-bg);
}

/* Firmer still: pressed-looking controls and selected rows. */
.hover-surface-strong:hover {
    background-color: var(--border-base);
}

/* Hovering a control that sits on a dark ground, e.g. the sidebar. */
.hover-surface-dark:hover {
    background-color: var(--fg-body-strong);
}

/* Text darkening on hover — the usual affordance for a muted label that is
 * actually a link or a control. */
.hover-text-body:hover {
    color: var(--fg-body-strong);
}

.hover-text-heading:hover {
    color: var(--fg-1);
}

.hover-text-secondary:hover {
    color: var(--fg-3);
}

/* On a dark ground the affordance runs the other way, toward full white. */
.hover-text-on-dark:hover {
    color: var(--fg-on-dark);
}

/* The same affordance driven by an ANCESTOR's hover, for an icon that must
 * brighten with the row it sits in rather than only under the pointer. Five
 * nav elements carried Tailwind's group-hover:text-white for this. */
.group:hover .group-hover-text-on-dark {
    color: var(--fg-on-dark);
}

/* ---------------------------------------------------------------------------
   Hovering the PARENT, not the element. A sidebar row lights its label and
   its icon together, so the icon reacts to the row's hover rather than its
   own. Tailwind spells this ``group-hover:``; the palette utilities it
   reached for were the last colour decisions in the sidebar markup.
   ``.group`` stays as the parent marker — Tailwind defines no styles for it,
   only the variant, so the descendant selector below is the whole mechanism.
   --------------------------------------------------------------------------- */
.group:hover .group-hover-text-on-dark {
    color: var(--fg-on-dark);
}

.group:hover .group-hover-text-brand {
    color: var(--color-brand-green-deep);
}

/* A border firming up on hover — inputs and cards that are clickable. */
.hover-border-strong:hover {
    border-color: var(--border-medium);
}

/* ---------------------------------------------------------------------------
 * Compliance / coverage accent.
 *
 * The compliance surfaces — framework mappings, the coverage panels, the
 * "Supported" chips — carry one concept in one colour family across 136 sites.
 * The shades are not arbitrary; each plays a role, so they are named for the
 * role rather than the step.
 *
 * The family is the brand's own deep green: the accent text is exactly
 * --color-brand-green-deep, and the fill and deep text are the --coverage-*
 * tokens the design system already defined for this concept.
 * ------------------------------------------------------------------------- */

/* Accent text — section headings, counts, inline emphasis. */
.text-compliance {
    color: var(--color-brand-green-deep);
}

/* A softer accent, used on icons beside the text above. */
.text-compliance-soft {
    color: var(--link-internal-fg);
}

/* Text sitting ON a compliance fill, where the accent lacks contrast. */
.text-compliance-deep {
    color: var(--coverage-strong-fg);
}

/* The faint tint behind a whole compliance section. */
.surface-compliance {
    background-color: var(--status-resolved-bg);
}

/* The firmer fill of a chip or badge. */
.surface-compliance-strong {
    background-color: var(--coverage-strong-bg);
}

.border-compliance {
    border-color: var(--success-soft-bg);
}

/* The status dot inside a "Supported" chip. */
.dot-compliance {
    background-color: var(--status-active-fg);
}

/* Three roles the set was missing, added when 34 raw shades were found sitting
   inside icon() calls — text-amber-500 for a warning glyph, text-blue-600 for an
   informational one. The value was fine; the call site naming a shade was not,
   because "re-tone every warning icon" then means finding four different ambers.
 */
/* Brand green as text. The palette had no class for this, so the dashboard's
   tenant-scope label imported COLOR_BRAND_GREEN from Python and stamped the
   hex inline — a colour decision that had left the stylesheet entirely. */
.text-brand {
    color: var(--color-brand-green);
}

.text-warning {
    color: var(--status-warning-fg);
}

.text-info {
    color: var(--status-info-fg);
}

/* The glossary's violet accent. Named for the role rather than the hue so the
   purple-600 and indigo-600 spellings collapse to one decision. */
.text-accent {
    color: var(--violet-fg);
}

/* ---------------------------------------------------------------------------
   Focus rings and overlays
   --------------------------------------------------------------------------- */

/* The keyboard focus ring. Every button macro carried Tailwind's
   focus:ring-gray-200 for this — a ramp the design system does not publish,
   restated once per macro, so the four could drift apart silently. */
.focus-ring:focus {
    outline: none;
    box-shadow: 0 0 0 4px var(--status-neutral-bg);
}

/* The skip link, visible only while focused: it lands on the page ground with
   full-contrast text, and takes the brand ring rather than a blue one so the
   first thing a keyboard user sees is the product's own colour.

   The whole focus treatment lives here. In markup it was a run of focus:
   utilities ending in a bare focus:ring-2, which paints Tailwind's DEFAULT ring
   colour — blue — so removing the explicit focus:ring-blue-500 beside it would
   have changed nothing on screen. */
.skip-link:focus {
    background-color: var(--bg-card);
    color: var(--fg-1);
    padding: 0.5rem 1rem;
    border-radius: var(--radius-md);
    font-size: var(--fs-base);
    font-weight: var(--fw-medium);
    box-shadow:
        0 0 0 2px var(--bg-card),
        0 0 0 4px var(--color-brand-green);
}

/* Modal scrims. Two grounds existed inline — one near-black at 50%, one black
   at 30% — for the same job on the same page. */
.scrim {
    background-color: color-mix(in srgb, var(--fg-1) 40%, transparent);
}

/* A soft warning ground under a section header — the "needs setup" group in a
   tenant list, and anywhere else a band of rows is flagged without being an
   error. Tailwind's amber-50 was standing in for this; it is a hair off the
   token the warning pills already use, which is exactly the drift that makes
   two warnings on one page look like two different states. */
.surface-warning {
    background-color: var(--status-warning-bg);
}

/* A card that is a link: its border and title take the brand colour on hover.
   Spelled out per call site as hover:border-emerald-400 with
   group-hover:text-emerald-700 beside it — Tailwind's emerald ramp standing in
   for the brand green it is nearly, but not exactly. Nine sites across the
   glossary, so nine chances for the two halves to drift apart. */
.card-link:hover {
    border-color: var(--color-brand-green);
}

.group:hover .card-link__title,
.card-link:hover .card-link__title {
    color: var(--color-brand-green-deep);
}

/* The hairline a sidebar row shows on hover, under the tint .hover-surface
   already provides. It was hover:border-gray-100 restated at every row. */
.hover-outline:hover {
    border-color: var(--border-base);
}

/* A soft informational ground for a grouped band of rows — the glossary's
   coverage groups. Tailwind's bg-blue-50/10 and bg-amber-50/10 were doing this
   at a tenth opacity, which is a tint of a tint and reads as neither. */
.surface-info {
    background-color: var(--status-info-bg);
}

/* A pill that links onward, in the informational tone: the glossary's
   cross-references. Was bg-indigo-50 + border-indigo-200 + hover:bg-indigo-100
   + hover:text-indigo-800 — one component spelled in four utilities, in a ramp
   the palette does not publish. */
.pill-link {
    background-color: var(--status-info-bg);
    border-color: var(--sev-info-fg);
    color: var(--status-info-fg);
}

.pill-link:hover {
    background-color: color-mix(
        in srgb,
        var(--status-info-fg) 18%,
        transparent
    );
    color: var(--color-brand-green-deep);
}

/* The glossary's section heading, in the accent its terms are keyed to. Was an
   inline style repeating the token and its fallback at every heading. */
.glossary-heading {
    color: var(--glossary-term-accent, var(--violet-fg));
}

/* A code/payload sample: light text on a dark ground, so JSON reads as data
   rather than prose. bg-gray-900 was Tailwind's near-black standing in for the
   rail's own ground, one shade off it. */
.surface-code {
    background-color: var(--bg-sidebar);
    color: var(--fg-on-dark);
}

/* The unfilled part of a control that fills: a switch's track before it is on,
   a range slider's groove. It was bg-gray-200 restated at six call sites —
   Tailwind's ramp standing in for the neutral the palette already publishes,
   so a change to the resting state had to be made six times. */
.track-empty {
    background-color: var(--status-neutral-bg);
}

/* A hairline between inline items — a breadcrumb separator, a toolbar rule.
   Also spelled bg-gray-200, which reads as a fill rather than a rule. */
.rule-inline {
    background-color: var(--border-base);
}

/* A link that is body text until hovered — a breadcrumb ancestor, a "back to
   the list" link. It hovers to the BRAND colour, not Tailwind's blue-600: the
   product has one link colour, and five call sites spelling a different one is
   how a second one starts. Distinct from .link-internal, which is brand-green
   at rest and carries an arrow; this one only reveals itself on hover. */
.link-quiet:hover {
    color: var(--color-brand-green-deep);
}

/* A button in the informational tone: a soft ground that deepens on hover,
   with a matching focus ring. Was bg-blue-100 + hover:bg-blue-200 +
   focus:ring-blue-300 — one component spelled as three utilities in a ramp the
   palette does not publish. */
.btn-info-soft {
    background-color: var(--status-info-bg);
}

.btn-info-soft:hover {
    background-color: color-mix(
        in srgb,
        var(--status-info-fg) 20%,
        transparent
    );
}

.btn-info-soft:focus {
    box-shadow: 0 0 0 2px
        color-mix(in srgb, var(--status-info-fg) 35%, transparent);
}

/* A link that carries no colour of its own — the whole row is the target and
   the text inside keeps the colour it already had. Was
   `style="text-decoration:none; color:inherit"` written at the call site. */
.link-plain {
    color: inherit;
    text-decoration: none;
}

/* A link that is brand-green at rest and carries no arrow — distinct from
   .link-internal, which adds one, and from .link-quiet, which is body text
   until hovered. Was an inline style naming the token and the reset together. */
.link-brand {
    color: var(--color-brand-green);
    text-decoration: none;
}

/* Soft grounds for the remaining two tones. .surface-warning and .surface-info
   already existed; success and danger were still being spelled as bg-green-100
   / bg-green-50/50 / bg-red-50, three different Tailwind steps for what is one
   decision. */
.surface-success {
    background-color: var(--status-online-bg);
}

.surface-danger-soft {
    background-color: var(--status-danger-bg);
}

/* A connection dot: filled when the thing is up, danger when it is not. It was
   bg-green-500 / bg-red-500 chosen inline at each call site, and one site had
   already drifted to bg-[var(--color-brand-green)] — the same state in two
   colours, which is exactly what a named pair prevents. */
.dot-up {
    background-color: var(--color-brand-green);
}

.dot-down {
    background-color: var(--status-danger-fg);
}

/* Tinted card borders, keyed to the tone the card carries. Five call sites
   spelled these as border-green-200 / border-orange-200 / border-blue-200 /
   border-green-400 / border-blue-400 — five ramps for four decisions. */
.border-success {
    border-color: var(--success-mid);
}

.border-warning {
    border-color: var(--status-warning-fg);
}

.border-info {
    border-color: var(--info-border);
}

/* The selected pill in a filter row: a firmer outline than its unselected
   siblings, so selection reads without a second colour. Was border-gray-400,
   a step the palette does not publish. */
.border-selected {
    border-color: var(--border-strong);
}

/* A hairline between stacked rows in a dense list. Lighter than
   .border-subtle, which separates sections. Was border-gray-50. */
.border-hairline {
    border-color: color-mix(in srgb, var(--border-base) 55%, transparent);
}

/* A soft brand wash behind a recommended option — the top edge tinted, fading
   to the card ground. Was a Tailwind gradient naming two ramp steps. */
.surface-recommended {
    background-image: linear-gradient(
        to bottom,
        color-mix(in srgb, var(--color-brand-green) 8%, transparent),
        var(--bg-card)
    );
}
