/* CRX Trade Inspired Theme - Professional Trading Platform Aesthetic */

/* Color Palette */
:root {
    /* Primary Colors - Deep blue/navy */
    --color-primary-dark: #1a2332;
    --color-primary: #2d3748;
    --color-primary-light: #4a5568;
    
    /* Accent Colors - Purple gradient */
    --color-accent: #8b5cf6;
    --color-accent-hover: #7c3aed;
    --color-accent-light: #a78bfa;
    --color-accent-gradient: linear-gradient(90deg, #a78bfa 0%, #8b5cf6 50%, #7c3aed 100%);
    
    /* Status Colors */
    --color-success: #10b981;
    --color-success-hover: #059669;
    --color-warning: #f59e0b;
    --color-warning-hover: #d97706;
    --color-error: #ef4444;
    --color-error-hover: #dc2626;
    --color-info: #63b3ed;
    --color-info-hover: #4a9fd8;
    --color-info-soft: rgba(99, 179, 237, 0.10);

    /* `warning-deep` is the rung BETWEEN warning and error: the hedge "grace" state, where a
       shortfall exists but the countdown has not expired. Both the borrower page and the lender
       dashboard had their own bare #fb923c for it. */
    --color-warning-deep: #fb923c;

    /* Chart series. Declared here (not as hex literals inside a chart function) so an SVG series,
       a metric card and a table cell that mean the same thing cannot drift apart. `error-deep` is
       the beyond-the-last-rung shade, one step past --color-error. The numbered slots are the
       CATEGORICAL ramp: use them for "these are different series", and the semantic
       success/warning/error vars for "this series means good/bad". lending_history_charts.js.html
       had grown a second, disagreeing palette of seven literals; these are those values, named. */
    --color-error-deep: #b91c1c;
    --color-chart-series: #8b5cf6;
    --color-chart-series-alt: #2dd4bf;
    --color-chart-series-3: #4f9dff;
    --color-chart-series-4: #f5a623;
    --color-chart-series-5: #f57bb0;

    /* Background Colors - Dark Theme */
    --color-bg-primary: #0f1419;
    --color-bg-secondary: #1a1f2e;
    --color-bg-card: #1e2532;
    --color-bg-dark: #0a0e14;
    
    /* Text Colors - Light for Dark Theme */
    --color-text-primary: #e2e8f0;
    --color-text-secondary: #f1f5f9;
    --color-text-muted: #94a3b8;
    --color-text-light: #ffffff;
    
    /* Border Colors - Dark Theme */
    --color-border: #2d3748;
    --color-border-focus: #8b5cf6;
    
    /* Shadows */
    --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
    --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
    --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
    --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);

    /* Radii & spacing scale */
    --radius-sm: 6px;
    --radius-md: 10px;
    --radius-lg: 14px;
    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --transition-fast: 120ms ease;

    /* Layout scale. --layout-max-width is the app-wide content column (header, nav and every page
       body share one .container). No breakpoint needed: a max-width is inert below its own value.
       --layout-text-max-width caps PROSE only — a wide column helps cards, not sentences. */
    --layout-max-width: 1600px;
    --layout-text-max-width: 84ch;

    /* Soft status/accent fills (card tints, badges) */
    --color-accent-soft: rgba(139, 92, 246, 0.12);
    --color-warning-soft: rgba(245, 158, 11, 0.08);
    --color-success-soft: rgba(16, 185, 129, 0.10);
    --color-error-soft: rgba(239, 68, 68, 0.10);

    /* Skeleton loading placeholders */
    --skeleton-base: var(--color-bg-card);
    --skeleton-shine: rgba(255, 255, 255, 0.06);
}

/* Reset and Base Styles */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
    background-color: var(--color-bg-primary);
    color: var(--color-text-primary);
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* Typography */
h1, h2, h3, h4, h5, h6 {
    font-weight: 600;
    color: var(--color-text-secondary);
    line-height: 1.2;
}

h1 {
    font-size: 2rem;
}

h2 {
    font-size: 1.5rem;
}

h3 {
    font-size: 1.25rem;
}

code {
    font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;
    font-size: 0.9em;
    background-color: var(--color-bg-dark);
    color: var(--color-text-light);
    padding: 0.125rem 0.375rem;
    border-radius: 0.25rem;
}

/* Layout */
.container {
    max-width: var(--layout-max-width);
    margin: 0 auto;
    padding: 20px;
}

/* Explanatory copy: a section intro under a heading, or a page footnote. Capped width so widening
   .container stretches the cards, not the sentences. */
.page-note {
    margin: 0.75rem 0;
    color: var(--color-text-muted);
    font-size: 0.85rem;
    max-width: var(--layout-text-max-width);
}

/* Centred footnote variant. Needs auto inline margins as well as text-align: the base rule caps the
   width, so it would otherwise sit against the left edge of a wide page. */
.page-note--center {
    margin-top: 1.5rem;
    margin-inline: auto;
    text-align: center;
}

/* Header */
.header {
    background: linear-gradient(135deg, var(--color-bg-dark) 0%, var(--color-primary-dark) 100%);
    color: var(--color-text-light);
    padding: 1.5rem 0;
    margin-bottom: 0;
    box-shadow: var(--shadow-md);
    border-bottom: 1px solid var(--color-border);
}

.header .container {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 1rem;
}

.header .logo {
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    color: var(--color-text-light);
    display: flex;
    align-items: center;
    margin-right: 1rem;
    text-transform: uppercase;
}

.header .logo .logo-accent {
    background: var(--color-accent-gradient);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
    font-weight: 700;
    margin-left: 0.25rem;
}

.header h1 {
    text-align: center;
    font-size: 2rem;
    font-weight: 700;
    color: var(--color-text-light);
    letter-spacing: -0.02em;
    margin: 0;
}

/* Navigation */
.nav {
    background: var(--color-bg-card);
    padding: 0.75rem 0;
    margin-bottom: 2rem;
    box-shadow: var(--shadow-sm);
    border-bottom: 1px solid var(--color-border);
}

.nav > .container > ul {
    list-style: none;
    display: flex;
    justify-content: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    padding: 0 1rem;
}

.nav > .container > ul > li > a {
    color: var(--color-text-light);
    text-decoration: none;
    padding: 0.75rem 1.25rem;
    display: block;
    white-space: nowrap;
    transition: all 0.2s ease;
    border: 1px solid var(--color-border);
    border-radius: 6px;
    font-weight: 500;
    background-color: rgba(255, 255, 255, 0.03);
}

.nav > .container > ul > li > a:hover {
    background-color: rgba(139, 92, 246, 0.15);
    border-color: var(--color-accent-light);
    color: var(--color-accent-light);
}

.nav > .container > ul > li > a.active {
    background-color: rgba(139, 92, 246, 0.2);
    border-color: var(--color-accent);
    font-weight: 600;
    color: var(--color-accent);
    box-shadow: 0 0 8px rgba(139, 92, 246, 0.3);
}

/* Navigation Dropdown */
.nav-dropdown {
    position: relative;
}

.nav-dropdown-toggle {
    cursor: pointer;
    user-select: none;
}

.nav-dropdown-menu {
    position: absolute;
    top: calc(100% + 0.25rem);
    left: 50%;
    transform: translateX(-50%);
    background: var(--color-bg-card);
    border: 1px solid var(--color-border);
    border-radius: 8px;
    box-shadow: var(--shadow-lg);
    min-width: 240px;
    list-style: none;
    padding: 0.25rem 0;
    margin: 0;
    z-index: 1000;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 0.15s ease, visibility 0.15s ease, transform 0.15s ease;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    overflow: hidden;
}

