/* ============================================================
   Shared presentation utilities
   ============================================================

   The small set of presentation patterns that were repeated as inline styles in
   dozens of components in the application this came from. Each class reproduces one
   exact declaration group that appeared many times; together they are not a general
   utility framework, and new one-off styling belongs in the owning component's
   .razor.css instead.

   This file must be linked LAST, after the consuming application's own stylesheets
   and its scoped bundle. These classes replaced inline styles, which outranked every
   sheet; coming last is what preserves that. A component's own scoped rules still
   outrank them, which is intended.

   Why classes rather than component CSS: these patterns cross component
   boundaries (the same muted caption appears in the dashboard, admin and public
   pages), and most of them sit on MudBlazor components, whose markup a scoped
   rule cannot reach without ::deep. A global class works from either side.

   Load order: this file is linked last, so at equal specificity it wins against
   the other application stylesheets. Component-scoped rules still outrank it,
   which is intended - a component that styles its own element keeps control.

   The neutral ramps have since been unified, so the -alt variants these once needed
   are gone; each role has exactly one class.
   ============================================================ */

/* ── Text roles ─────────────────────────────────────────── */

.text-strong {
    color: var(--ds-text-primary);
}

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

.text-secondary {
    color: var(--ds-text-secondary);
}

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

/* ── Text roles with a weight, as they were written inline ── */

.text-strong-semibold {
    color: var(--ds-text-primary);
    font-weight: 600;
}

.text-body-medium {
    color: var(--ds-text-body);
    font-weight: 500;
}

.text-strong-bold {
    color: var(--ds-text-primary);
    font-weight: 700;
}

/* ── Field and metadata labels ──────────────────────────── */

/* The small uppercase caption above a value. Two sizes are in use; they are kept
   apart until the typography scale is normalised. */
.label-caps {
    color: var(--ds-text-muted);
    text-transform: uppercase;
    font-size: var(--ds-text-10);
}

.label-caps-sm {
    color: var(--ds-text-secondary);
    font-weight: 600;
    text-transform: uppercase;
    font-size: var(--ds-text-11);
}

/* ── Surfaces ───────────────────────────────────────────── */

/* An outlined panel with no background of its own. */
.surface-outline {
    border: 1px solid var(--ds-border);
    border-radius: 8px;
}

.surface-outline-sm {
    border: 1px solid var(--ds-border);
    border-radius: 6px;
}

.surface-outline-lg {
    border: 1px solid var(--ds-border);
    border-radius: 12px;
}

/* An outlined panel filled with the surface colour - the stat-tile variant of
   surface-outline-sm, for a panel that sits on a tinted page background. */
.surface-panel-sm {
    background: var(--ds-surface);
    border: 1px solid var(--ds-border);
    border-radius: 6px;
}

/* ── Alignment ──────────────────────────────────────────── */

/* MudBlazor ships flex-1, cursor-pointer and the spacing scale, but not this one. */
.text-right {
    text-align: right;
}

/* ── Text roles with a size ─────────────────────────────── */

.text-strong-medium {
    color: var(--ds-text-primary);
    font-weight: var(--ds-weight-medium);
}

/* Secondary/muted text at body size - the metadata line under a title. */
.text-meta {
    color: var(--ds-text-secondary);
    font-size: var(--ds-text-13);
}

.text-meta-muted {
    color: var(--ds-text-muted);
    font-size: var(--ds-text-13);
}

/* ── Weight ─────────────────────────────────────────────────
   A weight on its own, with no colour attached, was the single most repeated
   inline declaration left in the application this came from: 25 attributes across
   eleven files, most
   of them on a MudText whose typography class sets a weight this then had to
   beat. These are global and this sheet is linked last, so they win on source
   order rather than on specificity - which is also why they stay this plain.
   A weight combined with a colour belongs to one of the text roles above.

   They carry a ds- prefix for a reason worth keeping. The unprefixed names are
   Bootstrap's, and seven places in the markup already say Class="fw-bold" -
   including a brand heading - written by someone who assumed Bootstrap
   was loaded. It is not, so those have always rendered at their inherited weight.
   Defining a bare .fw-bold here silently turned all seven bold, and the regression
   pass caught it. The prefix stops a utility this file adds from ever
   activating markup we did not write. */
.ds-fw-medium {
    font-weight: var(--ds-weight-medium);
}

.ds-fw-semibold {
    font-weight: var(--ds-weight-semibold);
}

.ds-fw-bold {
    font-weight: var(--ds-weight-bold);
}

/* The heading that opens a card section: three pages wrote this same declaration
   set inline. It lives here rather than in a component stylesheet because two of
   those pages are built entirely from MudBlazor components - there is no plain
   element of theirs in the tree, so nothing carries a CSS-isolation scope
   attribute and a scoped rule, ::deep or not, never matches. A global rule has no
   such requirement, and like the weights above it wins over MudBlazor's own
   typography class on source order. */
