/* =============================================================================
   The Money Ark — UI v3
   A dark SaaS dashboard layer over Bootstrap 5.1.3 + main.css.

   READ THIS BEFORE EDITING
   ------------------------
   main.css is a light theme bolted onto a dark app and defends itself with 42
   !important rules (silver gradient headers, color:#000 tables, near-opaque
   pastel row fills, a purple navbar gradient, and a global
   .col-md-4{width:20%!important}). v3.css loads after it, so equal specificity
   plus !important wins. Section 2 below is the neutralisation layer; every
   block there names the main.css line it overrides. Do not delete those
   without checking main.css first.

   main.js is UNCHANGED and binds to this markup. Constraints it imposes:
     - mainContent.style.display = 'block'   -> the sidebar must be position:fixed,
                                                never a flex sibling
     - loginContent.style.display = 'flex'   -> the login shell is a flex container
     - showAllPortfolioCards() sets display:block on EVERY '#portfolio .card'
       -> no flex/grid may live on a .card inside #portfolio. Layout goes on an
          inner wrapper (see .v3-kpi inside .v3-kpi-card).
     - plPercentElement.className = 'text-success' | 'text-danger' | 'text-light'
       -> #portfolioPLPercent must be styled BY ID, since its class list is
          replaced wholesale.
     - marketStatusBadge.className = 'badge bg-danger'  -> same reasoning.
     - the market-health ribbon gets INLINE style.backgroundColor, so overriding
       it needs !important.
     - modals are opened with style.display='block'; the [style*="block"]
       attribute selector below is what re-centres them without touching main.js.
   ========================================================================== */

/* =============================================================================
   1. TOKENS
   ========================================================================== */
:root {
    /* surfaces */
    --v3-bg: #080B12;
    --v3-surface: #0F1420;
    --v3-surface-2: #151B2B;
    --v3-surface-3: #1D2537;
    --v3-sidebar: #0B0F1A;

    /* borders */
    --v3-border: rgba(255, 255, 255, .07);
    --v3-border-strong: rgba(255, 255, 255, .14);

    /* text */
    --v3-text: rgba(255, 255, 255, .94);
    --v3-text-2: rgba(255, 255, 255, .64);
    --v3-text-3: rgba(255, 255, 255, .42);

    /* brand + semantic */
    --v3-accent: #6366F1;
    --v3-accent-2: #818CF8;
    --v3-accent-soft: rgba(99, 102, 241, .14);
    --v3-positive: #10B981;
    --v3-negative: #F43F5E;
    /* Text-on-dark variants. The fills above are tuned for tinted backgrounds
       and accent bars; as plain text on a dark surface they read dim. These are
       one step lighter and clear WCAG AA comfortably against --v3-surface. */
    --v3-positive-text: #34D399;
    --v3-negative-text: #FB7185;
    --v3-warning: #F59E0B;
    --v3-info: #38BDF8;

    /* spacing (4px base) */
    --v3-1: 4px;
    --v3-2: 8px;
    --v3-3: 12px;
    --v3-4: 16px;
    --v3-5: 24px;
    --v3-6: 32px;
    --v3-7: 48px;

    /* radii */
    --v3-r-sm: 8px;
    --v3-r-md: 14px;
    --v3-r-pill: 999px;

    /* elevation — dark UIs lean on border contrast, not heavy shadow */
    --v3-shadow-1: 0 1px 2px rgba(0, 0, 0, .35);
    --v3-shadow-2: 0 8px 24px rgba(0, 0, 0, .45);
    --v3-shadow-3: 0 24px 64px rgba(0, 0, 0, .6);

    /* motion */
    --v3-fast: 140ms cubic-bezier(.4, 0, .2, 1);
    --v3-slow: 220ms cubic-bezier(.4, 0, .2, 1);

    --v3-sidebar-w: 244px;

    --v3-font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    --v3-font-brand: 'Cinzel', Georgia, serif;
}

/* =============================================================================
   2. NEUTRALISE main.css
   Each block names the main.css line it overrides.
   ========================================================================== */

/* :169 silver gradient header · :178 black h5 · :1039 15px radius */
.card-header {
    background: transparent !important;
    background-image: none !important;
    border-bottom: 1px solid var(--v3-border) !important;
    border-radius: var(--v3-r-md) var(--v3-r-md) 0 0 !important;
    padding: var(--v3-4) var(--v3-5) !important;
}

.card-header h5,
.card-header h4,
.card-header h6,
.card-header .card-title {
    color: var(--v3-text) !important;
    text-shadow: none !important;
}

/* :1262-1265 back-testing header forced to black. That rule is a two-selector
   group whose FIRST arm is '#back-testing .card-header .card-title' — (1,2,0),
   which outranks a plain '#back-testing .card-header h4' (1,1,1). Match both
   arms or this silently loses. */
#back-testing .card-header .card-title,
#back-testing .card-header h4 {
    color: var(--v3-text) !important;
    text-shadow: none !important;
}

/* :1258 history disclosure arrow forced to black, and oversized */
#portfolioHistoryArrow {
    color: var(--v3-text-3) !important;
    font-size: 11px;
    line-height: 1;
    transition: transform var(--v3-fast), color var(--v3-fast);
}

/* :198 + :1054 navbar (card-bg, then a purple gradient) */
.navbar {
    background: var(--v3-sidebar) !important;
    background-image: none !important;
}

/* :204 navbar-brand colour */
.navbar-brand {
    color: var(--v3-text) !important;
}

/* :270 neon glow on every heading */
h1, h2, h3, h4, h5, h6 {
    text-shadow: none !important;
}

/* :209 black table text · :245 + :376 silver thead with black text
   :231/:235/:240 white row tints · :249 opaque cell background
   :1048 .table{background:rgba(255,255,255,.95)} — a 95% WHITE fill on the
   table element itself. The cells are transparent, so without this the whole
   table renders white-on-white the moment rows are injected. */
.table {
    background: transparent !important;
    background-color: transparent !important;
    color: var(--v3-text) !important;
    border-color: var(--v3-border) !important;
    box-shadow: none !important;
    margin-bottom: 0;
}

.table > thead > tr > th {
    background: transparent !important;
    background-image: none !important;
    color: var(--v3-text-3) !important;
    border-bottom: 1px solid var(--v3-border-strong) !important;
}

.table > tbody > tr {
    background-color: transparent !important;
}

.table > tbody > tr > td {
    background: transparent !important;
    color: var(--v3-text) !important;
    border-top: 1px solid var(--v3-border) !important;
}

.table > tbody > tr:nth-child(odd) {
    background-color: rgba(255, 255, 255, .015) !important;
}

.table > tbody > tr:hover > td {
    background: rgba(255, 255, 255, .045) !important;
}

/* :308 .container{max-width:98%!important} — the sidebar shell owns width now */
.v3-main .container {
    max-width: none !important;
    width: 100%;
    padding-left: 0;
    padding-right: 0;
}

.navbar .container {
    max-width: none !important;
    width: 100%;
    padding: 0;
}

/* :315/:321 .col-md-4{width:20%} / .col-md-8{width:80%} are global and squeeze
   the market-health gauge. Restore a sane split inside that panel only. */
.v3-market .col-md-4 {
    width: 32% !important;
}

.v3-market .col-md-8 {
    width: 68% !important;
}

@media (max-width: 991px) {
    .v3-market .col-md-4,
    .v3-market .col-md-8 {
        width: 100% !important;
    }
}

/* :283 placeholders at 90% white read as real values */
.form-control::placeholder {
    color: var(--v3-text-3) !important;
    opacity: 1;
}

/* :1007 metric-card slate gradient */
.metric-card {
    background: var(--v3-surface-2) !important;
    background-image: none !important;
}

/* :264 glass panel around every form group — far too heavy at this density */
.card-body form > div {
    background: transparent !important;
    padding: 0 !important;
}

/* :216 rounded overflow wrapper clipped sticky headers */
.table-responsive {
    border: none !important;
    box-shadow: none !important;
}

/* -----------------------------------------------------------------------------
   main.css ships a complete ID-SCOPED mini-theme for the two trading
   confirmation modals — #actionModal (:729-800, 18 rules) and
   #portfolioExitModal (:850-930, 16 rules) — with its own palette:
       .modal-content{#222}  .form-control{#333}  .alert{#333}
       .alert-info{#264653}  .alert-warning{#e76f51}  .btn-primary{#2a9d8f}
   ID specificity (1,1,0) beats every class selector in this file, so these two
   modals silently opted out of the design system: solid teal/orange alert
   blocks, grey inputs and a green Confirm button. Overrides must be ID-scoped
   too, or they lose.
   -------------------------------------------------------------------------- */