/* Create invisible bridge to maintain hover */
.nav-dropdown::before {
    content: '';
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    width: 100%;
    height: 0.25rem;
    background: transparent;
    z-index: 999;
    display: none;
}

.nav-dropdown:hover::before {
    display: block;
}

.nav-dropdown:hover .nav-dropdown-menu,
.nav-dropdown:focus-within .nav-dropdown-menu {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: translateX(-50%) translateY(0);
}

.nav-dropdown-menu li {
    margin: 0;
    display: block;
    width: 100%;
}

.nav-dropdown-menu li + li {
    border-top: 1px solid rgba(148, 163, 184, 0.12);
}

.nav-dropdown-menu a {
    width: 100%;
    padding: 0.8rem 1rem;
    display: block;
    color: var(--color-text-primary);
    text-decoration: none;
    background: transparent;
    border: none;
    border-radius: 0;
    box-shadow: none;
    font-weight: 400;
    font-size: 0.9rem;
    white-space: nowrap;
    text-align: left;
    line-height: 1.2;
}

.nav-dropdown-menu a:hover {
    background-color: rgba(139, 92, 246, 0.1);
    color: var(--color-accent-light);
}

/* Cards */
.card {
    background: var(--color-bg-card);
    border-radius: 12px;
    box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3), 0 2px 4px -1px rgba(0, 0, 0, 0.2);
    padding: 1.5rem;
    margin-bottom: 1.5rem;
    border: 1px solid var(--color-border);
    transition: box-shadow 0.2s ease, transform 0.2s ease, border-color 0.2s ease;
}

.card:hover {
    box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -2px rgba(0, 0, 0, 0.3);
    border-color: var(--color-accent);
}

.card h2 {
    color: var(--color-text-secondary);
    margin-bottom: 1rem;
    border-bottom: 2px solid var(--color-accent);
    padding-bottom: 0.75rem;
    font-weight: 600;
}

/* Forms */
.form-group {
    margin-bottom: 1.25rem;
}

/* .form-label: identical presentation for a heading over something that is NOT a labelable
   form control (a read-only value, a button group, a JS-mounted widget). A <label> there is
   an accessibility defect — it promises screen readers an association it can't deliver — so
   those headings are <span class="form-label"> instead, paired with role="group"/aria where
   the grouping matters. */
.form-group label,
.form-group .form-label {
    display: block;
    margin-bottom: 0.5rem;
    font-weight: 600;
    color: var(--color-text-secondary);
    font-size: 0.9rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.form-group input,
.form-group select,
.form-group textarea,
.form-control {
    width: 100%;
    padding: 0.75rem 1rem;
    border: 1px solid var(--color-border);
    border-radius: 6px;
    font-size: 1rem;
    transition: all 0.2s ease;
    background-color: var(--color-bg-secondary);
    color: var(--color-text-primary);
}

.form-group input:focus,
.form-group select:focus,
.form-group textarea:focus,
.form-control:focus {
    outline: none;
    border-color: var(--color-border-focus);
    box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.1);
}

.form-group input:disabled,
.form-group select:disabled {
    background-color: var(--color-bg-dark);
    cursor: not-allowed;
    opacity: 0.5;
    border-color: var(--color-border);
}

.form-group small {
    display: block;
    margin-top: 0.25rem;
    color: var(--color-text-muted);
    font-size: 0.875rem;
}

/* Buttons */
.btn {
    background: var(--color-accent);
    color: var(--color-text-light);
    border: none;
    padding: 0.75rem 1.5rem;
    border-radius: 6px;
    cursor: pointer;
    font-size: 1rem;
    font-weight: 500;
    transition: all 0.2s ease;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    text-decoration: none;
    box-shadow: 0 2px 4px rgba(139, 92, 246, 0.3);
}

.btn:hover:not(:disabled) {
    background: var(--color-accent-hover);
    box-shadow: 0 4px 8px rgba(139, 92, 246, 0.4);
    transform: translateY(-1px);
}

.btn:active:not(:disabled) {
    transform: translateY(0);
}

.btn:disabled {
    background: var(--color-primary-light);
    cursor: not-allowed;
    opacity: 0.5;
    transform: none;
    box-shadow: none;
}

.btn-success {
    background: var(--color-success);
}

.btn-success:hover:not(:disabled) {
    background: var(--color-success-hover);
}

.btn-warning {
    background: var(--color-warning);
}

.btn-warning:hover:not(:disabled) {
    background: var(--color-warning-hover);
}

.btn-danger {
    background: var(--color-error);
}

.btn-danger:hover:not(:disabled) {
    background: var(--color-error-hover);
}

.btn-secondary {
    background: var(--color-primary);
}

.btn-secondary:hover:not(:disabled) {
    background: var(--color-primary-light);
}

/* Alerts */
.alert {
    padding: 1rem 1.25rem;
    border-radius: 8px;
    margin-bottom: 1rem;
    border-left: 4px solid;
    box-shadow: var(--shadow-sm);
}

.alert-success {
    background: rgba(16, 185, 129, 0.15);
    color: #6ee7b7;
    border-color: var(--color-success);
}

.alert-error {
    background: rgba(239, 68, 68, 0.15);
    color: #fca5a5;
    border-color: var(--color-error);
}

.alert-info {
    background: rgba(139, 92, 246, 0.15);
    color: #c4b5fd;
    border-color: var(--color-accent);
}

.alert-warning {
    background: rgba(245, 158, 11, 0.15);
    color: #fcd34d;
    border-color: var(--color-warning);
}

/* Inline in-card notice ("callout"): a fully-bordered, denser sibling of .alert for a notice that
   sits INSIDE a card next to the thing it warns about, rather than at the top of the page.
   Three pages had each grown their own copy of this exact box with bare hex literals —
   exchanges.html's .subaccount-warning and .margin-funding-notice, vault.html's
   .vault-deposit-warning — at three slightly different densities. One family, in the design
   system, so a warning on the funding page and a warning on the vault page look like the same
   product making the same kind of statement. */
.callout {
    margin-top: 0.75rem;
    padding: 0.75rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    line-height: 1.4;
}

.callout strong {
    display: block;
    margin-bottom: 0.25rem;
}

.callout small {
    display: block;
    line-height: 1.4;
}

.callout--warning {
    background: var(--color-warning-soft);
    border-color: var(--color-warning);
    color: #fcd34d;
}

.callout--error {
    background: var(--color-error-soft);
    border-color: var(--color-error);
    color: #fca5a5;
}

.callout--info {
    background: var(--color-info-soft);
    border-color: var(--color-info);
    color: #c4b5fd;
}

/* Action-needed variant: an inline single-line notice (no block <strong> heading break). */
.callout--inline {
    padding: 0.6rem 0.85rem;
    font-size: 0.85rem;
}

.callout--inline strong {
    display: inline;
    margin-bottom: 0;
}

@media (max-width: 768px) {
    .callout {
        padding: 0.5rem;
    }

    .callout small {
        font-size: 0.75rem;
    }
}

/* Toast notifications — floating, fixed position */
.toast-container {
    position: fixed;
    top: 1rem;
    right: 1rem;
    z-index: 9999;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    max-width: 450px;
    pointer-events: none;
}

.toast {
    padding: 0.875rem 1.25rem;
    border-radius: 8px;
    border-left: 4px solid;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
    pointer-events: auto;
    cursor: pointer;
    animation: toast-in 0.3s ease-out;
    transition: opacity 0.3s ease, transform 0.3s ease;
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 0.75rem;
    word-break: break-word;
}

.toast:hover {
    opacity: 0.9;
}

.toast-message {
    flex: 1;
}

