/*
 * Admin panel design system.
 *
 * A port of the mobile app's design language to the web, one to one:
 * lib/view/theme/app_color_scheme.dart, app_tokens.dart, app_text_styles.dart.
 *
 * Every class here is `ui-` prefixed and self-contained, so it never fights
 * the Admiro template's own CSS on specificity. Views rebuilt on these
 * classes owe the template nothing but its Bootstrap JS (modals, dropdowns).
 *
 * Light and dark both defined; dark follows the OS unless the panel forces a
 * choice with data-theme on <html>.
 */

/* ── Tokens ──────────────────────────────────────────────────────────────── */

:root {
    --primary: #4a3aff;
    --on-primary: #ffffff;
    --primary-soft: #edebff;

    --background: #f6f6fb;
    --surface: #ffffff;
    --surface-variant: #f1f1f7;
    --surface-elevated: #ffffff;
    --border: #e6e6f0;
    --divider: #eeeef4;

    --text: #14142b;
    --text-secondary: #6b6b85;
    --text-tertiary: #9c9cb2;
    --text-inverse: #ffffff;

    --success: #16a34a;      --success-soft: #dcfce7;
    --warning: #f59e0b;      --warning-soft: #fef3c7;
    --danger:  #ef4444;      --danger-soft:  #fee2e2;
    --info:    #0ea5e9;      --info-soft:    #e0f2fe;
    --skeleton: #e9e9f1;

    /* 4pt spacing scale */
    --s-xxs: 2px;  --s-xs: 4px;  --s-sm: 8px;  --s-md: 12px;
    --s-lg: 16px;  --s-xl: 20px; --s-xxl: 24px; --s-xxxl: 32px;

    --r-sm: 10px; --r-md: 14px; --r-lg: 20px; --r-xl: 28px; --r-pill: 999px;
    --shadow: 0 8px 24px rgba(20, 20, 43, 0.06);

    --font: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, sans-serif;
    --font-ar: 'IBM Plex Sans Arabic', 'Plus Jakarta Sans', sans-serif;

    --sidebar-w: 264px;
    /* The sticky top bar's height, so a view can offset sticky content by it. */
    --topbar-h: 76px;
}

:root:not([data-theme='light']) {
    color-scheme: light;
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme='light']) {
        --primary: #8a7cff;
        --on-primary: #0b0b14;
        --primary-soft: #232047;
        --background: #0b0b14;
        --surface: #15152a;
        --surface-variant: #1d1d36;
        --surface-elevated: #1a1a31;
        --border: #2a2a47;
        --divider: #232340;
        --text: #f3f3fa;
        --text-secondary: #a3a3be;
        --text-tertiary: #6e6e8a;
        --text-inverse: #0b0b14;
        --success: #4ade80;  --success-soft: #12301f;
        --warning: #fbbf24;  --warning-soft: #3a2a0a;
        --danger:  #f87171;  --danger-soft:  #3b1414;
        --info:    #38bdf8;  --info-soft:    #0c2a3a;
        --skeleton: #232340;
        --shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
        color-scheme: dark;
    }
}

[data-theme='dark'] {
    --primary: #8a7cff;
    --on-primary: #0b0b14;
    --primary-soft: #232047;
    --background: #0b0b14;
    --surface: #15152a;
    --surface-variant: #1d1d36;
    --surface-elevated: #1a1a31;
    --border: #2a2a47;
    --divider: #232340;
    --text: #f3f3fa;
    --text-secondary: #a3a3be;
    --text-tertiary: #6e6e8a;
    --text-inverse: #0b0b14;
    --success: #4ade80;  --success-soft: #12301f;
    --warning: #fbbf24;  --warning-soft: #3a2a0a;
    --danger:  #f87171;  --danger-soft:  #3b1414;
    --info:    #38bdf8;  --info-soft:    #0c2a3a;
    --skeleton: #232340;
    --shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
    color-scheme: dark;
}

/* ── Reset and base ──────────────────────────────────────────────────────── */

.ui * { box-sizing: border-box; }

body.ui {
    margin: 0;
    background: var(--background);
    color: var(--text);
    font-family: var(--font);
    font-size: 14px;
    line-height: 1.45;
    letter-spacing: -0.1px;
    -webkit-font-smoothing: antialiased;
}

[dir='rtl'] body.ui { font-family: var(--font-ar); letter-spacing: 0; }

/*
    Scoped to plain links only. `.ui a` is specificity 0-1-1, which outranks
    every single-class component rule, so it was repainting each anchor-based
    component in primary: an `<a class="ui-btn">` came out purple-on-purple
    with an invisible label, and the whole sidebar rendered primary instead of
    secondary grey. Components own their own colour; only a bare link inherits
    the accent.
*/
.ui a { text-decoration: none; }
.ui a:not([class]) { color: var(--primary); }
.ui a:not([class]):hover { opacity: 0.85; }
.ui-link { color: var(--primary); }
.ui-link:hover { opacity: 0.85; }