#actionModal .modal-content,
#portfolioExitModal .modal-content {
    background: var(--v3-surface) !important;
    color: var(--v3-text);
    border: 1px solid var(--v3-border-strong) !important;
}

#actionModal h5,
#portfolioExitModal h2 {
    color: var(--v3-text);
    border-bottom: 1px solid var(--v3-border);
    padding-bottom: var(--v3-3);
    margin-bottom: var(--v3-4);
    font-size: 17px;
    font-weight: 650;
}

#actionModal .form-control,
#portfolioExitModal .form-control {
    background: var(--v3-surface-2);
    border: 1px solid var(--v3-border-strong);
    color: var(--v3-text);
    border-radius: var(--v3-r-sm);
}

#actionModal .form-control:focus,
#portfolioExitModal .form-control:focus {
    background: var(--v3-surface-2);
    border-color: var(--v3-accent);
    box-shadow: 0 0 0 3px var(--v3-accent-soft);
}

#actionModal .form-control[readonly],
#portfolioExitModal .form-control[readonly] {
    background: rgba(255, 255, 255, .03);
    color: var(--v3-text-3);
}

#actionModal .form-text,
#portfolioExitModal .form-text,
#portfolioExitModal .form-control-static {
    color: var(--v3-text-3);
}

#actionModal .alert,
#portfolioExitModal .alert {
    background: var(--v3-surface-2);
    border: 1px solid var(--v3-border);
    color: var(--v3-text-2);
    border-radius: var(--v3-r-md);
}

#actionModal .alert-info,
#portfolioExitModal .alert-info {
    background: rgba(56, 189, 248, .10);
    border: 1px solid rgba(56, 189, 248, .28);
    border-left: 3px solid var(--v3-info);
    color: var(--v3-text);
}

#actionModal .alert-warning,
#portfolioExitModal .alert-warning {
    background: rgba(245, 158, 11, .12);
    border: 1px solid rgba(245, 158, 11, .30);
    border-left: 3px solid var(--v3-warning);
    color: var(--v3-text);
}

#actionModal .alert-secondary {
    background: var(--v3-surface-3);
    border-color: var(--v3-border);
    color: var(--v3-text-2);
}

#actionModal .alert h5,
#actionModal .alert strong,
#portfolioExitModal .alert strong {
    color: var(--v3-text);
    border-bottom: none;
    padding-bottom: 0;
    margin-bottom: var(--v3-2);
    font-size: 14px;
}

#actionModal .btn-primary,
#portfolioExitModal .btn-primary {
    background: var(--v3-accent);
    border-color: var(--v3-accent);
    color: #fff;
}

#actionModal .btn-primary:hover,
#portfolioExitModal .btn-primary:hover {
    background: var(--v3-accent-2);
    border-color: var(--v3-accent-2);
}

#actionModal .btn-secondary,
#portfolioExitModal .btn-secondary {
    background: var(--v3-surface-3);
    border-color: var(--v3-border-strong);
    color: var(--v3-text-2);
}

#actionModal .modal-buttons,
#portfolioExitModal .modal-footer {
    border-top: 1px solid var(--v3-border);
    padding-top: var(--v3-4);
    margin-top: var(--v3-5);
    gap: var(--v3-2);
}

/* main.css floats this one and sizes it 28px; keep the shared .close treatment */
#actionModal .close,
#portfolioExitModal .close {
    float: none;
    position: absolute;
    top: var(--v3-4);
    right: var(--v3-4);
    font-size: 20px;
    font-weight: 400;
    color: var(--v3-text-3);
}

#actionModal .close:hover,
#portfolioExitModal .close:hover {
    color: var(--v3-text);
}

/* =============================================================================
   3. BASE
   ========================================================================== */
html {
    -webkit-text-size-adjust: 100%;
}

body {
    background: var(--v3-bg);
    color: var(--v3-text);
    font-family: var(--v3-font);
    font-size: 14px;
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* scroll lock — main.js already toggles body.modal-open */
body.modal-open {
    overflow: hidden;
}

/* every figure aligns in a column */
.table,
.v3-kpi,
.metric-card,
#marketHealthScore,
.v3-num {
    font-variant-numeric: tabular-nums;
    font-feature-settings: 'tnum' 1;
}

::selection {
    background: var(--v3-accent);
    color: #fff;
}

/* focus visibility — never remove the ring, only restyle it */
:focus-visible {
    outline: 2px solid var(--v3-accent-2);
    outline-offset: 2px;
    border-radius: var(--v3-r-sm);
}

/* scrollbars */
* {
    scrollbar-width: thin;
    scrollbar-color: rgba(255, 255, 255, .16) transparent;
}

*::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}

*::-webkit-scrollbar-thumb {
    background: rgba(255, 255, 255, .14);
    border-radius: var(--v3-r-pill);
    border: 2px solid transparent;
    background-clip: content-box;
}

*::-webkit-scrollbar-thumb:hover {
    background: rgba(255, 255, 255, .24);
    background-clip: content-box;
}

/* =============================================================================
   4. LOGIN
   #loginContent is set to display:flex by main.js
   ========================================================================== */
.login-container {
    background:
        radial-gradient(1000px 600px at 50% -10%, rgba(99, 102, 241, .13), transparent 70%),
        var(--v3-bg);
    padding: var(--v3-5);
}

.v3-login {
    width: 100%;
    max-width: 400px;
    text-align: center;
}

.login-title {
    font-family: var(--v3-font-brand);
    font-size: 34px;
    font-weight: 700;
    letter-spacing: .01em;
    color: var(--v3-text);
    margin-bottom: var(--v3-1);
}

.v3-login-sub {
    color: var(--v3-text-3);
    font-size: 13px;
    margin-bottom: var(--v3-5);
}

.login-card {
    max-width: none;
    width: 100%;
    text-align: left;
    box-shadow: var(--v3-shadow-3);
}

/* =============================================================================
   5. SHELL — fixed sidebar + offset main
   ========================================================================== */
#mainContent {
    min-height: 100vh;
}

.navbar {
    position: fixed;
    inset: 0 auto 0 0;
    width: var(--v3-sidebar-w);
    z-index: 1030;
    display: block;
    padding: var(--v3-4) var(--v3-3);
    border-right: 1px solid var(--v3-border);
    overflow-y: auto;
    margin-bottom: 0 !important;
}

.navbar .container {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    min-height: calc(100vh - var(--v3-6));
    gap: var(--v3-1);
}

/* brand. checkAuth() does innerHTML += ' | username', so the trailing text node
   inherits this small muted style while .v3-brand-text stays large. */
.navbar-brand {
    display: block;
    padding: var(--v3-2) var(--v3-3) var(--v3-4);
    margin: 0;
    font-size: 11px;
    font-weight: 500;
    color: var(--v3-text-3) !important;
    text-decoration: none;
    line-height: 1.4;
}

.v3-brand-text {
    display: block;
    font-family: var(--v3-font-brand);
    font-size: 17px;
    font-weight: 700;
    color: var(--v3-text);
    letter-spacing: .01em;
}

.v3-brand-mark {
    display: inline-block;
    width: 8px;
    height: 8px;
    margin-bottom: var(--v3-2);
    border-radius: 2px;
    background: linear-gradient(135deg, var(--v3-accent-2), var(--v3-accent));
    box-shadow: 0 0 12px rgba(99, 102, 241, .8);
}

/* nav list */
.navbar .nav-tabs {
    display: block;
    border: none !important;
    margin: 0;
    padding: 0;
    list-style: none;
    flex: 1 1 auto;
}

.navbar .nav-item {
    margin: 0 0 2px;
}

/* NOTE: main.js sets li.style.display='block' on #labTabItem / #databaseTabItem,
   so the flex layout lives on the <a>, never on the <li>. */
.navbar .nav-link {
    display: flex;
    align-items: center;
    gap: var(--v3-3);
    padding: 9px var(--v3-3);
    border: none !important;
    border-radius: var(--v3-r-sm);
    color: var(--v3-text-2) !important;
    font-size: 13.5px;
    font-weight: 500;
    text-decoration: none;
    transition: background var(--v3-fast), color var(--v3-fast);
}