.ds-section-title {
    font-weight: var(--ds-weight-semibold);
    color: var(--ds-text-primary);
    margin-bottom: 16px;
}

/* ── Text overflow and accessibility helpers ───────────────
   MudBlazor ships flex, spacing and alignment utilities but none of these, and each
   was written inline or re-declared per feature (white-space:nowrap and min-width:0 on
   flex children, a screen-reader-only class per stylesheet). */

/* Content that a screen reader announces but that takes no space on screen. */
.ds-visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

.ds-nowrap {
    white-space: nowrap;
}

/* Lets a flex or grid child shrink below its content, so long text can truncate. */
.ds-min-w-0 {
    min-width: 0;
}

/* One line, cut with an ellipsis. Includes min-width:0 so it also works on a flex child. */
.ds-truncate {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* A fixed number of lines, cut with an ellipsis. */
.ds-line-clamp-2,
.ds-line-clamp-4 {
    display: -webkit-box;
    overflow: hidden;
    -webkit-box-orient: vertical;
}

.ds-line-clamp-2 {
    -webkit-line-clamp: 2;
    line-clamp: 2;
}

.ds-line-clamp-4 {
    -webkit-line-clamp: 4;
    line-clamp: 4;
}

/* ── Code and identifiers ───────────────────────────────────
   An API key, a key prefix, a code or a log line: monospace, and (for a long value with no
   spaces) allowed to break anywhere so it never pushes its container wider. These were
   written inline as font-family: monospace in four applications. */
.ds-mono {
    font-family: var(--ds-font-mono);
}

.ds-break-all {
    word-break: break-all;
}

/* Repeated constrained regions in admin filters, pickers and detail panels.
   Opt-in only: these classes never alter existing MudBlazor markup. Widths are
   capped by the parent so the same composition works on a phone. */
.ds-filter-control {
    flex: 1 1 11rem;
    width: 11rem;
    min-width: min(9rem, 100%);
    max-width: 100%;
}
.ds-stat-tile { flex: 1 1 9rem; min-width: 0; }
.ds-content-narrow { width: 100%; max-width: 26rem; }
.ds-min-h-screen { min-height: 100vh; }
.ds-scroll-region { max-height: 60vh; overflow-y: auto; min-height: 0; }
.ds-scroll-compact { max-height: 12rem; overflow-y: auto; }
.ds-scroll-chips { max-height: 6rem; overflow-y: auto; }
.ds-picker-panel { height: min(58vh, 32rem); min-height: min(20rem, 58vh); }
.ds-select-all { user-select: all; }
.ds-surface-alt { background: var(--ds-surface-alt); }
.ds-surface-primary { background: var(--ds-primary-subtle); }
.ds-text-disabled { color: var(--ds-text-disabled); }
.ds-text-success { color: var(--ds-success-text); }
.ds-text-error { color: var(--ds-error-text); }
.ds-divider-bottom { border-bottom: 1px solid var(--ds-divider); }
.ds-divider-top { border-top: 1px solid var(--ds-divider); }
.ds-detail-accent { border-inline-start: 3px solid var(--ds-primary); }
.ds-pre-line { white-space: pre-line; }
.ds-text-left { text-align: left; }
.ds-text-center { text-align: center; }
.ds-pre-wrap { white-space: pre-wrap; overflow-wrap: anywhere; }
.ds-min-h-0 { min-height: 0; }
.ds-text-inverse { color: var(--ds-text-inverse); }
.ds-surface-inverse { background: var(--ds-text-primary); color: var(--ds-text-inverse); }

/* Repeated table-column roles; natural table layout handles the remaining cells. */
.ds-column-avatar { width: 4rem; }
.ds-column-action { width: 6rem; }
.ds-column-detail { width: 12rem; }
.ds-column-contact { min-width: 12rem; }
.ds-cell-summary { max-width: 10rem; overflow: hidden; }

/* Semantic roles repeated by metrics, import previews and detail panels.
   Opt-in classes only; no product names or framework selectors. */
.ds-text-primary { color: var(--ds-primary); }
.ds-text-secondary { color: var(--ds-secondary); }
.ds-text-warning { color: var(--ds-warning-text); }
.ds-text-caption { font-size: var(--ds-text-12); }
.ds-text-meta { font-size: var(--ds-text-13); }
.ds-brand-fill { background: var(--ds-brand-fill); color: var(--ds-text-inverse); }
.ds-outline-inverse { border-color: var(--ds-text-inverse); }
.ds-max-w-full { max-width: 100%; }
.ds-text-uppercase { text-transform: uppercase; }
.ds-link-undecorated { text-decoration: none; }
.ds-surface-success { background: var(--ds-success-surface); }
.ds-surface-warning { background: var(--ds-warning-subtle); }
.ds-surface-error { background: var(--ds-error-surface); }
.ds-surface-secondary { background: color-mix(in srgb, var(--ds-secondary) 12%, var(--ds-surface)); }
.ds-outline-success { border: 1px solid var(--ds-success-surface); }
.ds-outline-warning { border: 1px solid var(--ds-warning-border); }
.ds-outline-error { border: 1px solid var(--ds-error-surface); }
.ds-radius-md { border-radius: var(--ds-radius-md); }
.ds-radius-lg { border-radius: var(--ds-radius-lg); }
.ds-break-word { overflow-wrap: anywhere; }
.ds-wrap { white-space: normal; }
.ds-scroll-preview { max-height: min(25rem, 60vh); overflow-y: auto; }
.ds-column-message { min-width: min(25rem, 100%); }
.ds-surface { background: var(--ds-surface); }
.ds-surface-sunken { background: var(--ds-surface-sunken); }
.ds-surface-transparent { background: transparent; }
.ds-fill-primary { background: var(--ds-primary); color: var(--ds-text-inverse); }
.ds-radius-sm { border-radius: var(--ds-radius-sm); }
.ds-radius-pill { border-radius: var(--ds-radius-pill); }
.ds-outline-dashed { border: 1px dashed var(--ds-border-emphasis); }
.ds-shadow { box-shadow: var(--ds-shadow-md); }
.ds-fw-normal { font-weight: var(--ds-weight-regular); }
.ds-text-micro { font-size: var(--ds-text-10); }
.ds-text-small { font-size: var(--ds-text-11); }
.ds-text-body { font-size: var(--ds-text-14); }
.ds-text-title { font-size: var(--ds-text-18); }
.ds-text-value { font-size: var(--ds-text-28); }
.ds-italic { font-style: italic; }
.ds-tracking-label { letter-spacing: 0.02em; }
.ds-leading-tight { line-height: var(--ds-leading-tight); }
.ds-leading-body { line-height: var(--ds-leading-body); }
.ds-align-middle { vertical-align: middle; }
.ds-content-reading { max-width: 48rem; }
.ds-flex-content { flex: 1 1 16rem; min-width: 0; }
.ds-column-date { width: 9rem; }
.ds-metric-tile { min-height: 7.5rem; }
.ds-indicator-small { width: 1rem; height: 1rem; }
.ds-badge-compact { min-height: 1.25rem; height: auto; }
.ds-sticky-panel { position: sticky; top: 1rem; }
.ds-hover-lift { transition: transform 0.2s ease, box-shadow 0.2s ease; }
.ds-hover-lift:hover { transform: translateY(-1px); box-shadow: var(--ds-shadow-md); }
.ds-accent-success { border-inline-start: 3px solid var(--ds-success); }
.ds-accent-info { border-inline-start: 3px solid var(--ds-info); }
.ds-accent-warning { border-inline-start: 3px solid var(--ds-warning); }
.ds-accent-error { border-inline-start: 3px solid var(--ds-error); }
.ds-accent-neutral { border-inline-start: 3px solid var(--ds-border-emphasis); }
/* Transient guidance anchored to newly created content. Applications decide when
   to show it; appearance and reduced-motion behavior are shared. */
.ds-pulse-dot { position: relative; width: 0.5rem; height: 0.5rem; border-radius: var(--ds-radius-pill); background: var(--ds-success); display: inline-block; }
.ds-pulse-dot::after { content: ""; position: absolute; inset: -0.375rem; border-radius: inherit; border: 2px solid var(--ds-success-surface); animation: ds-pulse 1.2s ease-out infinite; }
.ds-coachmark { position: absolute; left: 0; bottom: calc(100% + 0.5rem); max-width: min(20rem, 80vw); padding: 0.5rem 0.75rem; background: var(--ds-success); color: var(--ds-text-inverse); font-size: var(--ds-text-12); border-radius: var(--ds-radius-md); box-shadow: var(--ds-shadow-md); z-index: 2; pointer-events: none; }
@keyframes ds-pulse { from { transform: scale(0.6); opacity: 0.9; } to { transform: scale(1.6); opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .ds-pulse-dot::after { animation: none; } }
@media (prefers-reduced-motion: reduce) {
    .ds-hover-lift { transition: none; }
    .ds-hover-lift:hover { transform: none; }
}

/* ── Motion ─────────────────────────────────────────────────
   A short rise-in for content that replaces other content in place (the next step of a
   tour, say). Put it on an element with a @key so it replays; reduced motion turns it off. */
.ds-enter {
    animation: ds-enter 0.28s ease-out;
}

@keyframes ds-enter {
    from { opacity: 0; transform: translateY(6px); }
    to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
    .ds-enter {
        animation: none;
    }
}