/* Type scale, matching AppTextStyles */
.ui-h1 { font-size: 26px; font-weight: 800; line-height: 1.15; letter-spacing: -0.6px; margin: 0; }
.ui-h2 { font-size: 20px; font-weight: 700; line-height: 1.2;  letter-spacing: -0.4px; margin: 0; }
.ui-h3 { font-size: 16px; font-weight: 700; line-height: 1.25; letter-spacing: -0.2px; margin: 0; }
.ui-body { font-size: 15px; font-weight: 500; line-height: 1.45; margin: 0; }
.ui-body-sm { font-size: 13px; font-weight: 500; line-height: 1.4; margin: 0; }
.ui-label { font-size: 12px; font-weight: 600; letter-spacing: 0.1px; margin: 0; }
.ui-caption { font-size: 11px; font-weight: 500; line-height: 1.3; margin: 0; }
.ui-overline { font-size: 11px; font-weight: 700; letter-spacing: 0.8px; text-transform: uppercase; margin: 0; }
.ui-numeral { font-size: 30px; font-weight: 800; line-height: 1.1; letter-spacing: -0.8px;
    font-variant-numeric: tabular-nums; margin: 0; }

.ui-muted { color: var(--text-secondary); }
.ui-faint { color: var(--text-tertiary); }
.ui-num { font-variant-numeric: tabular-nums; }

/* ── App shell ───────────────────────────────────────────────────────────── */

.ui-shell { display: flex; min-height: 100vh; }

.ui-sidebar {
    position: fixed;
    inset-block: 0;
    inset-inline-start: 0;
    width: var(--sidebar-w);
    background: var(--surface);
    border-inline-end: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    padding: var(--s-xl) var(--s-md);
    overflow-y: auto;
    z-index: 40;
}

.ui-brand {
    display: flex;
    align-items: center;
    gap: var(--s-md);
    padding: 0 var(--s-sm) var(--s-xl);
    color: var(--text);
}

.ui-brand img { width: 34px; height: 34px; border-radius: var(--r-sm); }
.ui-brand-name { font-size: 15px; font-weight: 800; letter-spacing: -0.3px; }

.ui-nav-section {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.9px;
    text-transform: uppercase;
    color: var(--text-tertiary);
    padding: var(--s-lg) var(--s-sm) var(--s-sm);
}

.ui-nav-item {
    display: flex;
    align-items: center;
    gap: var(--s-md);
    padding: 10px var(--s-md);
    margin-bottom: 2px;
    border-radius: var(--r-md);
    color: var(--text-secondary);
    font-size: 14px;
    font-weight: 600;
    transition: background 0.12s ease, color 0.12s ease;
}

.ui-nav-item i, .ui-nav-item svg { width: 18px; font-size: 16px; text-align: center; flex: none; }
.ui-nav-item:hover { background: var(--surface-variant); color: var(--text); opacity: 1; }
.ui-nav-item.is-active { background: var(--primary-soft); color: var(--primary); font-weight: 700; }
.ui-nav-item .ui-nav-count {
    margin-inline-start: auto;
    background: var(--danger); color: var(--text-inverse);
    border-radius: var(--r-pill); font-size: 10px; font-weight: 700;
    padding: 2px 7px;
}

.ui-main {
    flex: 1;
    margin-inline-start: var(--sidebar-w);
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.ui-topbar {
    position: sticky;
    top: 0;
    z-index: 30;
    display: flex;
    align-items: center;
    gap: var(--s-md);
    padding: var(--s-lg) var(--s-xl);
    min-height: var(--topbar-h);
    background: color-mix(in srgb, var(--background) 88%, transparent);
    backdrop-filter: blur(10px);
    border-bottom: 1px solid var(--border);
}

.ui-topbar-title { min-width: 0; flex: 1; }
.ui-topbar-actions { display: flex; align-items: center; gap: var(--s-sm); }

.ui-page { padding: var(--s-xxl) var(--s-xl) var(--s-xxxl); max-width: 1280px; width: 100%; }
.ui-page > * + * { margin-top: var(--s-xxl); }

/* Round icon button, the AppIconButton equivalent */
.ui-icon-btn {
    inline-size: 40px; block-size: 40px;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-pill);
    color: var(--text);
    cursor: pointer;
    position: relative;
    flex: none;
}

.ui-icon-btn:hover { background: var(--surface-variant); }
.ui-icon-btn.is-filled { background: var(--primary); border-color: transparent; color: var(--on-primary); }

.ui-icon-btn .ui-dot {
    position: absolute; inset-block-start: 8px; inset-inline-end: 8px;
    inline-size: 8px; block-size: 8px; border-radius: 50%;
    background: var(--danger); border: 1.5px solid var(--surface);
}

/* ── Card ────────────────────────────────────────────────────────────────── */

.ui-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    padding: var(--s-lg);
}

/* The row-shaped card: the app's most repeated unit, tighter than a content
   card. 42 of ~135 AppCard call sites use this padding. */
.ui-card.is-row { padding: var(--s-md); }

.ui-card.is-flush { padding: 0; }
.ui-card.is-elevated { box-shadow: var(--shadow); }
.ui-card.is-tappable { cursor: pointer; transition: box-shadow 0.15s ease; }
.ui-card.is-tappable:hover { box-shadow: var(--shadow); }