.navbar .nav-link i {
    width: 16px;
    font-size: 14px;
    text-align: center;
    color: var(--v3-text-3);
    transition: color var(--v3-fast);
}

.navbar .nav-link:hover {
    background: rgba(255, 255, 255, .045);
    color: var(--v3-text) !important;
}

.navbar .nav-link:hover i {
    color: var(--v3-text-2);
}

.navbar .nav-link.active {
    background: var(--v3-accent-soft) !important;
    color: #fff !important;
    border: none !important;
}

.navbar .nav-link.active i {
    color: var(--v3-accent-2);
}

/* sidebar footer buttons — Help, Settings, and the Logout button that
   addLogoutButton() appends to .navbar .container at runtime */
.navbar .container > .btn {
    display: flex;
    align-items: center;
    gap: var(--v3-3);
    width: 100%;
    padding: 9px var(--v3-3);
    background: transparent !important;
    background-image: none !important;
    border: none !important;
    border-radius: var(--v3-r-sm);
    color: var(--v3-text-3) !important;
    font-size: 13px;
    font-weight: 500;
    text-align: left;
    box-shadow: none !important;
    transition: background var(--v3-fast), color var(--v3-fast);
}

.navbar .container > .btn i {
    width: 16px;
    font-size: 14px;
    text-align: center;
}

.navbar .container > .btn:hover {
    background: rgba(255, 255, 255, .05) !important;
    color: var(--v3-text) !important;
}

/* main column */
.v3-main {
    margin-left: var(--v3-sidebar-w);
    padding: 0 var(--v3-6) var(--v3-7);
    max-width: 1560px;
}

/* =============================================================================
   6. PAGE HEADER
   ========================================================================== */
.v3-page-head {
    position: sticky;
    top: 0;
    z-index: 20;
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--v3-4);
    flex-wrap: wrap;
    padding: var(--v3-6) 0 var(--v3-4);
    margin-bottom: var(--v3-5);
    border-bottom: 1px solid var(--v3-border);
    background: linear-gradient(to bottom, var(--v3-bg) 78%, rgba(8, 11, 18, 0));
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
}

.v3-page-title {
    font-size: 24px;
    font-weight: 650;
    letter-spacing: -.015em;
    color: var(--v3-text);
    margin: 0;
}

.v3-page-sub {
    font-size: 13px;
    color: var(--v3-text-3);
    margin: 2px 0 0;
}

.v3-page-actions {
    display: flex;
    align-items: center;
    gap: var(--v3-2);
}

/* =============================================================================
   7. CARDS
   Every top-level portfolio panel keeps .card because showAllPortfolioCards()
   needs to find it, and must stay display:block.
   ========================================================================== */
.card {
    background: var(--v3-surface);
    border: 1px solid var(--v3-border);
    border-radius: var(--v3-r-md);
    box-shadow: var(--v3-shadow-1);
    margin-bottom: var(--v3-5);
    overflow: hidden;
}

.card.mt-4 {
    margin-top: 0 !important;
}

.card-body {
    padding: var(--v3-5);
}

.card-header h5,
.card-header h4 {
    font-size: 15px;
    font-weight: 600;
    letter-spacing: -.005em;
    margin: 0;
}

/* =============================================================================
   8. KPI BLOCK
   .v3-kpi-card is a .card (display:block, forced by main.js).
   The grid lives on .v3-kpi inside it.
   ========================================================================== */
.v3-kpi-card {
    background:
        radial-gradient(760px 300px at 0% 0%, rgba(99, 102, 241, .09), transparent 62%),
        var(--v3-surface);
}

.v3-kpi {
    display: grid;
    grid-template-columns: minmax(240px, .9fr) 2fr;
    gap: var(--v3-5);
    align-items: center;
    padding: var(--v3-5);
}

.v3-kpi-hero {
    border-right: 1px solid var(--v3-border);
    padding-right: var(--v3-5);
}

.v3-kpi-hero-top {
    display: flex;
    align-items: center;
    gap: var(--v3-2);
}

.v3-kpi-label {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--v3-text-3);
    margin: 0;
}

.v3-kpi-hero-figure {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: var(--v3-3);
    margin-top: var(--v3-2);
}

/* styled BY ID — main.js replaces the class list wholesale */
#totalPortfolioValue {
    font-size: 34px;
    font-weight: 700;
    letter-spacing: -.025em;
    line-height: 1.1;
    color: var(--v3-text) !important;
    margin: 0;
}

#portfolioPLPercent {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 9px;
    border-radius: var(--v3-r-pill);
    font-size: 12.5px;
    font-weight: 600;
    margin: 0;
    background: rgba(255, 255, 255, .07);
    color: var(--v3-text-2) !important;
}

#portfolioPLPercent.text-success {
    background: rgba(16, 185, 129, .14);
    color: var(--v3-positive-text) !important;
    font-weight: 700;
}

#portfolioPLPercent.text-danger {
    background: rgba(244, 63, 94, .14);
    color: var(--v3-negative-text) !important;
    font-weight: 700;
}

/* never encode gain/loss by colour alone */
#portfolioPLPercent.text-success::before {
    content: '\25B2';
    font-size: 8px;
}

#portfolioPLPercent.text-danger::before {
    content: '\25BC';
    font-size: 8px;
}

.v3-kpi-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--v3-5);
}

.v3-kpi-stat h4 {
    font-size: 20px;
    font-weight: 650;
    letter-spacing: -.015em;
    margin: var(--v3-1) 0 0;
    color: var(--v3-text) !important;
}

.v3-unit {
    font-size: 12px;
    font-weight: 500;
    color: var(--v3-text-3);
}

.v3-hint {
    color: var(--v3-text-3) !important;
    font-size: 12px;
    text-decoration: none !important;
}

.v3-hint:hover {
    color: var(--v3-text-2) !important;
}

/* =============================================================================
   9. TABLES
   ========================================================================== */
.table-responsive {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

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

.table > thead > tr > th {
    padding: 10px var(--v3-3) !important;
    font-size: 10.5px !important;
    font-weight: 600 !important;
    letter-spacing: .07em;
    text-transform: uppercase;
    white-space: nowrap;
    position: sticky;
    top: 0;
    z-index: 2;
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
}

.table > tbody > tr > td {
    padding: 11px var(--v3-3) !important;
    vertical-align: middle;
    border-top-color: var(--v3-border) !important;
}

.table > tbody > tr {
    transition: background var(--v3-fast);
}

/* Bootstrap 5.1.3 ships `.table > :not(:first-child){border-top:2px solid
   currentColor}` to divide thead from tbody. currentColor here is our near-white
   table text, so it paints a bright 2px bar above the first row — and it is
   still drawn when the thead is display:none (card mode). */
.table > :not(:first-child) {
    border-top: none !important;
}

/* the card already draws the outer edge */
.card-body > .table-responsive > .table > tbody > tr:first-child > td {
    border-top: none !important;
}

/* --- semantic rows main.js applies ---------------------------------------
   main.css painted these near-white with black text (:650, :654, :947, :960,
   :1104). Here they keep their meaning via a left accent bar plus a faint
   tint, which is legible on a dark surface. */
.pi-cycle-row td,
.pi-cycle-row:hover td {
    background-color: rgba(129, 140, 248, .10) !important;
    color: var(--v3-text) !important;
}

.pi-cycle-row {
    background-color: transparent !important;
    border-left: none !important;
}

.pi-cycle-row td:first-child {
    box-shadow: inset 3px 0 0 var(--v3-accent-2);
}

.above-80-row td,
.above-80-row:hover td {
    background-color: rgba(245, 158, 11, .10) !important;
    color: var(--v3-text) !important;
}

.above-80-row td:first-child {
    box-shadow: inset 3px 0 0 var(--v3-warning);
}

.high-performer td {
    background-color: rgba(16, 185, 129, .11) !important;
    color: var(--v3-text) !important;
}

.high-performer td:first-child {
    box-shadow: inset 3px 0 0 var(--v3-positive);
}

.low-performer td {
    background-color: rgba(244, 63, 94, .11) !important;
    color: var(--v3-text) !important;
}

.low-performer td:first-child {
    box-shadow: inset 3px 0 0 var(--v3-negative);
}

.completed td {
    opacity: .55;
}

/* --- Profit / Loss cells -------------------------------------------------
   main.js puts .text-success / .text-danger on the <td> itself for
   Profit/Loss and P/L % in Holdings (main.js:2404,:2407) and Portfolio
   History (:3410,:3413). The blanket `color: … !important` on every td in
   §2 was flattening them to ordinary body text, so gains and losses looked
   identical. A td-qualified selector (0,2,3) outranks that (0,1,3).

   Colour is not the only signal: main.js already prefixes a literal '+' or
   '-' on both figures, so this reads correctly without colour vision.

   Applies in card mode too - the mobile td rule does not set `color`, so
   there is nothing extra to override there. The `LABEL` pseudo-element keeps
   its own muted colour and is unaffected. */
.table > tbody > tr > td.text-success,
.table > tbody > tr > td .text-success {
    color: var(--v3-positive-text) !important;
    font-weight: 650;
    letter-spacing: -.01em;
}

.table > tbody > tr > td.text-danger,
.table > tbody > tr > td .text-danger {
    color: var(--v3-negative-text) !important;
    font-weight: 650;
    letter-spacing: -.01em;
}

/* =============================================================================
   10. BUTTONS
   ========================================================================== */
.btn {
    border-radius: var(--v3-r-sm);
    font-size: 13px;
    font-weight: 550;
    padding: 7px 14px;
    letter-spacing: -.005em;
    transition: background var(--v3-fast), border-color var(--v3-fast),
        color var(--v3-fast), transform var(--v3-fast);
}

.btn:active {
    transform: translateY(.5px);
}

/* Bootstrap's default is a 0.25rem grey halo, which reads as a chunky border
   on the small icon buttons (expand, gear). */
.btn:focus,
.btn:focus-visible {
    box-shadow: 0 0 0 3px var(--v3-accent-soft);
    outline: none;
}

/* the ▼/▲ trade-expander in Holdings and Portfolio History */
.expand-trades-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 34px;
    line-height: 1;
}