.toast-actions {
    flex-shrink: 0;
    display: flex;
    gap: 0.25rem;
    align-items: center;
}

.toast-btn {
    opacity: 0.6;
    font-size: 1.1rem;
    line-height: 1;
    cursor: pointer;
    background: none;
    border: none;
    color: inherit;
    padding: 0.1rem 0.2rem;
}

.toast-btn:hover {
    opacity: 1;
}

.toast.toast-removing {
    opacity: 0;
    transform: translateX(100%);
}

/* Dedup "bump": re-triggered on a repeat toast instead of stacking a duplicate */
.toast.toast-bump {
    animation: toast-bump 0.3s ease-out;
}

@keyframes toast-bump {
    0% { transform: scale(1); }
    35% { transform: scale(1.03); }
    100% { transform: scale(1); }
}

.toast-success {
    background: rgba(16, 185, 129, 0.95);
    color: #fff;
    border-color: #10b981;
}

.toast-error {
    background: rgba(239, 68, 68, 0.95);
    color: #fff;
    border-color: #ef4444;
}

.toast-info {
    background: rgba(139, 92, 246, 0.95);
    color: #fff;
    border-color: #8b5cf6;
}

.toast-warning {
    background: rgba(245, 158, 11, 0.95);
    color: #fff;
    border-color: #f59e0b;
}

@keyframes toast-in {
    from {
        opacity: 0;
        transform: translateX(100%);
    }
    to {
        opacity: 1;
        transform: translateX(0);
    }
}

/* Balance Grid */
.balance-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    gap: 1.25rem;
    margin-bottom: 2rem;
}

.balance-card {
    background: var(--color-bg-secondary);
    border: 1px solid var(--color-border);
    border-radius: 10px;
    padding: 1.25rem;
    text-align: center;
    transition: all 0.2s ease;
}

.balance-card:hover {
    border-color: var(--color-accent);
    box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3), 0 2px 4px -1px rgba(0, 0, 0, 0.2);
    transform: translateY(-2px);
    background: var(--color-bg-card);
}

.balance-card h3 {
    color: var(--color-text-muted);
    margin-bottom: 0.75rem;
    font-size: 0.875rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-weight: 600;
}

.balance-amount {
    font-size: 1.75rem;
    font-weight: 700;
    color: var(--color-text-secondary);
    margin-bottom: 0.75rem;
    font-variant-numeric: tabular-nums;
}

.balance-actions {
    display: flex;
    gap: 0.5rem;
    justify-content: center;
    flex-wrap: wrap;
}

/* Tables */
table {
    width: 100%;
    border-collapse: collapse;
    background: var(--color-bg-card);
    border-radius: 8px;
    overflow: hidden;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
    border: 1px solid var(--color-border);
}

table thead {
    background: var(--color-bg-dark);
    color: var(--color-text-light);
}

table th {
    padding: 1rem;
    text-align: left;
    font-weight: 600;
    text-transform: uppercase;
    font-size: 0.875rem;
    letter-spacing: 0.05em;
}

table td {
    padding: 1rem;
    border-top: 1px solid var(--color-border);
}

table tbody tr {
    transition: background-color 0.2s ease;
}

table tbody tr:hover {
    background-color: var(--color-bg-secondary);
}

table tbody tr:last-child td {
    border-bottom: none;
}

/* Tabs */
.tabs {
    display: flex;
    gap: 0;
    border-bottom: 2px solid var(--color-border);
    margin-bottom: 1.5rem;
    overflow-x: auto;
}

.tab {
    padding: 0.75rem 1.5rem;
    background: none;
    border: none;
    border-bottom: 3px solid transparent;
    cursor: pointer;
    font-size: 1rem;
    font-weight: 500;
    color: var(--color-text-muted);
    transition: all 0.2s ease;
    white-space: nowrap;
}

.tab:hover {
    color: var(--color-text-primary);
    background-color: var(--color-bg-secondary);
}

.tab.active {
    color: var(--color-accent);
    border-bottom-color: var(--color-accent);
    font-weight: 600;
}

.tab-content {
    display: none;
}

.tab-content.active {
    display: block;
}

/* Compact tab variant for dense dashboards (borrower risk page, lender dashboard) */
.tabs--compact {
    margin-bottom: var(--space-4);
}

.tabs--compact .tab {
    padding: 0.5rem 0.9rem;
    font-size: 0.9rem;
}

.tab:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: -2px;
}

/* Pill tab variant: rounded standalone buttons instead of underlined tabs, with the active
   tab filled in solid accent. Used by pages that pick between a small set of top-level venues
   (e.g. the exchanges page's exchange picker) rather than switching content sub-sections. */
.tabs--pills {
    gap: 0.5rem;
    border-bottom: none;
    margin-bottom: 1rem;
}

.tabs--pills .tab {
    padding: 0.6rem 1.4rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-bg-secondary);
    transition: background-color var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);
}

.tabs--pills .tab:hover {
    color: var(--color-text-primary);
    border-color: var(--color-accent-light);
    background-color: var(--color-bg-secondary);
}

.tabs--pills .tab.active {
    background-color: var(--color-accent);
    border-color: var(--color-accent);
    color: #fff;
    font-weight: 600;
}

.tab-badge {
    display: inline-block;
    margin-left: 0.35rem;
    padding: 0 0.45rem;
    border-radius: 10px;
    background: var(--color-accent-soft);
    color: var(--color-accent-light);
    font-size: 0.75em;
    font-weight: 600;
    line-height: 1.5;
}

/* Metric cards (dashboard stat tiles) */
.metric-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}

.metric-card {
    padding: 0.65rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-bg-secondary);
    transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.metric-card:hover {
    border-color: var(--color-primary-light);
    box-shadow: var(--shadow-md);
}

.metric-card--important {
    border-color: var(--color-warning);
    background: var(--color-warning-soft);
}

.metric-card .metric-label {
    display: flex;
    align-items: center;
    gap: 0.3rem;
    color: var(--color-text-muted);
    font-size: 0.8em;
}

.metric-card .metric-value {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    margin-top: 0.15rem;
    word-break: break-word;
}

.metric-card .metric-subtext {
    color: var(--color-text-muted);
    font-size: 0.78em;
    margin-top: 0.15rem;
}

/* Pinned metric strip (the mini risk summary shown on non-summary tabs). Sticky so the overview
   stays visible while scrolling long tab bodies; cards WRAP responsively instead of scrolling
   horizontally. */
.metric-card-row {
    position: sticky;
    top: 0;
    z-index: 5; /* keep BELOW tooltips/toasts */
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    padding: var(--space-1) 0 var(--space-2);
    margin-bottom: var(--space-3);
    /* No wrapper border/box — just the cards. Background matches the enclosing .card container
       (invisible at rest) while staying opaque so content doesn't bleed through the gaps while
       the strip is stuck during scroll. */
    background: var(--color-bg-card);
}

/* Plain value cards compress hard so the whole strip fits one line; meter cards keep room.
   Content is vertically centered so short cards don't leave dead space below (flex stretches
   every card to the height of the tallest, i.e. the meter cards). */
.metric-card-row .metric-card {
    flex: 1 1 96px;
    min-width: 0;
    padding: 0.4rem 0.5rem;
    display: flex;
    flex-direction: column;
    justify-content: center;
}

.metric-card-row .metric-card:has(.threshold-meter) {
    flex: 1.8 1 150px;
}

.metric-card-row .metric-card .metric-label {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    display: block;
}

.metric-card--compact {
    padding: 0.4rem 0.55rem;
}

.metric-card--compact .metric-label {
    font-size: 0.7em;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    white-space: nowrap;
}