.ui-card-head {
    display: flex; align-items: center; gap: var(--s-md);
    margin-bottom: var(--s-md);
}

.ui-card-head .ui-card-head-text { flex: 1; min-width: 0; }
/* A title and its subtitle are one locked block, 2px apart. */
.ui-card-head-text > * + * { margin-top: 2px; }

/* A flush card has no padding of its own, so its header supplies it. The
   card component adds this class whenever `flush` and a title are combined. */
.ui-card.is-flush .ui-card-head.ui-p-head {
    padding: var(--s-lg) var(--s-lg) var(--s-md);
    margin-bottom: 0;
}
.ui-card-divider { height: 1px; background: var(--divider); margin: var(--s-lg) 0; border: 0; }

/* ── Section header ──────────────────────────────────────────────────────── */
/*
    In the app the card almost never carries its own title: AppSectionHeader
    sits above the card or the list, then 12px of air, then the content. Cards
    inside a section stack 8px apart (.ui-stack); sections stand 24px apart.
*/

.ui-section-head {
    display: flex; align-items: center; gap: var(--s-md);
    margin-bottom: var(--s-md);
}

.ui-section-head-text { flex: 1; min-width: 0; }
.ui-section-head-text > * + * { margin-top: 2px; }

.ui-section-title { font-size: 16px; font-weight: 700; line-height: 1.25; letter-spacing: -0.2px; margin: 0; }
.ui-section-sub { font-size: 13px; font-weight: 500; color: var(--text-secondary); margin: 0; }

/* The section action is a quiet text button, not a filled one. */
.ui-section-action {
    display: inline-flex; align-items: center; gap: var(--s-xs);
    padding: 8px var(--s-md);
    border: 0; background: transparent;
    border-radius: var(--r-pill);
    color: var(--primary);
    font-family: inherit; font-size: 12px; font-weight: 600;
    cursor: pointer; white-space: nowrap; flex: none;
}
.ui-section-action:hover { background: var(--primary-soft); color: var(--primary); }

/* When a label does sit inside a card it is a tertiary eyebrow, never a
   heading, so the loudest thing in the card stays the number. */
.ui-eyebrow {
    font-size: 11px; font-weight: 700; letter-spacing: 0.8px;
    text-transform: uppercase; color: var(--text-tertiary); margin: 0;
}

/* ── Grid helpers ────────────────────────────────────────────────────────── */

.ui-grid { display: grid; gap: var(--s-sm); }
.ui-grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.ui-grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.ui-grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.ui-grid.is-stats { grid-template-columns: repeat(auto-fit, minmax(0, 232px)); }
.ui-row { display: flex; align-items: center; gap: var(--s-md); }
.ui-row.is-between { justify-content: space-between; }
.ui-spacer { flex: 1; }
.ui-stack > * + * { margin-top: var(--s-sm); }

/* ── Icon disc and list row ──────────────────────────────────────────────── */
/*
    [ 44px tinted disc, radius 10 ] 12px [ title / 2px / subtitle ] [ chevron ]
    The disc radius is deliberately tighter than the card's, and the trailing
    chevron is the quietest thing in the row.
*/

.ui-disc {
    inline-size: 44px; block-size: 44px;
    border-radius: var(--r-sm);
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 20px; flex: none;
    background: var(--surface-variant); color: var(--text-secondary);
}

.ui-disc.is-sm { inline-size: 38px; block-size: 38px; font-size: 17px; }
.ui-disc.is-xs { inline-size: 32px; block-size: 32px; font-size: 15px; }

.ui-disc.is-primary { background: var(--primary-soft); color: var(--primary); }
.ui-disc.is-success { background: var(--success-soft); color: var(--success); }
.ui-disc.is-warning { background: var(--warning-soft); color: var(--warning); }
.ui-disc.is-danger  { background: var(--danger-soft);  color: var(--danger); }
.ui-disc.is-info    { background: var(--info-soft);    color: var(--info); }