.expand-trades-btn .expand-arrow {
    font-size: 10px;
    line-height: 1;
}

.btn-sm {
    padding: 5px 10px;
    font-size: 12px;
}

.btn-primary {
    background: var(--v3-accent);
    border-color: var(--v3-accent);
    color: #fff;
}

.btn-primary:hover,
.btn-primary:focus {
    background: var(--v3-accent-2);
    border-color: var(--v3-accent-2);
    color: #fff;
}

.btn-outline-primary {
    color: var(--v3-text-2);
    border-color: var(--v3-border-strong);
    background: transparent;
}

.btn-outline-primary:hover {
    background: rgba(255, 255, 255, .06);
    border-color: var(--v3-border-strong);
    color: var(--v3-text);
}

.btn-secondary {
    background: var(--v3-surface-3);
    border-color: var(--v3-border-strong);
    color: var(--v3-text-2);
}

.btn-secondary:hover {
    background: var(--v3-surface-3);
    color: var(--v3-text);
}

.btn-danger {
    background: var(--v3-negative);
    border-color: var(--v3-negative);
}

.btn-success {
    background: var(--v3-positive);
    border-color: var(--v3-positive);
    color: #04211a;
}

.btn-warning {
    background: var(--v3-warning);
    border-color: var(--v3-warning);
    color: #2a1a00;
}

.btn-info {
    background: var(--v3-info);
    border-color: var(--v3-info);
    color: #04202b;
}

/* main.css's gradient button, used by the sidebar footer + logout */
.btn-dark-gradient {
    background: transparent;
    border: none;
    color: var(--v3-text-2);
}

/* =============================================================================
   11. FORMS
   ========================================================================== */
.form-label,
.form-group > label,
.card-body label {
    font-size: 12px;
    font-weight: 550;
    color: var(--v3-text-2);
    margin-bottom: 5px;
}

.form-control,
.form-select {
    background: var(--v3-surface-2);
    border: 1px solid var(--v3-border-strong);
    border-radius: var(--v3-r-sm);
    color: var(--v3-text) !important;
    font-size: 13.5px;
    padding: 8px 11px;
    transition: border-color var(--v3-fast), box-shadow var(--v3-fast);
}

.form-control:focus,
.form-select:focus {
    background: var(--v3-surface-2);
    border-color: var(--v3-accent);
    box-shadow: 0 0 0 3px var(--v3-accent-soft);
    color: var(--v3-text) !important;
}

.form-control[readonly] {
    background: rgba(255, 255, 255, .03);
    color: var(--v3-text-3) !important;
}

.form-check-input {
    background-color: var(--v3-surface-3);
    border-color: var(--v3-border-strong);
    cursor: pointer;
}

.form-check-input:checked {
    background-color: var(--v3-accent);
    border-color: var(--v3-accent);
}

.form-check-input:focus {
    box-shadow: 0 0 0 3px var(--v3-accent-soft);
    border-color: var(--v3-accent);
}

.form-check-label {
    font-size: 13px;
    color: var(--v3-text-2);
}

.form-text {
    color: var(--v3-text-3) !important;
    font-size: 11.5px;
}

/* =============================================================================
   12. BADGES, ALERTS, PILLS
   ========================================================================== */
.badge {
    font-size: 11px;
    font-weight: 600;
    padding: 4px 9px;
    border-radius: var(--v3-r-pill);
    letter-spacing: .01em;
}

.badge.bg-secondary {
    background: rgba(255, 255, 255, .09) !important;
    color: var(--v3-text-2) !important;
}

.badge.bg-success {
    background: rgba(16, 185, 129, .16) !important;
    color: var(--v3-positive) !important;
}

.badge.bg-danger {
    background: rgba(244, 63, 94, .16) !important;
    color: var(--v3-negative) !important;
}

.badge.bg-warning {
    background: rgba(245, 158, 11, .16) !important;
    color: var(--v3-warning) !important;
}

.badge.bg-info {
    background: rgba(56, 189, 248, .16) !important;
    color: var(--v3-info) !important;
}

.badge.bg-light {
    background: rgba(255, 255, 255, .12) !important;
    color: var(--v3-text) !important;
}

.alert {
    border-radius: var(--v3-r-md);
    border: 1px solid var(--v3-border);
    font-size: 13px;
    padding: var(--v3-3) var(--v3-4);
}

.alert-success {
    background: rgba(16, 185, 129, .10);
    border-color: rgba(16, 185, 129, .28);
    color: var(--v3-positive);
}

.alert-info {
    background: rgba(56, 189, 248, .10);
    border-color: rgba(56, 189, 248, .28);
    color: var(--v3-info);
}

.alert-warning {
    background: rgba(245, 158, 11, .10);
    border-color: rgba(245, 158, 11, .28);
    color: var(--v3-warning);
}

.alert-danger {
    background: rgba(244, 63, 94, .10);
    border-color: rgba(244, 63, 94, .28);
    color: var(--v3-negative);
}

/* --- market health ribbon -------------------------------------------------
   Only rendered for EXIT_ALL_HOLDINGS / WAIT_ON_BENCH, so it is genuinely
   high-severity. main.js sets INLINE backgroundColor (#dc3545 / #cc5500) and
   color:white, hence !important here. Severity still comes from the
   alert-danger / alert-warning class main.js adds. */
.v3-health-ribbon {
    display: flex;
    align-items: center;
    border-radius: var(--v3-r-md);
    padding: var(--v3-3) var(--v3-4) !important;
    margin-bottom: var(--v3-5) !important;
    font-size: 13px;
    color: var(--v3-text) !important;
}

.v3-health-ribbon.alert-danger {
    background: linear-gradient(90deg, rgba(244, 63, 94, .20), rgba(244, 63, 94, .07)) !important;
    border: 1px solid rgba(244, 63, 94, .4) !important;
    box-shadow: inset 3px 0 0 var(--v3-negative);
}

.v3-health-ribbon.alert-warning {
    background: linear-gradient(90deg, rgba(245, 158, 11, .20), rgba(245, 158, 11, .07)) !important;
    border: 1px solid rgba(245, 158, 11, .4) !important;
    box-shadow: inset 3px 0 0 var(--v3-warning);
}

.v3-health-ribbon #marketHealthTitle {
    font-weight: 650;
    font-size: 13.5px;
}

.v3-health-ribbon #marketHealthMessage {
    color: var(--v3-text-2);
    font-size: 12.5px;
}

.v3-health-ribbon.alert-danger #marketHealthIcon {
    color: var(--v3-negative);
}