.metric-card--compact .metric-value {
    font-size: 0.95em;
    /* Long status strings ("reduction required") must wrap to fit the narrow strip cards
       instead of clipping; short numeric values are unaffected. */
    white-space: normal;
    overflow-wrap: anywhere;
    line-height: 1.15;
}

.metric-value--success { color: var(--color-success); }
.metric-value--warning { color: var(--color-warning); }
.metric-value--error { color: var(--color-error); }

/* Before/after line inside a .metric-card: the headline value is always the REAL, current figure;
   this line is the only place a hypothetical (stressed / projected) value may appear, and it is
   always named. Both risk-analytics tabs render it through one helper
   (renderShockDeltaCardHtml in includes/loan_shocks.js.html) so the two tabs cannot describe the
   same before/after with opposite conventions. */
.metric-card .metric-delta {
    font-size: 0.78em;
    margin-top: 0.15rem;
    color: var(--color-text-muted);
}

.metric-delta--worse { color: var(--color-error); }
.metric-delta--better { color: var(--color-success); }
/* A shock that moved the number but not the DISPLAYED number: neither good nor bad news, and it
   must not be coloured as though something happened. */
.metric-delta--neutral { color: var(--color-text-muted); }

/* Hero cards: the handful of decision-driving metrics at the top of the Summary tab. */
.metric-card--hero {
    padding: 0.85rem 0.9rem;
    background: var(--color-bg-card);
    border-left: 3px solid var(--color-accent);
}

.metric-card--hero .metric-value {
    font-size: 1.35rem;
    margin-top: 0.25rem;
}

.metric-card--hero .metric-subtext,
.metric-card--compact .metric-subtext {
    /* One line, always: a long subtext must never stretch the row (full text lives on the tooltip). */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Threshold meter: slim bar + ticks showing a value against its escalation ladder. */
.threshold-meter {
    position: relative;
    margin-top: 0.45rem;
    cursor: help;
}

/* Hover popup: the full color-coded ladder, anchored under the bar. Shown on CARD hover (not
   just bar hover) after a short delay, so levels appear by default without flashing while the
   pointer merely passes through the grid. */
.threshold-meter-popup {
    display: inline-flex;
    opacity: 0;
    visibility: hidden;
    transition: opacity 120ms ease 250ms, visibility 0s linear 370ms;
    position: absolute;
    z-index: 1000;
    top: calc(100% + 6px);
    left: 0;
    min-width: 190px;
    padding: 0.55rem 0.65rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-bg-primary);
    box-shadow: var(--shadow-lg);
}

.metric-card:hover .threshold-meter-popup,
.threshold-meter:hover .threshold-meter-popup {
    opacity: 1;
    visibility: visible;
    transition-delay: 250ms;
}

/* Ladder legend rows: swatch + label + value. Used in the meter popup and ⓘ tooltips. */
.threshold-legend {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    width: 100%;
}

.threshold-legend-row {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    font-size: 0.78rem;
    line-height: 1.2;
    white-space: nowrap;
}

.threshold-legend-row--current {
    font-weight: 700;
}

.threshold-legend-swatch {
    flex: 0 0 auto;
    width: 8px;
    height: 8px;
    border-radius: 2px;
}

.threshold-legend-label {
    color: var(--color-text-muted);
    text-transform: capitalize;
}

.threshold-legend-row--current .threshold-legend-label {
    color: var(--color-text-primary);
}

.threshold-legend-value {
    margin-left: auto;
    font-variant-numeric: tabular-nums;
}