.ui-item { display: flex; align-items: center; gap: var(--s-md); min-width: 0; }
.ui-item-text { flex: 1; min-width: 0; }
.ui-item-title {
    font-size: 15px; font-weight: 600; color: var(--text); margin: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ui-item-sub {
    font-size: 11px; font-weight: 500; color: var(--text-secondary); margin: 2px 0 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ui-item-chevron { color: var(--text-tertiary); font-size: 18px; flex: none; }

/* The app's _InfoRow puts a caption-sized label above its value, so the value
   is the line that carries the weight. */
.ui-item-label {
    font-size: 11px; font-weight: 500; color: var(--text-secondary); margin: 0 0 2px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ── Stat tile ───────────────────────────────────────────────────────────── */

.ui-stat {
    background: var(--surface-variant);
    border-radius: var(--r-md);
    padding: var(--s-lg);
    min-width: 0;
}

.ui-stat-label {
    display: flex; align-items: center; gap: var(--s-xs);
    font-size: 11px; font-weight: 500; color: var(--text-secondary);
    margin-bottom: var(--s-sm);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.ui-stat-value {
    font-size: 20px; font-weight: 700; letter-spacing: -0.4px;
    font-variant-numeric: tabular-nums;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.ui-stat.is-compact { padding: var(--s-md); }
.ui-stat.is-compact .ui-stat-value { font-size: 16px; }

/* ── Chip ────────────────────────────────────────────────────────────────── */

.ui-chip {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 4px 10px;
    border-radius: var(--r-pill);
    font-size: 12px; font-weight: 600;
    background: var(--surface-variant); color: var(--text-secondary);
    max-width: 100%;
}

.ui-chip > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ui-chip .ui-chip-dot { inline-size: 6px; block-size: 6px; border-radius: 50%; background: currentColor; flex: none; }

.ui-chip.is-primary { background: var(--primary-soft); color: var(--primary); }
.ui-chip.is-success { background: var(--success-soft); color: var(--success); }
.ui-chip.is-warning { background: var(--warning-soft); color: #92400e; }
.ui-chip.is-danger  { background: var(--danger-soft);  color: var(--danger); }
.ui-chip.is-info    { background: var(--info-soft);    color: #0369a1; }

@media (prefers-color-scheme: dark) {
    :root:not([data-theme='light']) .ui-chip.is-warning { color: var(--warning); }
    :root:not([data-theme='light']) .ui-chip.is-info { color: var(--info); }
}
[data-theme='dark'] .ui-chip.is-warning { color: var(--warning); }
[data-theme='dark'] .ui-chip.is-info { color: var(--info); }

/* ── Buttons ─────────────────────────────────────────────────────────────── */

.ui-btn {
    display: inline-flex; align-items: center; justify-content: center;
    gap: var(--s-sm);
    padding: 12px var(--s-xl);
    border: 1px solid transparent;
    border-radius: var(--r-md);
    background: var(--primary); color: var(--on-primary);
    font-family: inherit; font-size: 14px; font-weight: 700; letter-spacing: -0.1px;
    cursor: pointer;
    transition: opacity 0.12s ease, background 0.12s ease;
    white-space: nowrap;
}

.ui-btn:hover { opacity: 0.9; color: var(--on-primary); }
.ui-btn:disabled, .ui-btn.is-disabled { opacity: 0.5; pointer-events: none; }
.ui-btn.is-block { width: 100%; }

.ui-btn.is-secondary { background: var(--surface); border-color: var(--border); color: var(--text); }
.ui-btn.is-secondary:hover { background: var(--surface-variant); color: var(--text); }
.ui-btn.is-ghost { background: var(--primary-soft); color: var(--primary); }
.ui-btn.is-ghost:hover { color: var(--primary); }
.ui-btn.is-danger { background: var(--danger-soft); color: var(--danger); }
.ui-btn.is-danger:hover { color: var(--danger); }
.ui-btn.is-success { background: var(--success); color: #fff; }
.ui-btn.is-success:hover { color: #fff; }

.ui-btn.is-sm { padding: 7px var(--s-md); font-size: 12px; border-radius: var(--r-pill); }
.ui-btn.is-lg { padding: 15px var(--s-xxl); font-size: 15px; }

/* ── Segmented tabs ──────────────────────────────────────────────────────── */

.ui-tabs {
    display: inline-flex;
    gap: var(--s-xs);
    padding: var(--s-xs);
    background: var(--surface-variant);
    border-radius: var(--r-pill);
    max-width: 100%;
    overflow-x: auto;
    scrollbar-width: none;
}

.ui-tabs::-webkit-scrollbar { display: none; }

.ui-tab {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 9px var(--s-lg);
    border: 0; background: transparent;
    border-radius: var(--r-pill);
    color: var(--text-secondary);
    font-family: inherit; font-size: 12px; font-weight: 600;
    cursor: pointer; white-space: nowrap;
}

.ui-tab:hover { color: var(--text); }
.ui-tab.is-active { background: var(--surface); color: var(--text); font-weight: 700; box-shadow: var(--shadow); }
.ui-tab .ui-tab-count {
    background: var(--text-tertiary); color: var(--text-inverse);
    border-radius: var(--r-pill); font-size: 10px; font-weight: 700; padding: 1px 6px;
}
.ui-tab.is-active .ui-tab-count { background: var(--primary); }

/* ── Forms ───────────────────────────────────────────────────────────────── */

.ui-field { display: block; margin-bottom: var(--s-md); }
.ui-field-label {
    display: block; margin-bottom: var(--s-sm);
    font-size: 12px; font-weight: 600; color: var(--text-secondary);
}

.ui-input, .ui-select, .ui-textarea {
    width: 100%;
    padding: 12px var(--s-lg);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    color: var(--text);
    font-family: inherit; font-size: 14px;
    transition: border-color 0.12s ease;
}

.ui-input::placeholder, .ui-textarea::placeholder { color: var(--text-tertiary); }
.ui-input:focus, .ui-select:focus, .ui-textarea:focus {
    outline: none; border-color: var(--primary); border-width: 1.5px;
}
.ui-input:disabled, .ui-input[readonly] { background: var(--surface-variant); color: var(--text-secondary); }
.ui-textarea { min-height: 96px; resize: vertical; }
.ui-input.is-invalid, .ui-select.is-invalid { border-color: var(--danger); }
.ui-field-error { margin-top: var(--s-xs); font-size: 11px; color: var(--danger); }
.ui-field-help { margin-top: var(--s-xs); font-size: 11px; color: var(--text-secondary); }

.ui-search {
    display: flex; align-items: center; gap: var(--s-sm);
    padding: 0 var(--s-lg);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-pill);
    height: 46px;
}
.ui-search i { color: var(--text-tertiary); }
.ui-search input {
    flex: 1; border: 0; background: transparent; color: var(--text);
    font-family: inherit; font-size: 14px; outline: none; min-width: 0;
}

.ui-check { display: inline-flex; align-items: center; gap: var(--s-sm); cursor: pointer; }
.ui-check input { accent-color: var(--primary); inline-size: 16px; block-size: 16px; }

/* ── Table ───────────────────────────────────────────────────────────────── */

.ui-table-wrap { overflow-x: auto; border-radius: var(--r-lg); }

.ui-table { width: 100%; border-collapse: collapse; font-size: 13px; }

.ui-table th {
    text-align: start;
    padding: var(--s-md) var(--s-lg);
    background: var(--surface-variant);
    color: var(--text-secondary);
    font-size: 10px; font-weight: 700; letter-spacing: 0.7px; text-transform: uppercase;
    white-space: nowrap;
}

.ui-table th:first-child { border-start-start-radius: var(--r-sm); border-end-start-radius: var(--r-sm); }
.ui-table th:last-child  { border-start-end-radius: var(--r-sm); border-end-end-radius: var(--r-sm); }

.ui-table td {
    padding: var(--s-lg);
    border-bottom: 1px solid var(--divider);
    color: var(--text);
    vertical-align: middle;
}

.ui-table tbody tr:last-child td { border-bottom: 0; }
.ui-table tbody tr:hover td { background: var(--surface-variant); }

/* ── Avatar ──────────────────────────────────────────────────────────────── */

.ui-avatar {
    inline-size: 40px; block-size: 40px;
    border-radius: 50%;
    background: var(--primary-soft);
    color: var(--primary);
    display: inline-flex; align-items: center; justify-content: center;
    font-weight: 700; font-size: 15px;
    overflow: hidden; flex: none;
}
.ui-avatar img { width: 100%; height: 100%; object-fit: cover; }
.ui-avatar.is-sm { inline-size: 32px; block-size: 32px; font-size: 13px; }
.ui-avatar.is-lg { inline-size: 56px; block-size: 56px; font-size: 20px; }
.ui-avatar.has-ring { border: 2px solid var(--surface); }

.ui-avatar-stack { display: flex; }
.ui-avatar-stack .ui-avatar + .ui-avatar { margin-inline-start: -10px; }

/* ── Empty state and skeleton ────────────────────────────────────────────── */

.ui-empty { text-align: center; padding: var(--s-xxxl) var(--s-lg); }
.ui-empty-icon {
    inline-size: 56px; block-size: 56px; margin: 0 auto var(--s-md);
    border-radius: 50%; background: var(--surface-variant); color: var(--text-tertiary);
    display: flex; align-items: center; justify-content: center; font-size: 22px;
}
.ui-empty-title { font-size: 15px; font-weight: 600; }
.ui-empty-text { font-size: 13px; color: var(--text-secondary); margin-top: var(--s-xs); }

.ui-skeleton {
    background: var(--skeleton);
    border-radius: var(--r-sm);
    animation: ui-pulse 1.6s ease-in-out infinite;
}
@keyframes ui-pulse { 0%, 100% { opacity: 0.45; } 50% { opacity: 1; } }

/* ── Progress ────────────────────────────────────────────────────────────── */

.ui-progress { height: 6px; background: var(--surface-variant); border-radius: var(--r-pill); overflow: hidden; }
.ui-progress > div { height: 100%; background: var(--primary); border-radius: var(--r-pill); }

/* ── Check-in ring ───────────────────────────────────────────────────────── */
/*
    The app's signature element, ported one to one: 232px across, a 12px arc
    over a surface-variant track, and a white 184px disc inside carrying a
    tinted icon puck, a headline and a caption. The idle state gets the only
    coloured glow in the whole design, and the live state gets the pulse halo.

    Markup:
      <div class="ui-ring-wrap" style="--pct: 75">
        <div class="ui-ring"></div>
        <div class="ui-ring-disc"> puck / value / caption </div>
      </div>
*/

.ui-ring-wrap {
    --ring: 232px;
    --stroke: 12px;
    --pct: 0;
    --accent: var(--primary);
    position: relative;
    inline-size: var(--ring);
    block-size: var(--ring);
    margin-inline: auto;
    flex: none;
}

.ui-ring-wrap.is-live { --accent: var(--success); }

/* The arc. Masked to a ring so the track and the progress share one box. */
.ui-ring {
    position: absolute;
    inset: 0;
    border-radius: 50%;
    background-color: var(--surface-variant);
    background-image: conic-gradient(var(--accent) calc(var(--pct) * 1%), transparent 0);
    transition: background-image 600ms cubic-bezier(0.215, 0.61, 0.355, 1);
    -webkit-mask: radial-gradient(farthest-side,
        transparent calc(50% - var(--stroke)), #000 calc(50% - var(--stroke) + 0.5px));
            mask: radial-gradient(farthest-side,
        transparent calc(50% - var(--stroke)), #000 calc(50% - var(--stroke) + 0.5px));
}

/* The white disc inside, inset by twice the stroke as on mobile. */
.ui-ring-disc {
    position: absolute;
    inset: calc(var(--stroke) * 2);
    border-radius: 50%;
    background: var(--surface);
    border: 1px solid var(--border);
    box-shadow: 0 10px 32px color-mix(in srgb, var(--accent) 35%, transparent);
    display: flex; flex-direction: column;
    align-items: center; justify-content: center;
    padding: 0 var(--s-lg);
    text-align: center;
}

/* Once the shift is running the coloured halo gives way to the neutral one. */
.ui-ring-wrap.is-live .ui-ring-disc,
.ui-ring-wrap.is-done .ui-ring-disc { box-shadow: var(--shadow); }

/* The pulse, which loops only while a shift is live. */
.ui-ring-wrap.is-live::after {
    content: '';
    position: absolute; inset: 0;
    border-radius: 50%;
    background: color-mix(in srgb, var(--accent) 18%, transparent);
    animation: ui-ring-pulse 1600ms ease-out infinite;
    pointer-events: none;
    z-index: -1;
}

@keyframes ui-ring-pulse {
    from { transform: scale(0.92); opacity: 1; }
    to   { transform: scale(1.14); opacity: 0; }
}

.ui-ring-puck {
    inline-size: 36px; block-size: 36px; border-radius: 50%;
    display: grid; place-items: center;
    background: color-mix(in srgb, var(--accent) 12%, transparent);
    color: var(--accent);
    font-size: 20px;
    margin-bottom: var(--s-sm);
}

.ui-ring-wrap.is-done .ui-ring-puck { background: var(--accent); color: var(--on-primary); }

.ui-ring-value { font-size: 20px; font-weight: 700; letter-spacing: -0.4px; margin: 0; }
.ui-ring-value.is-numeral {
    font-size: 30px; font-weight: 800; letter-spacing: -0.8px;
    font-variant-numeric: tabular-nums;
}
.ui-ring-caption {
    font-size: 11px; font-weight: 500; color: var(--text-secondary);
    margin: 2px 0 0; max-width: 100%;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ── Alerts ──────────────────────────────────────────────────────────────── */

.ui-alert {
    display: flex; gap: var(--s-md); align-items: flex-start;
    padding: var(--s-lg);
    border-radius: var(--r-md);
    font-size: 13px;
}
.ui-alert.is-success { background: var(--success-soft); color: var(--success);
    border: 1px solid color-mix(in srgb, var(--success) 35%, transparent); }
.ui-alert.is-danger  { background: var(--danger-soft);  color: var(--danger);
    border: 1px solid color-mix(in srgb, var(--danger) 35%, transparent); }
.ui-alert.is-warning { background: var(--warning-soft); color: var(--warning);
    border: 1px solid color-mix(in srgb, var(--warning) 35%, transparent); }
/* The info notice is the one borderless wash in the app. */
.ui-alert.is-info    { background: var(--info-soft);    color: var(--info); border: 1px solid var(--info-soft); }

/* ── Bootstrap modal and dropdown ────────────────────────────────────────── */

/*
 * The shell deliberately loads none of Bootstrap's CSS, but it does load
 * Bootstrap's JS, which only toggles `display` and the `show` class. Without
 * the structural rules below every modal paints inline and permanently
 * visible. These are the minimum layout rules from Bootstrap 5, kept
 * verbatim in behaviour, followed by our own appearance.
 */

.modal {
    position: fixed;
    inset: 0;
    z-index: 1055;
    display: none;
    width: 100%;
    height: 100%;
    overflow-x: hidden;
    overflow-y: auto;
    outline: 0;
}

.modal-dialog {
    position: relative;
    width: auto;
    margin: var(--s-sm);
    pointer-events: none;
}

.modal.fade .modal-dialog {
    transform: translateY(-32px);
    transition: transform 0.2s cubic-bezier(0.33, 1, 0.68, 1);
}

.modal.show .modal-dialog { transform: none; }
.modal.show .modal-dialog, .modal-content { pointer-events: auto; }

.modal-content {
    position: relative;
    display: flex;
    flex-direction: column;
    width: 100%;
}

.modal-dialog-centered {
    display: flex;
    align-items: center;
    min-height: calc(100% - var(--s-lg));
}

.modal-dialog-scrollable { height: calc(100% - var(--s-lg)); }
.modal-dialog-scrollable .modal-content { max-height: 100%; overflow: hidden; }
.modal-dialog-scrollable .modal-body { overflow-y: auto; }

.modal-backdrop {
    position: fixed;
    inset: 0;
    z-index: 1050;
    width: 100vw;
    height: 100vh;
    background-color: #14142b;
    opacity: 0;
    transition: opacity 0.15s linear;
}

.modal-backdrop.show { opacity: 0.5; }

@media (min-width: 576px) {
    .modal-dialog { max-width: 520px; margin: var(--s-xxxl) auto; }
    .modal-dialog-centered { min-height: calc(100% - var(--s-xxxl) * 2); }
    .modal-lg, .modal-xl { max-width: 800px; }
    .modal-sm { max-width: 380px; }
}

/* Dropdowns: same story, JS only adds `show`. */
.dropdown, .dropup { position: relative; }

.dropdown-menu {
    position: absolute;
    z-index: 1000;
    display: none;
    min-width: 11rem;
    inset-inline-start: 0;
    margin-top: var(--s-xs);
}

.dropdown-menu.show { display: block; }
.dropdown-menu-end { inset-inline-start: auto; inset-inline-end: 0; }

/* The close button Bootstrap markup uses inside a modal header. */
.btn-close {
    inline-size: 32px;
    block-size: 32px;
    padding: 0;
    border: 0;
    border-radius: var(--r-pill);
    background: var(--surface-variant);
    color: var(--text-secondary);
    cursor: pointer;
    flex: none;
    position: relative;
}

.btn-close::before {
    content: '\00d7';
    font-size: 20px;
    line-height: 1;
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
}

.btn-close:hover { background: var(--border); color: var(--text); }

/* A handful of Bootstrap utilities that view markup and JS still rely on. */
.d-none { display: none !important; }
.fade { transition: opacity 0.15s linear; }
.fade:not(.show) { opacity: 0; }
.collapse:not(.show) { display: none; }
.visually-hidden {
    position: absolute !important;
    width: 1px; height: 1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
}

/* ── Modal and dropdown appearance ───────────────────────────────────────── */

.modal-content {
    background: var(--surface) !important;
    border: 1px solid var(--border) !important;
    border-radius: var(--r-xl) !important;
    box-shadow: var(--shadow) !important;
    color: var(--text);
}
/*
    Bootstrap's own CSS lays these two out as flex rows; since only its JS is
    loaded, ui.css has to. Without it the close button drops onto its own line
    under the title and the footer buttons stack.
*/
.modal-header {
    display: flex; align-items: center; gap: var(--s-md);
    border-bottom: 1px solid var(--divider);
    padding: var(--s-xl) var(--s-xxl);
}
.modal-header .modal-title { flex: 1; min-width: 0; }
.modal-header .btn-close { margin-inline-start: auto; }

.modal-footer {
    display: flex; align-items: center; justify-content: flex-end;
    flex-wrap: wrap; gap: var(--s-sm);
    border-top: 1px solid var(--divider);
    padding: var(--s-lg) var(--s-xxl) var(--s-xl);
}

.modal-body { padding: var(--s-xl) var(--s-xxl); }
.modal-title { font-size: 20px; font-weight: 700; letter-spacing: -0.4px; margin: 0; }

/* A modal is a fixed overlay, so the page's own child spacing must not push
   it down by 24px. */
.ui-page > .modal { margin: 0; }
.modal-backdrop.show { opacity: 0.5; }

.dropdown-menu {
    background: var(--surface) !important;
    border: 1px solid var(--border) !important;
    border-radius: var(--r-md) !important;
    box-shadow: var(--shadow) !important;
    padding: 6px !important;
}
.dropdown-item { border-radius: var(--r-sm); color: var(--text) !important; font-size: 14px; padding: 9px var(--s-md); }
.dropdown-item:hover { background: var(--surface-variant) !important; }

/* ── Toast ───────────────────────────────────────────────────────────────── */
/*
    The app's transient confirmation. One of the only four things in the design
    that floats, so it is one of the only four that casts a shadow.
*/

.ui-toast {
    position: fixed;
    inset-block-end: var(--s-xxl);
    inset-inline-start: 50%;
    transform: translateX(-50%);
    z-index: 1080;
    display: flex; align-items: center; gap: var(--s-sm);
    max-width: min(420px, calc(100vw - var(--s-xxl) * 2));
    padding: var(--s-md) var(--s-lg);
    border-radius: var(--r-pill);
    background: var(--surface-elevated);
    border: 1px solid var(--border);
    box-shadow: var(--shadow);
    color: var(--text);
    font-size: 13px; font-weight: 600;
    animation: ui-toast-in 320ms cubic-bezier(0.215, 0.61, 0.355, 1) both;
}

.ui-toast > i { color: var(--success); }
.ui-toast.is-danger > i { color: var(--danger); }

@keyframes ui-toast-in {
    from { opacity: 0; transform: translateX(-50%) translateY(8px); }
    to   { opacity: 1; transform: translateX(-50%) translateY(0); }
}

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

/* ── Pagination ──────────────────────────────────────────────────────────── */

.ui-pagination { display: flex; gap: var(--s-xs); align-items: center; flex-wrap: wrap; }
.ui-pagination a, .ui-pagination span {
    min-inline-size: 34px; block-size: 34px;
    display: inline-flex; align-items: center; justify-content: center;
    padding: 0 var(--s-sm);
    border: 1px solid var(--border); border-radius: var(--r-sm);
    color: var(--text-secondary); font-size: 13px; font-weight: 600;
}
.ui-pagination .is-current { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
.ui-pagination .is-disabled { opacity: 0.4; pointer-events: none; }

/* ── Responsive: the sidebar becomes a drawer ────────────────────────────── */

.ui-sidebar-toggle { display: none; }
.ui-scrim { display: none; }

@media (max-width: 1024px) {
    .ui-sidebar {
        transform: translateX(calc(var(--sidebar-w) * -1));
        transition: transform 0.22s cubic-bezier(0.33, 1, 0.68, 1);
        box-shadow: var(--shadow);
    }
    [dir='rtl'] .ui-sidebar { transform: translateX(var(--sidebar-w)); }
    .ui-shell.is-drawer-open .ui-sidebar { transform: translateX(0); }

    .ui-main { margin-inline-start: 0; }
    .ui-sidebar-toggle { display: inline-flex; }

    .ui-shell.is-drawer-open .ui-scrim {
        display: block; position: fixed; inset: 0; z-index: 35;
        background: rgba(20, 20, 43, 0.5);
    }
}

@media (max-width: 640px) {
    .ui-page { padding: var(--s-xl) var(--s-lg) var(--s-xxxl); }
    .ui-topbar { padding: var(--s-md) var(--s-lg); }
    .ui-card { padding: var(--s-lg); border-radius: var(--r-md); }
    .ui-grid-3, .ui-grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .ui-h1 { font-size: 22px; }
    .ui-numeral { font-size: 26px; }

    /* Tables become stacked rows: each cell carries its header in a data
       attribute, so a wide table stays readable on a phone. */
    .ui-table.is-stacked thead { display: none; }
    .ui-table.is-stacked tbody tr {
        display: block;
        background: var(--surface);
        border: 1px solid var(--border);
        border-radius: var(--r-md);
        padding: var(--s-md);
        margin-bottom: var(--s-sm);
    }
    .ui-table.is-stacked tbody td {
        display: flex; justify-content: space-between; gap: var(--s-md);
        padding: 6px 0; border: 0; text-align: end;
    }
    .ui-table.is-stacked tbody td::before {
        content: attr(data-label);
        color: var(--text-secondary);
        font-size: 11px; font-weight: 600; text-transform: uppercase;
        letter-spacing: 0.5px; text-align: start; flex: none;
    }
    .ui-table.is-stacked tbody tr:hover td { background: transparent; }
}

/* ── Entry animation ─────────────────────────────────────────────────────── */
/*
    Every screen in the app fades and lifts its blocks in on a staggered
    ladder: fadeIn + slideY(0.08) over 320ms on easeOutCubic, delays climbing
    0, 80, 140, 200, 260, 320ms. Set --i on a child to place it on the ladder.
*/

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

.ui-enter > * {
    animation: ui-enter 320ms cubic-bezier(0.215, 0.61, 0.355, 1) both;
    animation-delay: calc(var(--i, 0) * 60ms);
}

.ui-enter > *:nth-child(1) { --i: 0; }
.ui-enter > *:nth-child(2) { --i: 1.3; }
.ui-enter > *:nth-child(3) { --i: 2.3; }
.ui-enter > *:nth-child(4) { --i: 3.3; }
.ui-enter > *:nth-child(5) { --i: 4.3; }
.ui-enter > *:nth-child(n+6) { --i: 5.3; }

@media (prefers-reduced-motion: reduce) {
    .ui-enter > * { animation: none; }
    .ui-ring-wrap.is-live::after { animation: none; }
}

/* ── Right to left: mirror icons that point somewhere ────────────────────── */

/*
 * Logical properties handle layout, but an arrow or chevron is a glyph and
 * has to be flipped explicitly. Only genuinely directional icons are listed;
 * a clock or a check must never be mirrored.
 */
[dir='rtl'] .fa-chevron-left,
[dir='rtl'] .fa-chevron-right,
[dir='rtl'] .fa-angle-left,
[dir='rtl'] .fa-angle-right,
[dir='rtl'] .fa-angles-left,
[dir='rtl'] .fa-angles-right,
[dir='rtl'] .fa-arrow-left,
[dir='rtl'] .fa-arrow-right,
[dir='rtl'] .fa-arrow-left-long,
[dir='rtl'] .fa-arrow-right-long,
[dir='rtl'] .fa-arrow-right-from-bracket,
[dir='rtl'] .fa-arrow-right-to-bracket,
[dir='rtl'] .fa-right-from-bracket,
[dir='rtl'] .fa-right-to-bracket,
[dir='rtl'] .fa-caret-left,
[dir='rtl'] .fa-caret-right,
[dir='rtl'] .fa-circle-chevron-left,
[dir='rtl'] .fa-circle-chevron-right,
[dir='rtl'] .fa-circle-arrow-left,
[dir='rtl'] .fa-circle-arrow-right,
[dir='rtl'] .fa-reply,
[dir='rtl'] .fa-share,
[dir='rtl'] .fa-paper-plane {
    transform: scaleX(-1);
}

@media print {
    .ui-sidebar, .ui-topbar, .ui-scrim { display: none !important; }
    .ui-main { margin: 0; }
}