.v3-health-ribbon.alert-warning #marketHealthIcon {
    color: var(--v3-warning);
}

/* =============================================================================
   13. MARKET HEALTH PANEL
   ========================================================================== */
/* keep the gauge optically centred against the two rows of metric cards
   beside it, instead of stranded at the top of a tall column */
.v3-market .card-body > .row {
    align-items: center;
}

.market-health-gauge {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 190px;
    padding: var(--v3-2) 0;
}

#marketHealthGauge {
    max-width: 100%;
    height: auto;
}

.gauge-info {
    margin-top: var(--v3-2);
    text-align: center;
}

#marketHealthScore {
    font-size: 30px;
    font-weight: 700;
    letter-spacing: -.02em;
    color: var(--v3-text) !important;
}

.metric-card {
    background: var(--v3-surface-2) !important;
    border: 1px solid var(--v3-border);
    border-radius: var(--v3-r-sm);
    padding: var(--v3-3) var(--v3-4) !important;
    height: 100%;
}

.metric-card h6 {
    font-size: 10.5px !important;
    font-weight: 600;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--v3-text-3) !important;
    margin-bottom: var(--v3-1);
}

.metric-card h4,
.metric-card h5 {
    font-size: 19px;
    font-weight: 650;
    letter-spacing: -.015em;
    margin: 0;
}

/* =============================================================================
   14. MODALS
   main.js opens these with style.display='block'. The attribute selector
   re-centres them without any JS change.
   ========================================================================== */
/* The OVERLAY is the scroll container, not the dialog.
   -----------------------------------------------------------------------------
   The dialog used to carry `max-height: calc(100vh - 48px); overflow-y:auto`.
   On mobile browsers 100vh is the URL-bar-HIDDEN height, which is taller than
   what is actually on screen, so the dialog was sized past the visible area:
   its internal scroll hit the end with the footer buttons still behind the
   browser chrome, and body.modal-open blocks page scroll, so there was no way
   to bring them up. Scrolling the overlay and sizing it with 100dvh (the
   height that actually tracks browser chrome) fixes it for every modal. */
.modal {
    background-color: rgba(6, 9, 15, .72) !important;
    backdrop-filter: blur(10px) saturate(120%);
    -webkit-backdrop-filter: blur(10px) saturate(120%);
    overflow-y: auto;
    overflow-x: hidden;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    padding: var(--v3-5);
    padding-top: max(var(--v3-5), env(safe-area-inset-top, 0px));
    padding-bottom: max(var(--v3-5), env(safe-area-inset-bottom, 0px));
}

/* main.css gives .modal height:100%, which resolves against the LARGE mobile
   viewport. 100dvh follows the visible one. */
@supports (height: 100dvh) {
    .modal {
        height: 100dvh !important;
    }
}

/* Stacking. main.css sets .modal{z-index:1000} and #actionModal{z-index:9999
   !important}, while the v3 sidebar sits at 1030 — so every modal EXCEPT
   #actionModal rendered behind the nav. On mobile the top bar covered the top
   of the dialog; on desktop the sidebar was never dimmed by the backdrop.
   One scale for all of them, still below the .loading overlay at 9999 so a
   spinner raised during a save stays visible.

   ⚠️ NO !important ON THIS RULE. MessagePopup() (main.js:3642/:3662) builds its
   own dialogs at inline z-index 2000 paired with a backdrop at inline 1900. An
   !important stylesheet declaration beats a non-important INLINE style, so
   `.modal{z-index:1080!important}` silently dragged every error/confirm popup
   below its own backdrop — the popup rendered dimmed, blurred and completely
   unclickable. Without !important the inline 2000 wins, as main.js intends,
   and this rule still beats main.css's .modal{z-index:1000} on file order. */
.modal {
    z-index: 1080;
}

/* These two are ID-scoped in main.css (#actionModal is 9999 !important), so
   they do need ID specificity plus !important to be brought onto the scale.
   Lowering #actionModal also fixes a latent bug: at 9999 it sat ABOVE any
   MessagePopup raised from inside it, so its own validation errors were
   unreachable. */
#actionModal,
#portfolioExitModal {
    z-index: 1080 !important;
}

/* belt and braces: a backdrop must never outrank a dialog */
.modal-backdrop {
    z-index: 1070;
}

.modal[style*="block"] {
    display: flex !important;
    /* flex-start, never center: a centered flex item taller than its container
       overflows in BOTH directions and the top becomes unscrollable. The auto
       margins below still centre it whenever it does fit. */
    align-items: flex-start;
    justify-content: center;
}

.modal-content {
    background: var(--v3-surface) !important;
    border: 1px solid var(--v3-border-strong) !important;
    border-radius: var(--v3-r-md) !important;
    box-shadow: var(--v3-shadow-3) !important;
    width: 100%;
    max-width: 560px;
    /* no max-height: the overlay scrolls, so nothing can be cut off */
    max-height: none;
    overflow: visible;
    margin: auto !important;
    padding: var(--v3-5) !important;
    animation: v3-modal-in var(--v3-slow) both;
}

@keyframes v3-modal-in {
    from { opacity: 0; transform: translateY(8px) scale(.985); }
    to   { opacity: 1; transform: none; }
}

.modal-header {
    border-bottom: 1px solid var(--v3-border);
    padding: 0 0 var(--v3-4);
    margin-bottom: var(--v3-4);
}

.modal-header .modal-title,
.modal-content > h2,
.modal-content > h5 {
    font-size: 17px;
    font-weight: 650;
    letter-spacing: -.015em;
    color: var(--v3-text) !important;
}

.modal-body {
    padding: 0;
}

.modal-footer,
.modal-buttons {
    display: flex;
    justify-content: flex-end;
    gap: var(--v3-2);
    border-top: 1px solid var(--v3-border);
    padding: var(--v3-4) 0 0;
    margin-top: var(--v3-5);
}

.close {
    position: absolute;
    top: var(--v3-4);
    right: var(--v3-4);
    width: 28px;
    height: 28px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--v3-r-sm);
    background: transparent;
    border: none;
    color: var(--v3-text-3);
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
    transition: background var(--v3-fast), color var(--v3-fast);
}

.close:hover {
    background: rgba(255, 255, 255, .07);
    color: var(--v3-text);
}

.modal-content {
    position: relative;
}

/* Bootstrap-flavoured modals in the markup (#editTradeModal, #initialCapitalModal).
   Here .modal-dialog is the flex item, so it carries the auto margins. */
.modal-dialog {
    width: 100%;
    max-width: 520px;
    margin: auto !important;
}

.modal-dialog .modal-content {
    max-width: none;
    max-height: none;
    margin: 0 !important;
}

/* =============================================================================
   15. LOADING, SKELETONS, EMPTY STATES
   ========================================================================== */
#loadingOverlay.loading {
    background: rgba(8, 11, 18, .72);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
}

.v3-skeleton,
.v2-skeleton {
    position: relative;
    overflow: hidden;
    background: var(--v3-surface-2);
    border-radius: var(--v3-r-sm);
    min-height: 44px;
}

.v3-skeleton::after,
.v2-skeleton::after {
    content: '';
    position: absolute;
    inset: 0;
    transform: translateX(-100%);
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .06), transparent);
    animation: v3-shimmer 1.4s infinite;
}

@keyframes v3-shimmer {
    to { transform: translateX(100%); }
}

.spinner-border {
    color: var(--v3-accent) !important;
}

.progress {
    background: var(--v3-surface-3);
    border-radius: var(--v3-r-pill);
    height: 6px;
    overflow: hidden;
}

.progress-bar {
    background: var(--v3-accent);
}

.analysis-step {
    color: var(--v3-text-3);
    font-size: 13px;
}

.analysis-step.completed {
    color: var(--v3-positive);
    opacity: 1;
}

/* =============================================================================
   16. MISC PANELS
   ========================================================================== */
.v3-onboard .card-body {
    padding: var(--v3-7) var(--v3-5) !important;
}

/* -----------------------------------------------------------------------------
   Expanded trade rows. main.js emits one <td colspan> of pipe-separated text;
   the enhancement script in index-v3.html restructures it into these elements
   (and MOVES the gear so its main.js click handler survives). If that script is
   ever removed the raw text still renders — just unlabelled.
   -------------------------------------------------------------------------- */