.threshold-tooltip-content {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.threshold-tooltip-text {
    display: block;
}

.threshold-meter-track {
    position: relative;
    height: 6px;
    border-radius: 3px;
    background: var(--color-primary-dark);
    border: 1px solid var(--color-border);
    overflow: visible;
}

.threshold-meter-fill {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    border-radius: 3px;
    transition: width var(--transition-fast);
}

.threshold-meter-fill--success { background: var(--color-success); }
.threshold-meter-fill--warning { background: var(--color-warning); }
.threshold-meter-fill--error { background: var(--color-error); }

.threshold-meter-dot {
    position: absolute;
    left: 3px;
    top: 50%;
    transform: translateY(-50%);
    width: 5px;
    height: 5px;
    border-radius: 50%;
}

.threshold-meter-tick {
    position: absolute;
    top: -3px;
    width: 2px;
    height: 12px;
    background: var(--color-text-muted);
    border-radius: 1px;
    opacity: 0.8;
}

.threshold-meter-caption {
    margin-top: 0.3rem;
    font-size: 0.72em;
    color: var(--color-text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    /* Classic "hover for details" affordance: dotted underline invites the ladder popup. */
    width: fit-content;
    max-width: 100%;
    border-bottom: 1px dotted var(--color-text-muted);
    padding-bottom: 1px;
}

/* Compact themed select (portfolio switcher, history portfolio picker) — matches the dark form
   inputs but sized for inline header use, with a custom chevron. */
.themed-select {
    appearance: none;
    -webkit-appearance: none;
    padding: 0.45rem 2rem 0.45rem 0.75rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background-color: var(--color-bg-secondary);
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%2394a3b8' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.7rem center;
    color: var(--color-text-primary);
    font-size: 0.9rem;
    line-height: 1.3;
    max-width: 100%;
    cursor: pointer;
    transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.themed-select:hover {
    border-color: var(--color-primary-light);
}

.themed-select:focus {
    outline: none;
    border-color: var(--color-border-focus);
    box-shadow: 0 0 0 3px var(--color-accent-soft);
}

/* Virtualized searchable picker (portfolio_picker.js) — trigger reuses .themed-select. */
.picker {
    position: relative;
    display: inline-block;
    min-width: 240px;
    max-width: 100%;
}

.picker-trigger {
    width: 100%;
    text-align: left;
    display: flex;
    align-items: center;
}

.picker-trigger-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    flex: 1;
    min-width: 0;
}

.picker-panel {
    position: absolute;
    z-index: 1000;
    top: calc(100% + 4px);
    left: 0;
    min-width: 100%;
    width: max-content;
    max-width: min(480px, 90vw);
    background-color: var(--color-bg-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
    overflow: hidden;
}

.picker-search {
    width: 100%;
    box-sizing: border-box;
    padding: 0.5rem 0.75rem;
    background-color: var(--color-bg-secondary);
    border: none;
    border-bottom: 1px solid var(--color-border);
    color: var(--color-text-primary);
    font-size: 0.9rem;
}

.picker-search:focus {
    outline: none;
    box-shadow: inset 0 -2px 0 var(--color-primary-light);
}

.picker-list {
    position: relative;
    overflow-y: auto;
}

.picker-list-spacer {
    position: relative;
}

.picker-option {
    position: absolute;
    left: 0;
    right: 0;
    display: flex;
    align-items: center;
    padding: 0 0.75rem;
    box-sizing: border-box;
    color: var(--color-text-primary);
    font-size: 0.9rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    cursor: pointer;
}

.picker-option:hover,
.picker-option--active {
    background-color: var(--color-accent-soft);
}

.picker-option-check {
    width: 1.1rem;
    flex: 0 0 1.1rem;
    color: var(--color-primary-light);
    font-weight: 700;
}

.picker-option-label {
    overflow: hidden;
    text-overflow: ellipsis;
}

.picker-option--selected {
    color: var(--color-text-primary);
    font-weight: 600;
    background-color: var(--color-accent-soft);
    box-shadow: inset 3px 0 0 var(--color-primary-light);
}

.picker-list-status {
    padding: 0.5rem 0.75rem;
    color: var(--color-text-muted);
    font-size: 0.85rem;
}

/* Inline header stat (e.g. Last 24h PnL on the portfolio-selector line). */
.header-inline-stat {
    display: inline-flex;
    align-items: baseline;
    gap: 0.4rem;
    margin-left: auto;
}

.header-inline-stat .strip-label {
    font-size: 0.7rem;
}

.header-inline-stat .strip-value {
    font-size: 1.05rem;
}

/* Labeled metric groups: scan by category instead of hunting through a flat grid. */
.metric-section {
    margin-bottom: var(--space-3);
}

.metric-section-title {
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--color-text-muted);
    margin: var(--space-4) 0 var(--space-2);
    padding-bottom: var(--space-1);
    border-bottom: 1px solid var(--color-border);
}

/* Pinned mini-summary strip (shown while a non-summary tab is active) */
.summary-strip {
    position: sticky;
    top: 0;
    z-index: 5; /* keep BELOW tooltips/toasts */
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
    align-items: center;
    padding: var(--space-2) var(--space-3);
    background: var(--color-bg-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-sm);
    margin-bottom: var(--space-4);
}

.strip-item {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.strip-label {
    font-size: 0.7em;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-text-muted);
    white-space: nowrap;
}

.strip-value {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.strip-value--success { color: var(--color-success); }
.strip-value--warning { color: var(--color-warning); }
.strip-value--error { color: var(--color-error); }

/* Loading States */
.loading {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 2rem;
    text-align: center;
}

.loading p {
    margin-top: 1rem;
    color: var(--color-text-muted);
}

/* Utility Classes */
.hidden {
    display: none !important;
}

.text-center {
    text-align: center;
}

.text-right {
    text-align: right;
}

.text-left {
    text-align: left;
}

.mt-1 { margin-top: 0.5rem; }
.mt-2 { margin-top: 1rem; }
.mt-3 { margin-top: 1.5rem; }
.mb-1 { margin-bottom: 0.5rem; }
.mb-2 { margin-bottom: 1rem; }
.mb-3 { margin-bottom: 1.5rem; }

/* Slider Input */
input[type="range"] {
    width: 100%;
    height: 6px;
    border-radius: 3px;
    background: var(--color-bg-secondary);
    outline: none;
    -webkit-appearance: none;
}

input[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: var(--color-accent);
    cursor: pointer;
    box-shadow: var(--shadow-sm);
    transition: all 0.2s ease;
}

input[type="range"]::-webkit-slider-thumb:hover {
    background: var(--color-accent-hover);
    transform: scale(1.1);
}

input[type="range"]::-moz-range-thumb {
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: var(--color-accent);
    cursor: pointer;
    border: none;
    box-shadow: var(--shadow-sm);
    transition: all 0.2s ease;
}

input[type="range"]::-moz-range-thumb:hover {
    background: var(--color-accent-hover);
    transform: scale(1.1);
}

/* Progress Indicators */
.progress-bar {
    width: 100%;
    height: 8px;
    background: var(--color-bg-secondary);
    border-radius: 4px;
    overflow: hidden;
}

.progress-bar-fill {
    height: 100%;
    background: var(--color-accent-gradient);
    transition: width 0.3s ease;
    border-radius: 4px;
}

/* Status Badges */
.badge {
    display: inline-block;
    padding: 0.25rem 0.75rem;
    border-radius: 12px;
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.badge-success {
    background: rgba(16, 185, 129, 0.2);
    color: #6ee7b7;
    border: 1px solid var(--color-success);
}

.badge-warning {
    background: rgba(245, 158, 11, 0.2);
    color: #fcd34d;
    border: 1px solid var(--color-warning);
}

.badge-error {
    background: rgba(239, 68, 68, 0.2);
    color: #fca5a5;
    border: 1px solid var(--color-error);
}

.badge-info {
    background: rgba(139, 92, 246, 0.2);
    color: #c4b5fd;
    border: 1px solid var(--color-accent);
}

/* Horizontal-scroll container for a wide table. Was an inline
   `{ overflowX: 'auto', marginTop: '0.75rem' }` object retyped at six call sites, including inside
   common.js's own renderSimpleTable factory. */
.table-scroll {
    overflow-x: auto;
    margin-top: 0.75rem;
}

/* Separator above a subsection inside a card (a rule plus the matching space). Was an inline
   three-property object retyped at four call sites across the loan pages and their includes. */
.section-divider {
    margin-top: 1rem;
    padding-top: 1rem;
    border-top: 1px solid var(--color-border);
}

/* Hedge-state pill (includes/borrowed_asset_hedge.js.html). An outlined chip whose border and text
   colour are the hedge severity, set inline because the colour IS the datum. Geometry lives here
   because both loan pages had retyped these six declarations at every call site. */
.hedge-pill {
    display: inline-block;
    border: 1px solid currentColor;
    border-radius: 999px;
    padding: 0.1rem 0.5rem;
    font-size: 0.78rem;
    font-weight: 700;
    white-space: nowrap;
}

.hedge-pill-row {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    margin-top: 0.4rem;
}

/* Neutral/inactive badge: a state with no verdict attached (a deactivated API token, an
   unrecognised status). Deliberately muted — never a colour that implies good or bad. */
.badge-muted {
    background: rgba(148, 163, 184, 0.18);
    color: var(--color-text-muted);
    border: 1px solid var(--color-text-muted);
}

.badge-processing {
    background: rgba(99, 102, 241, 0.2);
    color: #a5b4fc;
    border: 1px solid #6366f1;
}

/* Account Link Styling */
.account-link {
    color: var(--color-accent);
    text-decoration: none;
    display: inline-block;
    transition: color 0.2s ease;
}

.account-link:hover {
    color: var(--color-accent-light);
    text-decoration: underline;
}

/* Small staff-only admin hop beside exchange-account labels in shared tables. Keep its density
   in the design system so the borrower/lender account renderers do not hand-roll spacing. */
.exchange-account-admin-link {
    margin-left: 0.45rem;
    font-size: 0.78em;
}

.account-address {
    color: var(--color-accent);
    text-decoration: underline;
    cursor: pointer;
    font-size: 0.9em;
    word-break: break-all;
    display: inline-block;
    max-width: 100%;
    background-color: transparent;
    padding: 0;
}

.account-link-hint {
    color: var(--color-text-muted);
    font-size: 0.875rem;
}

/* Balance Info Styling */
.balance-info {
    margin-bottom: 0.5rem;
    padding: 0.75rem;
    background: var(--color-bg-secondary);
    border: 1px solid var(--color-border);
    border-radius: 6px;
    color: var(--color-text-primary);
}

.balance-info strong {
    color: var(--color-text-secondary);
}

.balance-info-text {
    color: var(--color-text-muted);
    display: block;
    margin-top: 0.25rem;
    font-size: 0.875rem;
}

/* Address Display Styling */
.address-display {
    background: var(--color-bg-secondary);
    color: var(--color-text-primary);
    padding: 0.75rem;
    border: 1px solid var(--color-border);
    border-radius: 6px;
    display: block;
    margin-top: 0.5rem;
    font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', monospace;
    font-size: 0.9em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    word-break: break-all;
    transition: border-color 0.2s ease, background-color 0.2s ease;
}

.address-display:hover {
    border-color: var(--color-accent);
    background: var(--color-bg-card);
}

/* Modal dialogs (shared UI primitive — see ui.js showModal) */
.modal {
    background: var(--color-bg-card);
    color: var(--color-text-primary);
    /* Center explicitly: the global * { margin: 0 } reset wipes the UA stylesheet's
       margin:auto that would otherwise center a <dialog> in the top layer. */
    position: fixed;
    inset: 0;
    margin: auto;
    height: fit-content;
    max-height: calc(100vh - 4rem);
    overflow-y: auto;
    /* Override the UA <dialog> border/padding with the theme's card styling. */
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-xl);
    padding: 1.5rem;
    max-width: 480px;
    width: calc(100% - 2rem);
    animation: modal-pop-in 0.16s ease-out;
}

@keyframes modal-pop-in {
    from {
        opacity: 0;
        transform: scale(0.97) translateY(-6px);
    }
    to {
        opacity: 1;
        transform: scale(1) translateY(0);
    }
}

.modal::backdrop {
    background: rgba(10, 14, 20, 0.7);
}

/* Fallback centering for browsers without <dialog>.showModal() support. */
.modal--fallback {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 10000;
}

.modal-title {
    margin-bottom: 0.75rem;
}

.modal-body {
    color: var(--color-text-muted);
    margin-bottom: 1rem;
    /* Messages migrated from confirm() contain \n\n paragraph breaks — preserve them. */
    white-space: pre-line;
}

.modal-form {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.modal-field {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.modal-field-label {
    font-weight: 600;
    color: var(--color-text-secondary);
    font-size: 0.9rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.modal-field input,
.modal-field textarea {
    width: 100%;
    padding: 0.75rem 1rem;
    border: 1px solid var(--color-border);
    border-radius: 6px;
    font-size: 1rem;
    transition: all 0.2s ease;
    background-color: var(--color-bg-secondary);
    color: var(--color-text-primary);
}

.modal-field input:focus,
.modal-field textarea:focus {
    outline: none;
    border-color: var(--color-border-focus);
    box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.1);
}

.modal-field-error {
    color: var(--color-error);
    font-size: 0.85rem;
    min-height: 1em;
}

.modal-footer {
    display: flex;
    gap: var(--space-2);
    justify-content: flex-end;
    margin-top: var(--space-4);
}

/* Card-header action link (e.g. Transfers → "Open allocation planner"): a quiet
   pill, not a raw browser-blue anchor.

   `display: inline-block` is load-bearing: vertical padding on an `inline` box does not grow the
   line box, so inside the h3's 1.2 line-height the pill overflowed 2.2px below its heading and drew
   over the Transfers tab strip. vertical-align centres it on the heading text. */
.card-header-link {
    display: inline-block;
    vertical-align: middle;
    font-size: 0.8rem;
    font-weight: 500;
    margin-left: 0.75rem;
    padding: 0.2rem 0.6rem;
    border: 1px solid var(--color-border);
    border-radius: 999px;
    color: var(--color-accent, #8b5cf6);
    text-decoration: none;
    white-space: nowrap;
    transition: background 0.15s ease, border-color 0.15s ease;
}
.card-header-link:hover {
    background: var(--color-accent-soft);
    border-color: var(--color-accent, #8b5cf6);
    color: var(--color-accent, #8b5cf6);
    text-decoration: none;
}

/* Inline link inside running text. There is no global `a` colour here, so an unclassed content
   anchor inherits the browser default #0000EE — 1.97:1 against this dark background, i.e. invisible.
   --color-info is 8.11:1 and already the product's "go read this other page" colour. Keep the
   underline: colour alone is not an accessible affordance for a link in prose. */
.inline-link {
    color: var(--color-info);
    text-decoration: underline;
    text-underline-offset: 0.15em;
    font-weight: 500;
}

.inline-link:hover {
    color: var(--color-info-hover);
    text-decoration-thickness: 2px;
}

.inline-link:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
}

/* Inline action error (surfaced next to a button by runAction) */
.action-error {
    color: var(--color-error);
    font-size: 0.85rem;
    margin-top: var(--space-1);
}

/* Shared component classes (extracted from common.js inline styles) */

/* renderTooltipIcon: "i" badge + hover/focus bubble */
.tooltip-icon {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1rem;
    height: 1rem;
    margin-left: 0.3rem;
    border: 1px solid var(--color-info, #63b3ed);
    border-radius: 50%;
    cursor: help;
    color: var(--color-info, #63b3ed);
    font-size: 0.72rem;
    font-weight: 700;
    line-height: 1;
}

.tooltip-bubble {
    /* Base hidden state — renderTooltipIcon toggles this via inline bubble.style.display on
       hover/focus, and inline style always wins over this class rule (no !important needed). */
    display: none;
    position: absolute;
    z-index: 1000;
    top: 1.25rem;
    left: 0;
    width: min(280px, 70vw);
    padding: 0.55rem 0.65rem;
    border: 1px solid var(--color-border, #333);
    border-radius: 6px;
    background: var(--color-bg-primary, #10101a);
    color: var(--color-text, #fff);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
    font-size: 0.78rem;
    font-weight: 400;
    line-height: 1.35;
    text-align: left;
}

/* createAccordionSection */
.accordion {
    margin-top: 0.75rem;
    border: 1px solid var(--color-border, #333);
    border-radius: 6px;
    background: var(--color-bg-secondary, #1a1a2e);
    overflow: hidden;
}

.accordion-summary {
    cursor: pointer;
    padding: 0.75rem;
    list-style: none;
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 0.75rem;
    align-items: center;
}

.accordion-subtitle {
    color: var(--color-text-muted, #999);
    font-size: 0.82rem;
    margin-top: 0.2rem;
}

.accordion-badge {
    color: var(--color-text-muted, #999);
    font-size: 0.82rem;
    text-align: right;
}

.accordion-body {
    padding: 0 0.75rem 0.75rem;
    border-top: 1px solid var(--color-border, #333);
}

/* createStatusBadge: colored bold text (NOT the .badge pill family) — color stays inline
   since callers pass arbitrary raw colors. */
.status-text {
    font-weight: bold;
    font-size: 0.85em;
}

/* createPaginationControls */
.pagination-footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.75rem;
    margin-top: 0.75rem;
    flex-wrap: wrap;
}

.pagination-summary {
    color: var(--color-text-muted, #999);
    font-size: 0.85rem;
}

.pagination-actions {
    display: flex;
    gap: 0.5rem;
    align-items: center;
}

.pagination-btn {
    padding: 0.35rem 0.7rem;
    font-size: 0.85rem;
}

/* PaginatedTableRenderer.render */
.data-table {
    width: 100%;
    border-collapse: collapse;
    table-layout: auto;
    margin-top: 0.5rem;
}

.data-table thead tr {
    border-bottom: 1px solid var(--color-border, #333);
}

.data-table th {
    /* Per-column align/nowrap/style overrides stay inline (dynamic); only the static padding
       lives here. */
    padding: 0.4rem 0.5rem;
}

/* Transfer cluster: renderTransferSteps / renderTransferFailureNotice / renderTransferCard.
   Dynamic status colors (transferStepStatusColor / transferStatusColor) stay inline. */
.transfer-steps {
    margin-top: 0.5rem;
}

.transfer-step-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin: 0.25rem 0;
}

.transfer-step-dot {
    margin-right: 0.5rem;
}

/* How long a step has been waiting / how long it took. A running step is emphasised: that is
   the number an operator is asking about when a transfer looks stuck. */
.transfer-step-timing {
    color: #666;
    white-space: nowrap;
}

.transfer-step-timing-running {
    color: #8a5a00;
    font-weight: 600;
}

/* On-chain hash link (mempool.space / Etherscan / Arbiscan / Hypurrscan). */
.transfer-step-tx,
.vault-tx-hash {
    color: var(--color-primary);
    font-size: 0.8em;
    text-decoration: none;
    white-space: nowrap;
}

.transfer-step-tx:hover,
.vault-tx-hash:hover {
    text-decoration: underline;
}

/* Hash we hold but cannot route to an explorer: selectable text, no link. */
.transfer-step-tx-unlinked {
    color: var(--color-text-muted, #666);
    cursor: text;
    text-decoration: none;
    user-select: all;
}

/* A step that moves funds on-chain and has no hash. Absence is ambiguous while the step runs
   and alarming once it has finished — the finished form is the one that cannot be looked up. */
.transfer-step-tx-missing {
    color: #8a5a00;
    white-space: nowrap;
}

.transfer-step-tx-missing-final {
    color: #8f1d12;
    font-weight: 600;
}

.transfer-failure {
    background: #fff4f2;
    border: 1px solid #f3b7ae;
    border-radius: 4px;
    color: #8f1d12;
    margin: 0.75rem 0;
    padding: 0.75rem;
}

.transfer-card {
    border: 1px solid #ddd;
    border-radius: 4px;
    padding: 1rem;
    margin-bottom: 0.5rem;
}

.transfer-card-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

/* "Created"/"Updated" meta lines, muted only when showUpdated is set. */
.transfer-meta-muted {
    color: #666;
}

.transfer-card-right {
    text-align: right;
}

.transfer-status-text {
    font-weight: bold;
}

.transfer-progress-track {
    background: #f0f0f0;
    border-radius: 4px;
    height: 8px;
    margin: 0.5rem 0;
}

.transfer-progress-fill {
    height: 100%;
    border-radius: 4px;
}

/* refreshVaultBalances balance-card detail block */
.balance-detail-block {
    margin: 0.5rem 0;
}

/* ==========================================================================
   Shared portfolio components (portfolio.js)
   ========================================================================== */

/* renderVenueBadge */
.venue-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-weight: 600;
    white-space: nowrap;
}

.venue-badge-dot {
    width: 0.6rem;
    height: 0.6rem;
    border-radius: 50%;
    display: inline-block;
    flex-shrink: 0;
}

/* renderAllocationBar */
.alloc-bar {
    display: flex;
    width: 100%;
    border-radius: 6px;
    overflow: hidden;
}

.alloc-bar-segment {
    height: 100%;
    min-width: 2px;
}

.alloc-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-top: 0.5rem;
    font-size: 0.8rem;
    color: var(--color-text-muted);
}

.alloc-legend-item {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
}

/* renderAssetVenueMatrix numeric cells */
.matrix-num {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* renderFreshness */
.freshness {
    color: var(--color-text-muted);
    font-size: 0.75rem;
}

/* renderConsolidatedPositions side cell */
.positions-side {
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-weight: 600;
}

/* ==========================================================================
   Responsive breakpoints (Phase 4f)

   Scoped to shared layout primitives only (.metric-grid / .balance-grid,
   .card, .tabs, header/nav, .data-table, .toast-container, .modal, .btn,
   form controls). Every rule below lives inside a max-width media query,
   so desktop (>1024px) rendering is untouched — nothing here modifies or
   restructures the base rules above.

   WIDE screens are not handled here: the upper end of the layout is
   --layout-max-width on .container. Use that variable, not a min-width
   query — a max-width is inert below its own value, so it cannot reach
   these breakpoints.
   ========================================================================== */

/* ---- <=1024px ----
   .metric-grid (repeat(auto-fit, minmax(150px, 1fr))) and .balance-grid
   (repeat(auto-fit, minmax(250px, 1fr))) already reflow their column count
   automatically as the viewport narrows, since they use auto-fit rather
   than a fixed column count. No override is needed at this breakpoint. */

@media (max-width: 768px) {
    /* Header: allow the logo + title to wrap instead of overflowing/clipping
       on narrow viewports. (.nav > .container > ul already has
       flex-wrap: wrap; only .header .container needed it.) */
    .header .container {
        flex-wrap: wrap;
        text-align: center;
    }

    /* .tabs already scrolls horizontally instead of wrapping: it's a flex
       container (default nowrap) with overflow-x: auto, and .tab has
       white-space: nowrap. No change needed here. */

    /* Data tables: give the table's own wrapper horizontal scroll so wide
       tables don't blow out the viewport or force page-level horizontal
       scrolling. Scoped to the table's *direct* parent (not the whole
       .card) so we don't turn .card into a scroll container generally —
       several .card elements host position: sticky strips (.metric-card-row,
       .summary-strip) and position: absolute popups
       (.threshold-meter-popup) that must not be clipped by a
       newly-scrolling ancestor. Some tables (loans.html) already wrap
       themselves in an inline overflow-x: auto div; this is a no-op there
       and only helps the tables that don't. */
    div:has(> table.data-table) {
        overflow-x: auto;
    }

    /* Modal: already `width: calc(100% - 2rem)` with a 480px cap, so it's
       already near-full-width on narrow viewports. No override needed. */

    /* Toast container: narrow to fit within the viewport instead of only
       insetting from the right. */
    .toast-container {
        left: 1rem;
    }
}

@media (max-width: 480px) {
    /* Metric grid: force a single column. (.balance-grid already collapses
       to one column on its own at this width — its 250px minmax leaves no
       room for a second column — so it needs no override.) */
    .metric-grid {
        grid-template-columns: 1fr;
    }

    /* Buttons and form controls: comfortable sizing at small widths. */
    .btn {
        padding: 0.7rem 1.1rem;
        font-size: 0.95rem;
    }

    .form-group input,
    .form-group select,
    .form-group textarea,
    .form-control {
        padding: 0.65rem 0.85rem;
        font-size: 0.95rem;
    }

    /* Header: shrink the title/logo so they don't force extra wrapping or
       overflow on very small screens. */
    .header h1 {
        font-size: 1.4rem;
    }

    .header .logo {
        font-size: 1.15rem;
    }

    /* Modal: reclaim a bit more width on very small screens. */
    .modal {
        width: calc(100% - 1rem);
        padding: 1rem;
    }

    /* Toast container: match the modal's tighter inset. */
    .toast-container {
        left: 0.5rem;
        right: 0.5rem;
    }
}

/* ==========================================================================
   Interactive portfolio components (donut v2, matrix From/To, exposure bars,
   move-funds slider) — GUI modernization phases P1/P4.
   ========================================================================== */

/* --- Donut segments --- */
.donut-segment-group {
    transform-box: view-box;
    transform-origin: center;
    transition: transform 0.15s ease, opacity 0.18s ease;
}
.donut-segment-group--active {
    transform: scale(1.06);
}
.donut-segment-group--selected {
    transform: scale(1.03);
}
.donut-segment-group--dim {
    opacity: 0.25;
}
.donut-segment-group [role="button"] {
    cursor: pointer;
    outline: none;
}
.donut-tooltip {
    position: absolute;
    z-index: 3;
    padding: 0.35rem 0.55rem;
    border-radius: 4px;
    font-size: 0.78rem;
    background: var(--color-bg-primary);
    border: 1px solid var(--color-border);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.35);
    pointer-events: none;
    white-space: nowrap;
}

/* --- Matrix cells (From/To selection) --- */
.matrix-cell {
    transition: background 0.15s ease, box-shadow 0.15s ease, opacity 0.15s ease;
}
.matrix-cell--clickable {
    cursor: pointer;
}
.matrix-cell--clickable:hover {
    background: var(--color-accent-soft);
}
.matrix-cell--from {
    box-shadow: inset 0 0 0 2px var(--color-success);
    background: var(--color-success-soft);
}
.matrix-cell--to {
    box-shadow: inset 0 0 0 2px var(--color-info);
    background: var(--color-info-soft);
}
.matrix-cell--eligible {
    box-shadow: inset 0 0 0 1px var(--color-border-focus);
}
.matrix-cell--dim {
    opacity: 0.3;
}
.matrix-row--clickable {
    cursor: pointer;
}
.matrix-row--clickable:hover td {
    background: var(--color-accent-soft);
}
.matrix-row--highlight td {
    background: var(--color-info-soft);
}

/* --- Exposure bars --- */
.exposure-bars {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}
.exposure-bar-row {
    display: grid;
    grid-template-columns: minmax(110px, 1fr) 3fr minmax(70px, auto);
    gap: 0.6rem;
    align-items: center;
}
.exposure-bar-label {
    font-size: 0.8rem;
    color: var(--color-text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.exposure-bar-track {
    height: 10px;
    border-radius: 5px;
    background: var(--color-bg-secondary);
    overflow: hidden;
}
.exposure-bar-fill {
    height: 100%;
    border-radius: 5px;
    transition: width 0.3s ease;
}
.exposure-bar-fill--long {
    background: var(--color-success);
}
.exposure-bar-fill--short {
    background: var(--color-error);
}
.exposure-bar-value {
    font-size: 0.8rem;
    text-align: right;
}

/* --- Move funds From/To banner + slider --- */
.from-to-banner {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    flex-wrap: wrap;
    padding: 0.5rem 0.75rem;
    margin-bottom: 0.75rem;
    border-radius: 6px;
    border: 1px solid var(--color-border);
    background: var(--color-bg-secondary);
    font-size: 0.85rem;
}
.from-to-banner .from-chip,
.from-to-banner .to-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.15rem 0.5rem;
    border-radius: 4px;
    font-weight: 600;
}
.from-to-banner .from-chip {
    background: var(--color-success-soft);
    border: 1px solid var(--color-success);
}
.from-to-banner .to-chip {
    background: var(--color-info-soft);
    border: 1px solid var(--color-info);
}
.from-to-banner .banner-clear {
    margin-left: auto;
    cursor: pointer;
    color: var(--color-text-muted);
    background: none;
    border: none;
    font-size: 0.8rem;
    text-decoration: underline;
}

input[type="range"].uf-slider {
    -webkit-appearance: none;
    appearance: none;
    width: 100%;
    height: 6px;
    border-radius: 3px;
    background: var(--color-bg-secondary);
    outline: none;
    margin: 0.5rem 0;
}
input[type="range"].uf-slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--color-accent);
    border: 2px solid var(--color-bg-primary);
    cursor: pointer;
    transition: transform 0.1s ease;
}
input[type="range"].uf-slider::-webkit-slider-thumb:hover {
    transform: scale(1.15);
}
input[type="range"].uf-slider::-moz-range-thumb {
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--color-accent);
    border: 2px solid var(--color-bg-primary);
    cursor: pointer;
}
.uf-quick-amounts {
    display: flex;
    gap: 0.4rem;
    margin-top: 0.35rem;
}
.uf-quick-amounts button {
    padding: 0.15rem 0.55rem;
    font-size: 0.75rem;
    border-radius: 4px;
    border: 1px solid var(--color-border);
    background: var(--color-bg-secondary);
    color: var(--color-text-muted);
    cursor: pointer;
}
.uf-quick-amounts button:hover {
    border-color: var(--color-border-focus);
    color: var(--color-text-primary);
}

/* --- Entrance animation for re-rendered regions --- */
@keyframes fadeSlideIn {
    from { opacity: 0; transform: translateY(6px); }
    to { opacity: 1; transform: translateY(0); }
}
.fade-slide-in {
    animation: fadeSlideIn 0.25s ease;
}
@media (prefers-reduced-motion: reduce) {
    .fade-slide-in {
        animation: none;
    }
    .donut-segment-group,
    .matrix-cell,
    .exposure-bar-fill {
        transition: none;
    }
}

/* --- Chart boxes (driven pies) --- */
.chart-box {
    padding: 0.75rem;
    border-radius: 8px;
    border: 1px solid transparent;
}
.chart-box--driver {
    border-color: var(--color-border-focus);
    box-shadow: 0 0 0 1px var(--color-border-focus);
}
/* renderAllocationDonut sizes its wrap at a fixed 160px while the chart box grows with the page —
   centre it so the slack reads as padding, not a chart pinned to the left of an empty box. */
.chart-box .donut-wrap {
    margin-inline: auto;
}
.chart-box-title {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin: 0 0 0.5rem;
    color: var(--color-text-muted);
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
.chart-reset-chip {
    margin-left: auto;
    padding: 0.1rem 0.5rem;
    font-size: 0.72rem;
    border-radius: 4px;
    border: 1px solid var(--color-border);
    background: var(--color-bg-secondary);
    color: var(--color-text-muted);
    cursor: pointer;
    text-transform: none;
    letter-spacing: normal;
}
.chart-reset-chip:hover {
    border-color: var(--color-border-focus);
    color: var(--color-text-primary);
}

/* --- Vault/exchange chart row --- */
.vault-chart-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
    gap: 1.25rem;
    margin-top: 1rem;
    align-items: start;
}
.chart-label {
    margin: 0 0 0.5rem;
    color: var(--color-text-muted);
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.freshness--stale {
    color: var(--color-warning);
}

/* --- Matrix: transfer affordance + blocked cells --- */
/* The pulse animates OPACITY on an overlay (compositor-only), never box-shadow directly:
   animating box-shadow forces a style/paint pass every frame on every eligible cell, which
   pinned a CPU core for as long as a From cell stayed selected. */
@keyframes eligiblePulse {
    0%, 100% { opacity: 0.45; }
    50% { opacity: 1; }
}
.matrix-cell--eligible {
    position: relative;
}
.matrix-cell--eligible::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    box-shadow: inset 0 0 0 2px var(--color-accent);
    animation: eligiblePulse 1.6s ease-in-out infinite;
    will-change: opacity;
}
@media (prefers-reduced-motion: reduce) {
    .matrix-cell--eligible::after {
        animation: none;
        opacity: 0.8;
    }
}
.matrix-cell--blocked {
    /* Not transferable from this venue: grey it out (never error-red — nothing is
       wrong, the asset just has no movement route here). */
    opacity: 0.35;
    cursor: not-allowed !important;
    box-shadow: none !important;
    background: transparent;
}
.matrix-cell--clickable {
    cursor: pointer;
}
.matrix-cell--clickable:hover {
    background: var(--color-accent-soft);
    box-shadow: inset 0 0 0 1px var(--color-accent);
}
.matrix-table tfoot td {
    border-top: 2px solid var(--color-border);
    padding-top: 0.5rem;
}
@media (prefers-reduced-motion: reduce) {
    .matrix-cell--eligible {
        animation: none;
    }
}

/* --- Venue filter chips (transfers panel) — same visual language as the
   instrument-filter chip: dark pill, subtle border, venue dot, accent active --- */
.venue-filter-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.45rem;
    margin-top: 0.65rem;
}
.venue-filter-chips button {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.3rem 0.75rem;
    font-size: 0.8rem;
    font-family: inherit;
    border-radius: 6px;
    border: 1px solid var(--color-border);
    background: var(--color-bg-secondary);
    color: var(--color-text-muted);
    cursor: pointer;
    transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
}
.venue-filter-chips button:hover {
    border-color: var(--color-border-focus);
    color: var(--color-text-primary);
}
.venue-filter-chips button.chip-active {
    border-color: var(--color-accent);
    background: var(--color-accent-soft);
    color: var(--color-accent-light);
    font-weight: 600;
    box-shadow: 0 0 0 1px var(--color-accent);
}
.venue-filter-chips button:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 1px;
}