/* main.js hardcodes background:#23293a and color:#fff inline on the detail
   cell, and tbody striping lands on these rows too — so consecutive trades
   alternated shade. Normalise both so a run of trades reads as one group. */
.table > tbody > tr.trade-row,
.table > tbody > tr.history-trade-row {
    background-color: transparent !important;
}

tr.trade-row > td[colspan],
tr.history-trade-row > td[colspan] {
    background: var(--v3-surface-2) !important;
    color: var(--v3-text-2) !important;
    border-top: 1px solid var(--v3-border) !important;
}

.v3-trade {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--v3-2) var(--v3-5);
}

.v3-trade-type {
    flex: 0 0 auto;
    padding: 3px 9px;
    border-radius: var(--v3-r-pill);
    font-size: 10.5px;
    font-weight: 650;
    letter-spacing: .06em;
    text-transform: uppercase;
    background: rgba(255, 255, 255, .08);
    color: var(--v3-text);
}

.v3-trade-entry { background: rgba(16, 185, 129, .16); color: var(--v3-positive); }
.v3-trade-add   { background: rgba(56, 189, 248, .16); color: var(--v3-info); }
.v3-trade-exit  { background: rgba(244, 63, 94, .16); color: var(--v3-negative); }

.v3-trade-field {
    display: inline-flex;
    align-items: baseline;
    gap: var(--v3-2);
    min-width: 0;
}

.v3-trade-k {
    font-size: 10px;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--v3-text-3);
    white-space: nowrap;
}

.v3-trade-v {
    font-size: 13px;
    color: var(--v3-text);
    font-variant-numeric: tabular-nums;
}

/* main.js sets color:#fff and margin-left:10px inline on this span */
.v3-trade-edit {
    margin-left: auto !important;
    color: var(--v3-text-3) !important;
    cursor: pointer;
    padding: 4px;
    border-radius: var(--v3-r-sm);
    transition: color var(--v3-fast), background var(--v3-fast);
}

.v3-trade-edit:hover {
    color: var(--v3-text) !important;
    background: rgba(255, 255, 255, .07);
}

@media (max-width: 767.98px) {
    .v3-trade {
        display: grid;
        grid-template-columns: auto minmax(0, 1fr);
        gap: 7px var(--v3-4);
        align-items: baseline;
    }

    .v3-trade-type {
        grid-column: 1 / -1;
        justify-self: start;
    }

    /* promote each key/value pair to grid items so labels form a column */
    .v3-trade-field {
        display: contents;
    }

    .v3-trade-v {
        text-align: right;
    }

    .v3-trade-edit {
        grid-column: 1 / -1;
        justify-self: end;
        margin-left: 0 !important;
        min-height: 34px;
        min-width: 44px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }
}

.v3-history .card-header {
    cursor: pointer;
    transition: background var(--v3-fast);
}

.v3-history .card-header:hover {
    background: rgba(255, 255, 255, .03) !important;
}

pre {
    background: var(--v3-surface-2);
    border: 1px solid var(--v3-border);
    border-radius: var(--v3-r-sm);
    padding: var(--v3-3);
    font-size: 12px;
    color: var(--v3-text-2);
    max-height: 380px;
    overflow: auto;
}

hr {
    border-color: var(--v3-border);
    opacity: 1;
}

a {
    color: var(--v3-accent-2);
}

.text-white-50 {
    color: var(--v3-text-3) !important;
}

.text-muted {
    color: var(--v3-text-3) !important;
}

/* =============================================================================
   17. RESPONSIVE
   Below 992px the sidebar becomes a horizontal top bar. main.js sets
   li.style.display='block' on the admin tabs, which still behaves correctly
   as a flex item.
   ========================================================================== */
@media (max-width: 991px) {
    .navbar {
        position: sticky;
        inset: auto;
        width: 100%;
        height: auto;
        padding: var(--v3-3) var(--v3-4);
        border-right: none;
        border-bottom: 1px solid var(--v3-border);
        overflow: visible;
    }

    .navbar .container {
        flex-direction: row;
        align-items: center;
        min-height: 0;
        gap: var(--v3-2);
        flex-wrap: wrap;
    }

    .navbar-brand {
        padding: 0 var(--v3-3) 0 0;
        flex: 0 0 auto;
    }

    .navbar .nav-tabs {
        display: flex;
        flex: 1 1 100%;
        order: 3;
        gap: var(--v3-1);
        overflow-x: auto;
        padding-bottom: 2px;
    }

    .navbar .nav-item {
        margin: 0;
        flex: 0 0 auto;
    }

    .navbar .nav-link {
        white-space: nowrap;
    }

    .navbar .container > .btn {
        width: auto;
        flex: 0 0 auto;
    }

    .navbar .container > .btn .v3-nav-text {
        display: none;
    }

    .v3-main {
        margin-left: 0;
        padding: 0 var(--v3-4) var(--v3-6);
    }

    .v3-page-head {
        position: static;
        padding-top: var(--v3-5);
    }

    .v3-kpi {
        grid-template-columns: 1fr;
        gap: var(--v3-4);
    }

    .v3-kpi-hero {
        border-right: none;
        border-bottom: 1px solid var(--v3-border);
        padding-right: 0;
        padding-bottom: var(--v3-4);
    }

    .v3-kpi-grid {
        grid-template-columns: repeat(2, 1fr);
        gap: var(--v3-4);
    }
}

@media (max-width: 575px) {
    .v3-main {
        padding: 0 var(--v3-3) var(--v3-6);
    }

    .card-body {
        padding: var(--v3-4);
    }

    #totalPortfolioValue {
        font-size: 28px;
    }

    .v3-page-title {
        font-size: 20px;
    }

    .modal {
        padding: var(--v3-3);
    }

    .modal-content {
        padding: var(--v3-4) !important;
    }

    /* dense financial tables stay scrollable rather than reflowing —
       main.js injects these rows, so a card transform would need JS changes */
    .table {
        font-size: 12px;
    }
}

/* =============================================================================
   17b. RESPONSIVE TABLES — one card per row below 768px
   -----------------------------------------------------------------------------
   main.js injects <tr> markup with no data-* labels, so the column NAME for
   each cell is recovered from :nth-child() against the static <thead> order.

   ==> THE COLUMN ORDER IN index-v3.html IS LOAD-BEARING. <==
   If you add, remove or reorder a <th> in one of these tables, you must update
   the matching nth-child labels below or every card will be mislabelled.
   Column counts are asserted by docs/ui/check-structure.cjs (rule 11).

   Layout per card:
       row 1   primary identifier (left)      state badge (right)
       body    LABEL .................. value
       footer  action buttons, full width
   Rows main.js inserts with colspan (the expandable trade detail under
   Holdings and History) stay full-width and unlabelled.
   ========================================================================== */
@media (max-width: 767.98px) {

    .v3-cards,
    .v3-cards > tbody,
    .v3-cards > tbody > tr,
    .v3-cards > tbody > tr > td {
        display: block;
        width: 100%;
    }

    /* the header row is the label source, not something to render */
    .v3-cards > thead {
        display: none;
    }

    .v3-cards {
        border: none !important;
    }

    /* --- the card --- */
    .v3-cards > tbody > tr {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        align-items: center;
        gap: 0 var(--v3-3);
        background: var(--v3-surface-2) !important;
        border: 1px solid var(--v3-border);
        border-radius: var(--v3-r-md);
        padding: var(--v3-3) var(--v3-4);
        margin-bottom: var(--v3-3);
    }

    .v3-cards > tbody > tr:hover > td {
        background: transparent !important;
    }

    /* --- default cell: LABEL ....... value --- */
    .v3-cards > tbody > tr > td {
        grid-column: 1 / -1;
        display: flex;
        align-items: baseline;
        justify-content: space-between;
        gap: var(--v3-4);
        text-align: right;
        padding: 7px 0 !important;
        border: none !important;
        border-top: 1px solid var(--v3-border) !important;
        background: transparent !important;
        box-shadow: none !important;
        min-width: 0;
        word-break: break-word;
    }

    .v3-cards > tbody > tr > td::before {
        content: attr(data-label);
        flex: 0 0 auto;
        text-align: left;
        font-size: 10.5px;
        font-weight: 600;
        letter-spacing: .06em;
        text-transform: uppercase;
        color: var(--v3-text-3);
        white-space: nowrap;
    }

    /* --- row 1: identity + state, no labels, no divider --- */
    .v3-cards > tbody > tr > td.v3-c-title,
    .v3-cards > tbody > tr > td.v3-c-state {
        border-top: none !important;
        padding-top: 0 !important;
        display: block;
    }

    .v3-cards > tbody > tr > td.v3-c-title {
        grid-column: 1;
        grid-row: 1;
        font-size: 16px;
        font-weight: 650;
        letter-spacing: -.01em;
        text-align: left;
    }

    .v3-cards > tbody > tr > td.v3-c-state {
        grid-column: 2;
        grid-row: 1;
        text-align: right;
    }

    /* Portfolio History puts the ▼ trade-expander in the Status cell alongside
       the badge (main.js:3374), so it lands in the card header. Give it a real
       tap target there. */
    .v3-cards .expand-trades-btn {
        min-width: 44px;
        min-height: 44px;
        margin-left: var(--v3-2);
        vertical-align: middle;
    }

    .v3-cards > tbody > tr > td.v3-c-title::before,
    .v3-cards > tbody > tr > td.v3-c-state::before,
    .v3-cards > tbody > tr > td.v3-c-actions::before {
        content: none;
    }

    /* --- footer: buttons go full width and get real tap targets --- */
    .v3-cards > tbody > tr > td.v3-c-actions {
        display: flex;
        flex-wrap: wrap;
        gap: var(--v3-2);
        padding-top: var(--v3-3) !important;
        margin-top: var(--v3-1);
    }

    .v3-cards > tbody > tr > td.v3-c-actions .btn {
        flex: 1 1 auto;
        min-height: 38px;
        padding: 8px 14px;
        font-size: 13px;
    }

    /* --- expandable detail rows main.js inserts with colspan --- */
    .v3-cards > tbody > tr > td[colspan] {
        display: block;
        text-align: left;
        border-top: none !important;
        font-size: 12.5px;
        line-height: 1.7;
    }

    .v3-cards > tbody > tr > td[colspan]::before {
        content: none;
    }

    /* a colspan-only row is a nested detail panel, not a card of its own.
       Padding comes from the <td>, so zero it here or it double-pads. */
    .v3-cards > tbody > tr:has(> td[colspan]) {
        display: block;
        padding: 0;
        margin-left: var(--v3-4);
        background: transparent !important;
        border: none;
    }

    /* --- semantic rows: the accent moves from the cell to the card edge --- */
    .v3-cards > tbody > tr > td:first-child {
        box-shadow: none !important;
    }

    .v3-cards > tbody > tr.pi-cycle-row {
        background: rgba(129, 140, 248, .10) !important;
        border-left: 3px solid var(--v3-accent-2);
    }

    .v3-cards > tbody > tr.above-80-row {
        background: rgba(245, 158, 11, .10) !important;
        border-left: 3px solid var(--v3-warning);
    }

    .v3-cards > tbody > tr.high-performer {
        background: rgba(16, 185, 129, .10) !important;
        border-left: 3px solid var(--v3-positive);
    }

    .v3-cards > tbody > tr.low-performer {
        background: rgba(244, 63, 94, .10) !important;
        border-left: 3px solid var(--v3-negative);
    }

    .v3-cards > tbody > tr.pi-cycle-row > td,
    .v3-cards > tbody > tr.above-80-row > td,
    .v3-cards > tbody > tr.high-performer > td,
    .v3-cards > tbody > tr.low-performer > td {
        background: transparent !important;
    }

    /* -------------------------------------------------------------------------
       Column labels. Order mirrors each <thead> exactly.
       ---------------------------------------------------------------------- */

    /* Required Actions — Type | Symbol | Date | Price | Reason | Technical Data
       | Market Cap | Action */
    .v3-cards-actions > tbody > tr > td:nth-child(1) { grid-column: 2; grid-row: 1; border-top: none !important; padding-top: 0 !important; display: block; text-align: right; }
    .v3-cards-actions > tbody > tr > td:nth-child(2) { grid-column: 1; grid-row: 1; border-top: none !important; padding-top: 0 !important; display: block; text-align: left; font-size: 16px; font-weight: 650; }
    .v3-cards-actions > tbody > tr > td:nth-child(1)::before,
    .v3-cards-actions > tbody > tr > td:nth-child(2)::before { content: none; }
    .v3-cards-actions > tbody > tr > td:nth-child(3)::before { content: 'Date'; }
    .v3-cards-actions > tbody > tr > td:nth-child(4)::before { content: 'Price'; }
    .v3-cards-actions > tbody > tr > td:nth-child(5)::before { content: 'Reason'; }
    .v3-cards-actions > tbody > tr > td:nth-child(6)::before { content: 'Technical'; }
    .v3-cards-actions > tbody > tr > td:nth-child(7)::before { content: 'Market Cap'; }
    .v3-cards-actions > tbody > tr > td:nth-child(8) { display: flex; flex-wrap: wrap; gap: var(--v3-2); padding-top: var(--v3-3) !important; }
    .v3-cards-actions > tbody > tr > td:nth-child(8)::before { content: none; }
    .v3-cards-actions > tbody > tr > td:nth-child(8) .btn { flex: 1 1 auto; min-height: 38px; }

    /* Holdings — Symbol | Entry Date | Avg Entry Price | Avg CPS | Current Price
       | Position Size | Profit/Loss | P/L % | Status | Market Cap | Actions */
    .v3-cards-holdings > tbody > tr > td:nth-child(1) { grid-column: 1; grid-row: 1; border-top: none !important; padding-top: 0 !important; display: block; text-align: left; font-size: 16px; font-weight: 650; }
    .v3-cards-holdings > tbody > tr > td:nth-child(9) { grid-column: 2; grid-row: 1; border-top: none !important; padding-top: 0 !important; display: block; text-align: right; }
    .v3-cards-holdings > tbody > tr > td:nth-child(1)::before,
    .v3-cards-holdings > tbody > tr > td:nth-child(9)::before { content: none; }
    .v3-cards-holdings > tbody > tr > td:nth-child(2)::before  { content: 'Entry Date'; }
    .v3-cards-holdings > tbody > tr > td:nth-child(3)::before  { content: 'Avg Entry'; }
    .v3-cards-holdings > tbody > tr > td:nth-child(4)::before  { content: 'Avg CPS'; }
    .v3-cards-holdings > tbody > tr > td:nth-child(5)::before  { content: 'Current Price'; }
    .v3-cards-holdings > tbody > tr > td:nth-child(6)::before  { content: 'Position Size'; }
    .v3-cards-holdings > tbody > tr > td:nth-child(7)::before  { content: 'Profit / Loss'; }
    .v3-cards-holdings > tbody > tr > td:nth-child(8)::before  { content: 'P/L %'; }
    .v3-cards-holdings > tbody > tr > td:nth-child(10)::before { content: 'Market Cap'; }
    .v3-cards-holdings > tbody > tr > td:nth-child(11) { display: flex; flex-wrap: wrap; gap: var(--v3-2); padding-top: var(--v3-3) !important; }
    .v3-cards-holdings > tbody > tr > td:nth-child(11)::before { content: none; }
    .v3-cards-holdings > tbody > tr > td:nth-child(11) .btn { flex: 1 1 auto; min-height: 38px; }

    /* Portfolio History — Symbol | Entry Date | Avg Entry Price | Exit Date
       | Exit Price | Profit/Loss | P/L % | Market Cap | Status */
    .v3-cards-history > tbody > tr > td:nth-child(1) { grid-column: 1; grid-row: 1; border-top: none !important; padding-top: 0 !important; display: block; text-align: left; font-size: 16px; font-weight: 650; }
    .v3-cards-history > tbody > tr > td:nth-child(9) { grid-column: 2; grid-row: 1; border-top: none !important; padding-top: 0 !important; display: block; text-align: right; }
    .v3-cards-history > tbody > tr > td:nth-child(1)::before,
    .v3-cards-history > tbody > tr > td:nth-child(9)::before { content: none; }
    .v3-cards-history > tbody > tr > td:nth-child(2)::before { content: 'Entry Date'; }
    .v3-cards-history > tbody > tr > td:nth-child(3)::before { content: 'Avg Entry'; }
    .v3-cards-history > tbody > tr > td:nth-child(4)::before { content: 'Exit Date'; }
    .v3-cards-history > tbody > tr > td:nth-child(5)::before { content: 'Exit Price'; }
    .v3-cards-history > tbody > tr > td:nth-child(6)::before { content: 'Profit / Loss'; }
    .v3-cards-history > tbody > tr > td:nth-child(7)::before { content: 'P/L %'; }
    .v3-cards-history > tbody > tr > td:nth-child(8)::before { content: 'Market Cap'; }

    /* The Lab results — User | Date | Period | Return ($) | Return (%) | W/L
       | Win % | Avg | B/W | Report | Actions */
    .v3-cards-results > tbody > tr > td:nth-child(1) { grid-column: 1; grid-row: 1; border-top: none !important; padding-top: 0 !important; display: block; text-align: left; font-size: 15px; font-weight: 650; }
    .v3-cards-results > tbody > tr > td:nth-child(3) { grid-column: 2; grid-row: 1; border-top: none !important; padding-top: 0 !important; display: block; text-align: right; font-size: 12px; color: var(--v3-text-3); }
    .v3-cards-results > tbody > tr > td:nth-child(1)::before,
    .v3-cards-results > tbody > tr > td:nth-child(3)::before { content: none; }
    .v3-cards-results > tbody > tr > td:nth-child(2)::before  { content: 'Date'; }
    .v3-cards-results > tbody > tr > td:nth-child(4)::before  { content: 'Return ($)'; }
    .v3-cards-results > tbody > tr > td:nth-child(5)::before  { content: 'Return (%)'; }
    .v3-cards-results > tbody > tr > td:nth-child(6)::before  { content: 'W/L'; }
    .v3-cards-results > tbody > tr > td:nth-child(7)::before  { content: 'Win %'; }
    .v3-cards-results > tbody > tr > td:nth-child(8)::before  { content: 'Avg'; }
    .v3-cards-results > tbody > tr > td:nth-child(9)::before  { content: 'Best / Worst'; }
    .v3-cards-results > tbody > tr > td:nth-child(10)::before { content: 'Report'; }
    .v3-cards-results > tbody > tr > td:nth-child(11)::before { content: 'Settings'; }

    /* Backtest reports — Start Date | End Date | Initial Capital | Final Value
       | Total Return | Monthly Avg Return | Yearly Avg Return | Total Trades
       | Report */
    .v3-cards-reports > tbody > tr > td:nth-child(1) { grid-column: 1; grid-row: 1; border-top: none !important; padding-top: 0 !important; display: block; text-align: left; font-size: 15px; font-weight: 650; }
    .v3-cards-reports > tbody > tr > td:nth-child(5) { grid-column: 2; grid-row: 1; border-top: none !important; padding-top: 0 !important; display: block; text-align: right; }
    .v3-cards-reports > tbody > tr > td:nth-child(1)::before,
    .v3-cards-reports > tbody > tr > td:nth-child(5)::before { content: none; }
    .v3-cards-reports > tbody > tr > td:nth-child(2)::before { content: 'End Date'; }
    .v3-cards-reports > tbody > tr > td:nth-child(3)::before { content: 'Initial Capital'; }
    .v3-cards-reports > tbody > tr > td:nth-child(4)::before { content: 'Final Value'; }
    .v3-cards-reports > tbody > tr > td:nth-child(6)::before { content: 'Monthly Avg'; }
    .v3-cards-reports > tbody > tr > td:nth-child(7)::before { content: 'Yearly Avg'; }
    .v3-cards-reports > tbody > tr > td:nth-child(8)::before { content: 'Total Trades'; }
    .v3-cards-reports > tbody > tr > td:nth-child(9) { display: flex; gap: var(--v3-2); padding-top: var(--v3-3) !important; }
    .v3-cards-reports > tbody > tr > td:nth-child(9)::before { content: none; }
    .v3-cards-reports > tbody > tr > td:nth-child(9) .btn { flex: 1 1 auto; min-height: 38px; }

    /* -------------------------------------------------------------------------
       Expandable detail rows, LAST so they beat the nth-child labels above.
       main.js inserts these as a single <td colspan> after a Holdings or
       History row — and that cell is also :nth-child(1), so without this it
       inherits the 16px card-title styling meant for the Symbol cell.
       ---------------------------------------------------------------------- */
    .v3-cards > tbody > tr > td[colspan] {
        grid-column: 1 / -1 !important;
        grid-row: auto !important;
        display: block !important;
        text-align: left !important;
        font-size: 12.5px !important;
        font-weight: 400 !important;
        line-height: 1.7;
        padding: var(--v3-3) var(--v3-4) !important;
        border: 1px solid var(--v3-border) !important;
        border-left: 2px solid var(--v3-border-strong) !important;
        border-radius: var(--v3-r-sm);
        margin-bottom: var(--v3-2);
        /* main.js hardcodes background:#23293a inline on these */
        background: var(--v3-surface-2) !important;
        color: var(--v3-text-2) !important;
    }

    .v3-cards > tbody > tr > td[colspan]::before {
        content: none !important;
    }

    .v3-cards > tbody > tr > td[colspan] strong {
        color: var(--v3-text);
    }

    /* the card IS the scroll container now — kill the horizontal scroller */
    .v3-cards-wrap,
    .card-body > .table-responsive:has(.v3-cards) {
        overflow-x: visible;
    }

    /* main.css:383 adds a '← Scroll →' hint to every .table-responsive on
       mobile. In card mode there is nothing to scroll sideways, so it is just
       a misleading label floating under the panel. */
    .table-responsive:has(.v3-cards)::after {
        content: none !important;
    }
}

/* =============================================================================
   17c. TOASTS
   main.js calls showToast(type, message) in 6 places but never defines it;
   the v3 page supplies the function (see index-v3.html). Sits above modals
   (2000) because errors are raised while a dialog is still open.
   ========================================================================== */
#v3-toasts {
    position: fixed;
    z-index: 2100;
    right: var(--v3-5);
    bottom: var(--v3-5);
    display: flex;
    flex-direction: column;
    gap: var(--v3-2);
    max-width: min(420px, calc(100vw - var(--v3-6)));
    pointer-events: none;
}

.v3-toast {
    pointer-events: auto;
    display: flex;
    align-items: flex-start;
    gap: var(--v3-3);
    padding: var(--v3-3) var(--v3-4);
    border-radius: var(--v3-r-md);
    border: 1px solid var(--v3-border-strong);
    background: var(--v3-surface-2);
    box-shadow: var(--v3-shadow-3);
    font-size: 13px;
    line-height: 1.5;
    color: var(--v3-text);
    animation: v3-toast-in var(--v3-slow) both;
}

@keyframes v3-toast-in {
    from { opacity: 0; transform: translateY(8px) scale(.98); }
    to   { opacity: 1; transform: none; }
}

.v3-toast-out {
    opacity: 0;
    transform: translateY(6px);
    transition: opacity 180ms ease, transform 180ms ease;
}

.v3-toast-icon {
    flex: 0 0 auto;
    font-size: 13px;
    line-height: 1.5;
}

.v3-toast-msg {
    flex: 1 1 auto;
    min-width: 0;
    word-break: break-word;
}

.v3-toast-x {
    flex: 0 0 auto;
    background: none;
    border: none;
    color: var(--v3-text-3);
    font-size: 17px;
    line-height: 1;
    padding: 0 2px;
    cursor: pointer;
    transition: color var(--v3-fast);
}

.v3-toast-x:hover {
    color: var(--v3-text);
}

.v3-toast-success {
    border-left: 3px solid var(--v3-positive);
}

.v3-toast-success .v3-toast-icon {
    color: var(--v3-positive);
}

.v3-toast-error {
    border-left: 3px solid var(--v3-negative);
    background: linear-gradient(90deg, rgba(244, 63, 94, .12), var(--v3-surface-2) 60%);
}

.v3-toast-error .v3-toast-icon {
    color: var(--v3-negative);
}

.v3-toast-info {
    border-left: 3px solid var(--v3-info);
}

.v3-toast-info .v3-toast-icon {
    color: var(--v3-info);
}

@media (max-width: 767.98px) {
    #v3-toasts {
        right: var(--v3-3);
        left: var(--v3-3);
        bottom: max(var(--v3-3), env(safe-area-inset-bottom, 0px));
        max-width: none;
    }
}

/* =============================================================================
   18. MOTION / ACCESSIBILITY
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .001ms !important;
        scroll-behavior: auto !important;
    }
}

@media print {
    .navbar,
    .v3-page-actions {
        display: none !important;
    }

    .v3-main {
        margin-left: 0;
    }
}
