/* Relievv — Bank to Tally
   Premium dashboard theme: dark navy sidebar, Inter type, left-accented
   stat cards, filter chips, pill badges — brand blue kept from the
   existing Relievv tool, chrome modernized around it. */

:root {
    --primary-blue: #1e3c72;
    --secondary-blue: #2a5298;
    --accent-blue: #3b6fed;
    --accent-blue-dark: #2a56c9;
    --light-blue: #eef3ff;
    --lighter-blue: #f7f9ff;
    --border-blue: #dbe4fb;

    --sidebar-bg-1: #0a1730;
    --sidebar-bg-2: #101f42;
    --sidebar-text: rgba(226, 233, 250, 0.72);
    --sidebar-text-strong: #ffffff;
    --sidebar-hover: rgba(255, 255, 255, 0.07);
    --sidebar-active: linear-gradient(135deg, #3b6fed, #5a8bff);

    --bg: #f3f5fb;
    --surface: #ffffff;
    --surface-alt: #f7f8fc;
    --border: #e7eaf3;
    --border-strong: #d7ddec;

    --text-dark: #16192b;
    --text-medium: #565d75;
    --text-light: #8a90a6;

    --success: #16a34a;
    --success-bg: #e9f9ef;
    --warning: #b7791f;
    --warning-bg: #fff6e0;
    --danger: #dc3545;
    --danger-bg: #fdeeee;
    --neutral-bg: #eef0f5;

    --radius-lg: 16px;
    --radius-md: 12px;
    --radius-sm: 9px;
    --shadow-xs: 0 1px 2px rgba(16, 24, 55, 0.05);
    --shadow-sm: 0 2px 8px rgba(16, 24, 55, 0.06);
    --shadow-md: 0 8px 24px rgba(16, 24, 55, 0.10);
    --shadow-lg: 0 16px 40px rgba(16, 24, 55, 0.16);
}

* { margin: 0; padding: 0; box-sizing: border-box; }

body {
    /* Reverted to Plus Jakarta Sans per your feedback — the Roboto swap
       read as looking worse in the app, so back to the original pick
       (logo/symbol images are untouched; this only changes the tool's
       text font). */
    font-family: 'Plus Jakarta Sans', 'Segoe UI', -apple-system, BlinkMacSystemFont, sans-serif;
    background: var(--bg);
    color: var(--text-dark);
    line-height: 1.55;
    /* NOTE on the 125vh below (here and everywhere else min-height/height
       is set to a viewport-relative size on this page): `vh` units are
       measured against the browser's real, unzoomed viewport — `zoom`
       does NOT rescale them. So a plain 100vh box inside a zoom:0.8
       ancestor still computes its height from the full real viewport, and
       then THAT box gets visually shrunk to 80% by the zoom, leaving a
       blank gap at the bottom equal to the missing 20%. 125vh (= 100/0.8)
       compensates for that shrink so the box still visually fills exactly
       100% of the real viewport after zooming out. */
    min-height: 125vh;
    font-size: 14.5px;
    -webkit-font-smoothing: antialiased;
    /* Default 80% zoom per your request — the whole UI (sidebar, tables,
       cards, fonts) renders at 80% scale from the start, so what the user
       sees at their browser's normal 100% already looks like they zoomed
       out to 80%. Chromium-only property (works in Chrome/Edge, which your
       screenshots show you using); browsers that don't support `zoom` just
       ignore it and render at normal 100%. */
    zoom: 0.8;
}

h1, h2, h3, h4 { letter-spacing: -0.01em; font-weight: 700; }
a { color: var(--accent-blue); text-decoration: none; }
a:hover { color: var(--accent-blue-dark); }
.icon { flex-shrink: 0; }
::selection { background: var(--light-blue); color: var(--primary-blue); }

/* ---------- Layout shell ---------- */
.app-shell { display: flex; min-height: 125vh; } /* see the 125vh note on body above */

.sidebar {
    width: 252px;
    flex-shrink: 0;
    background: linear-gradient(190deg, var(--sidebar-bg-2) 0%, var(--sidebar-bg-1) 100%);
    color: var(--sidebar-text);
    display: flex;
    flex-direction: column;
    position: sticky;
    top: 0;
    height: 125vh; /* see the 125vh note on body above — keeps the sidebar filling the real screen edge-to-edge */
    transition: width 0.18s ease;
}

.sidebar-brand {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    padding: 1.1rem 1.3rem 1.1rem;
}
.sidebar-brand img.mark { height: 30px; width: 30px; object-fit: contain; flex-shrink: 0; }
.sidebar-brand .wordmark { font-weight: 800; font-size: 1.05rem; color: #fff; letter-spacing: -0.01em; white-space: nowrap; overflow: hidden; }

/* Collapse toggle — sits in the brand row; the icon shown flips between
   chevron-left (expanded, click to collapse) and menu (collapsed, click to
   expand). This button is the ONE thing that stays visible in both
   states — see body.sidebar-collapsed rules below. */
.sidebar-toggle {
    display: flex; align-items: center; justify-content: center;
    width: 30px; height: 30px; flex-shrink: 0;
    border: none; border-radius: 8px; cursor: pointer;
    background: transparent; color: var(--sidebar-text);
    transition: background 0.15s ease, color 0.15s ease;
}
.sidebar-toggle:hover { background: var(--sidebar-hover); color: #fff; }
.sidebar-toggle-icon-collapse { display: none; }

body.sidebar-collapsed .sidebar { width: 76px; }
body.sidebar-collapsed .sidebar-brand { padding: 1.1rem 0.6rem; justify-content: center; }
body.sidebar-collapsed .sidebar-brand img.mark,
body.sidebar-collapsed .sidebar-brand .wordmark { display: none; }
body.sidebar-collapsed .sidebar-toggle-icon-expand { display: none; }
body.sidebar-collapsed .sidebar-toggle-icon-collapse { display: flex; }
body.sidebar-collapsed .sidebar-nav { padding: 0.4rem 0.6rem; }
body.sidebar-collapsed .sidebar-nav a { justify-content: center; padding: 0.62rem; gap: 0; }
body.sidebar-collapsed .sidebar-section-label,
body.sidebar-collapsed .nav-label,
body.sidebar-collapsed .sidebar-user-info { display: none; }
body.sidebar-collapsed .sidebar-footer { padding: 0.9rem 0.5rem; }
body.sidebar-collapsed .sidebar-user { justify-content: center; padding: 0.55rem; }
body.sidebar-collapsed .sidebar-logout { justify-content: center; }

.sidebar-nav { flex: 1; padding: 0.4rem 0.85rem; overflow-y: auto; }
.sidebar-section-label {
    margin: 1.1rem 0.75rem 0.4rem;
    font-size: 0.68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: rgba(226, 233, 250, 0.38);
}
.sidebar-nav a {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.62rem 0.85rem;
    border-radius: var(--radius-sm);
    color: var(--sidebar-text);
    font-weight: 500;
    font-size: 0.885rem;
    margin-bottom: 0.15rem;
    transition: background 0.15s ease, color 0.15s ease;
}
.sidebar-nav a:hover { background: var(--sidebar-hover); color: #fff; }
.sidebar-nav a.active {
    background: var(--sidebar-active);
    color: #fff;
    box-shadow: 0 4px 14px rgba(59, 111, 237, 0.35);
    font-weight: 600;
}
.sidebar-nav a .icon { opacity: 0.9; }

.sidebar-footer {
    padding: 0.9rem;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
}
.sidebar-user {
    display: flex; align-items: center; gap: 0.6rem;
    padding: 0.55rem 0.6rem; border-radius: var(--radius-sm);
    transition: background 0.15s ease;
}
.sidebar-user:hover { background: var(--sidebar-hover); }
.sidebar-user .name { color: #fff; font-weight: 600; font-size: 0.85rem; }
.sidebar-user .role { color: rgba(226,233,250,0.5); font-size: 0.75rem; }
.sidebar-user-info { flex: 1; min-width: 0; }
.sidebar-user-info div { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sidebar-logout {
    display: flex; align-items: center; gap: 0.6rem;
    margin-top: 0.3rem; padding: 0.5rem 0.6rem; border-radius: var(--radius-sm);
    color: var(--sidebar-text); font-size: 0.82rem; font-weight: 500;
    text-decoration: none; transition: background 0.15s ease, color 0.15s ease;
}
.sidebar-logout:hover { background: var(--sidebar-hover); color: #fff; }

.main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.topbar {
    background: rgba(255,255,255,0.85);
    backdrop-filter: blur(8px);
    padding: 1.1rem 2rem;
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-bottom: 1px solid var(--border);
    position: sticky;
    top: 0;
    z-index: 50;
}
.topbar .eyebrow { font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-light); margin-bottom: 0.15rem; }
.topbar h1 { font-size: 1.3rem; color: var(--text-dark); font-weight: 800; }
.topbar-right { display: flex; align-items: center; gap: 0.9rem; }
.topbar .user-chip {
    display: flex; align-items: center; gap: 0.6rem;
    font-size: 0.86rem; color: var(--text-medium); font-weight: 500;
    background: none; border: 1px solid transparent; border-radius: 999px;
    padding: 0.3rem 0.6rem 0.3rem 0.3rem; cursor: pointer; transition: background 0.15s ease, border-color 0.15s ease;
}
.topbar .user-chip:hover, .topbar .user-chip[aria-expanded="true"] {
    background: var(--surface-alt); border-color: var(--border);
}
.topbar .user-chip svg { color: var(--text-light); flex-shrink: 0; }

/* Profile popup (item 2) — click the top-right user chip to open, reuses
   the same absolute-positioned/`.show`-toggled popover look as
   .filter-panel (see that class) rather than a whole new pattern. Anchored
   to .user-chip-field (position:relative) instead of the button itself so
   it doesn't shift if the button's own width changes. */
.user-chip-panel { right: 0; left: auto; }
.user-chip-panel-link {
    display: flex; align-items: center; gap: 0.6rem;
    padding: 0.55rem 0.7rem; border-radius: 8px; font-size: 0.85rem; font-weight: 500;
    color: var(--text-medium); text-decoration: none;
}
.user-chip-panel-link:hover { background: var(--surface-alt); color: var(--text-dark); }
.user-chip-panel-link svg { color: var(--text-light); flex-shrink: 0; }
.user-avatar {
    width: 34px; height: 34px; border-radius: 50%;
    background: linear-gradient(135deg, var(--accent-blue), #35b34a);
    color: #fff; display: flex; align-items: center; justify-content: center;
    font-weight: 700; font-size: 0.85rem; flex-shrink: 0;
}

/* Dashboard-only greeting, top left (sits in the .eyebrow slot, above the
   "Your Clients" heading) — big and friendly so the tool feels familiar
   from the first glance, per your request. Explicit text-transform/
   letter-spacing overrides below undo the small-caps styling .eyebrow
   normally applies, since this is a much bigger, sentence-case greeting
   rather than a label. */
.dashboard-greeting {
    font-size: 1.5rem;
    font-weight: 800;
    color: var(--text-dark);
    letter-spacing: -0.01em;
    text-transform: none;
    white-space: nowrap;
}
.dashboard-greeting .greeting-name {
    background: linear-gradient(135deg, var(--accent-blue), #35b34a);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}
@media (max-width: 720px) {
    .dashboard-greeting { font-size: 1.1rem; }
}

.content { padding: 1.8rem 2rem 3rem; flex: 1; }

/* ---------- Flash messages ---------- */
.flashes { padding: 1rem 2rem 0; }
.flash {
    padding: 0.85rem 1.1rem;
    border-radius: var(--radius-sm);
    margin-bottom: 0.7rem;
    font-weight: 500;
    font-size: 0.88rem;
    border: 1px solid transparent;
    display: flex;
    align-items: center;
    gap: 0.6rem;
    /* A flash message can contain a long unbroken string with no spaces —
       most notably the dev-mode "here's your reset link directly" message
       on the Forgot password page, which includes the full reset URL
       (including its long signed token). Flexbox children default to
       min-width:auto, i.e. they refuse to shrink below their min-content
       width — and for unbroken text, min-content IS the full width — so
       without this the text overflowed straight out of the card instead
       of wrapping. overflow-wrap:anywhere (not break-word — break-word
       doesn't reduce min-content sizing, anywhere does) is what actually
       fixes it; word-break is a belt-and-braces fallback. */
    overflow-wrap: anywhere;
    word-break: break-word;
}
.flash-success { background: var(--success-bg); color: #157a3c; border-color: #c9efd8; }
.flash-error { background: var(--danger-bg); color: #a71d2a; border-color: #f6cdd1; }
.flash-warning { background: var(--warning-bg); color: #8a5a10; border-color: #f5e3ab; }
.flash-info { background: var(--light-blue); color: var(--primary-blue); border-color: var(--border-blue); }

/* ---------- Cards / sections ---------- */
.card {
    background: var(--surface);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    border: 1px solid var(--border);
    overflow: hidden;
    margin-bottom: 1.5rem;
}
.card-header {
    background: var(--surface);
    padding: 1.15rem 1.5rem;
    border-bottom: 1px solid var(--border);
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
}
.card-header h2, .card-header h3 { color: var(--text-dark); font-size: 1.02rem; font-weight: 700; }
.card-body { padding: 1.5rem; }

/* ---------- Stat tiles (Mysa-style: simple flat big boxes, no accent rail) ---------- */
.stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 1rem;
    margin-bottom: 1.6rem;
}
.stat-tile {
    background: var(--surface-alt);
    border-radius: var(--radius-lg);
    padding: 1.5rem 1.6rem;
    border: 1px solid var(--border);
    transition: box-shadow 0.18s ease, transform 0.18s ease, background 0.18s ease;
    animation: tileIn 0.4s ease both;
}
.stat-tile:hover { box-shadow: var(--shadow-md); transform: translateY(-2px); background: var(--surface); }
.stat-tile .value { font-size: 2.1rem; font-weight: 800; color: var(--text-dark); line-height: 1.1; font-variant-numeric: tabular-nums; }
.stat-tile .label {
    display: flex; align-items: center; gap: 0.4rem;
    color: var(--text-medium); font-size: 0.82rem; margin-top: 0.55rem; font-weight: 600;
}
.stat-tile.success .value { color: var(--success); }
.stat-tile.warning .value { color: #a9760f; }
.stat-tile.danger .value { color: var(--danger); }
.stat-tile.accent .value { color: var(--accent-blue); }
.stat-grid .stat-tile:nth-child(1) { animation-delay: 0.02s; }
.stat-grid .stat-tile:nth-child(2) { animation-delay: 0.06s; }
.stat-grid .stat-tile:nth-child(3) { animation-delay: 0.10s; }
.stat-grid .stat-tile:nth-child(4) { animation-delay: 0.14s; }
.stat-grid .stat-tile:nth-child(5) { animation-delay: 0.18s; }
.stat-grid .stat-tile:nth-child(6) { animation-delay: 0.22s; }

/* ---------- Buttons ---------- */
.btn {
    display: inline-flex; align-items: center; gap: 0.5rem;
    padding: 0.62rem 1.15rem;
    border-radius: var(--radius-sm);
    font-weight: 600; font-size: 0.87rem;
    border: 1px solid transparent; cursor: pointer;
    transition: all 0.15s ease;
    font-family: inherit;
    line-height: 1.2;
}
.btn-primary { background: var(--accent-blue); color: #fff; box-shadow: 0 2px 6px rgba(59,111,237,0.25); }
.btn-primary:hover { background: var(--accent-blue-dark); transform: translateY(-1px); box-shadow: 0 6px 16px rgba(59,111,237,0.32); }
.btn-success { background: var(--success); color: #fff; }
.btn-success:hover { background: #128a3e; transform: translateY(-1px); }
.btn-outline { background: var(--surface); color: var(--text-medium); border-color: var(--border-strong); }
.btn-outline:hover { background: var(--surface-alt); border-color: var(--accent-blue); color: var(--accent-blue); }
.btn-danger { background: var(--danger); color: #fff; }
.btn-ghost { background: transparent; color: var(--text-medium); }
.btn-ghost:hover { background: var(--surface-alt); }
.btn-sm { padding: 0.4rem 0.85rem; font-size: 0.78rem; }
.btn-icon { padding: 0.5rem; border-radius: var(--radius-sm); }
.btn:disabled { opacity: 0.5; cursor: not-allowed; transform: none !important; box-shadow: none !important; }

/* ---------- Forms ---------- */
label { display: block; font-size: 0.82rem; font-weight: 600; color: var(--text-medium); margin-bottom: 0.4rem; }
input[type=text], input[type=email], input[type=password], input[type=number], select, textarea {
    width: 100%;
    padding: 0.68rem 0.95rem;
    border: 1.5px solid var(--border-strong);
    border-radius: var(--radius-sm);
    font-size: 0.9rem;
    font-family: inherit;
    color: var(--text-dark);
    background: var(--surface);
}
input:focus, select:focus, textarea:focus {
    outline: none; border-color: var(--accent-blue);
    box-shadow: 0 0 0 3.5px rgba(59,111,237,0.13);
}
.field { margin-bottom: 1.05rem; }
.field-hint { font-size: 0.78rem; color: var(--text-light); margin-top: 0.35rem; }
.is-hidden { display: none !important; }

/* ---------- Filter chips ---------- */
.chip-bar { display: flex; align-items: center; gap: 0.55rem; flex-wrap: wrap; margin-bottom: 1.1rem; }
.chip {
    display: inline-flex; align-items: center; gap: 0.4rem;
    padding: 0.42rem 0.85rem;
    border-radius: 999px;
    border: 1.5px solid var(--border-strong);
    background: var(--surface);
    font-size: 0.8rem; font-weight: 600; color: var(--text-medium);
    cursor: pointer;
    transition: all 0.15s ease;
    user-select: none;
}
.chip:hover { border-color: var(--accent-blue); color: var(--accent-blue); }
.chip.active { background: var(--light-blue); border-color: var(--accent-blue); color: var(--accent-blue-dark); }
.chip .count { background: rgba(0,0,0,0.06); border-radius: 999px; padding: 0.05rem 0.45rem; font-size: 0.72rem; }
.chip.active .count { background: rgba(59,111,237,0.15); }

/* ---------- Tables ---------- */
.table-scroll { overflow-x: auto; }
/* Ledgers table only: a real vertical scroller so the 50-at-a-time
   pagination in ledgers.html's applyView()/scroll listener actually has
   something to scroll WITHIN — .table-scroll above only ever handled
   horizontal overflow, so with no height cap the whole page just grew
   with every ledger and the "load 50 more on scroll" logic never fired
   (there was nothing to scroll inside the box, only the page itself).
   Scoped to this one table's id, not added to .table-scroll generally, so
   every other table on the app (Review Transactions, etc.) keeps its
   existing no-cap behavior untouched. */
#ledgersScroll { max-height: 640px; overflow-y: auto; }

/* ---------- Ledgers page: multi-select filter dropdowns (Parent group /
   Sub grouping / Ledger). A plain <select multiple> needs ctrl/cmd-click to
   pick more than one option, which isn't obvious — this is a small
   checkbox-list dropdown instead: click the button, tick any number of
   options, close it. Scoped entirely under .ms- classes, used only on the
   Ledgers filter panel. ---------- */
.ms-field { position: relative; }
.ms-toggle { display: flex; width: 100%; }
.ms-dropdown {
    position: absolute; top: calc(100% + 0.3rem); left: 0; z-index: 40;
    background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm);
    box-shadow: 0 8px 24px rgba(20,25,40,0.14);
    min-width: 220px; max-width: 320px; padding: 0.5rem;
}
.ms-dropdown-actions { display: flex; gap: 0.5rem; margin-bottom: 0.4rem; padding-bottom: 0.4rem; border-bottom: 1px solid var(--border); }
.ms-mini {
    border: none; background: none; color: var(--accent-blue); font-size: 0.74rem; font-weight: 600;
    cursor: pointer; padding: 0.1rem 0.3rem;
}
.ms-mini:hover { text-decoration: underline; }
.ms-options { max-height: 220px; overflow-y: auto; }
.ms-option {
    display: flex; align-items: center; gap: 0.5rem; font-size: 0.82rem; font-weight: 400;
    padding: 0.3rem 0.3rem; border-radius: 4px; cursor: pointer; margin-bottom: 0;
}
.ms-option:hover { background: var(--surface-alt); }
.ms-option input { width: auto; margin: 0; }
.ms-option-empty { padding: 0.4rem 0.3rem; color: var(--text-light); font-size: 0.78rem; }
table.data-table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 0.86rem; min-width: 720px; }
table.data-table thead th {
    background: var(--surface-alt);
    color: var(--text-medium);
    text-align: left; padding: 0.55rem 0.85rem; font-weight: 700;
    font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.04em;
    border-bottom: 1px solid var(--border);
    white-space: nowrap;
}
table.data-table thead th .sort-icon { opacity: 0.4; margin-left: 0.25rem; vertical-align: -3px; }

/* Click-to-sort column headers (Transaction Date, Debit, Credit — see
   review.js's initSortableColumns). A small button sits right next to the
   header text, same idea as Mysa's per-column sort caret; clicking toggles
   ascending/descending and highlights the active column. */
table.data-table thead th[data-sort] { padding-right: 0.5rem; }
table.data-table thead th .sort-btn {
    display: inline-flex; align-items: center; justify-content: center;
    margin-left: 0.3rem; padding: 0.15rem; border: none; border-radius: 4px;
    background: transparent; color: var(--text-light); cursor: pointer;
    vertical-align: -3px; transition: background 0.15s ease, color 0.15s ease;
}
table.data-table thead th .sort-btn:hover { background: var(--border); color: var(--text-medium); }
table.data-table thead th.sort-active .sort-btn { color: var(--accent-blue); }
table.data-table thead th.sort-active[data-sort-dir="desc"] .sort-btn svg { transform: rotate(180deg); }
table.data-table tbody td { padding: 0.5rem 0.85rem; border-bottom: 1px solid var(--border); vertical-align: middle; color: var(--text-dark); }
table.data-table tbody tr:last-child td { border-bottom: none; }
table.data-table tbody tr:hover td { background: var(--surface-alt); }

/* Inline-editable Review Transactions cells: Cheque No, Description,
   Voucher No., Bill Ref No (see review.js's .editable-cell handler). Looks
   like plain text until hovered/focused, so the table doesn't read as a
   form by default.
   NOTE: selector is `input.editable-cell, textarea.editable-cell`, NOT a
   bare `.editable-cell` — the global `input[type=text], ...` rule above
   (~line 319) has specificity (0,0,1,1) via its attribute selector, which
   beats a bare `.editable-cell` class selector (0,0,1,0) regardless of
   source order, so the "invisible" styling below was silently losing to
   the boxed default input look. Tying specificity at (0,0,1,1) and
   appearing later in the file is what makes this win — same reasoning
   applies to the Description field now that it's a <textarea> (see
   .editable-narration below), since the global rule also targets a bare
   `textarea` element selector. */
input.editable-cell, textarea.editable-cell {
    border: 1px solid transparent; background: transparent; padding: 0.2rem 0.35rem;
    margin: -0.2rem -0.35rem; border-radius: 6px; font: inherit; color: inherit;
    width: 100%; min-width: 70px; transition: border-color 0.15s ease, background 0.15s ease;
    box-shadow: none;
}
input.editable-cell::placeholder, textarea.editable-cell::placeholder { color: var(--text-light); }
input.editable-cell:hover, textarea.editable-cell:hover { background: var(--surface); border-color: var(--border); }
input.editable-cell:focus, textarea.editable-cell:focus { border-color: var(--accent-blue); background: var(--surface); outline: none; box-shadow: 0 0 0 3px rgba(59,111,237,0.12); }

/* Description column: a <textarea> (not <input>) specifically so the full
   narration can wrap onto a second line instead of being clipped to one —
   most of the text shows on the first line, the remainder wraps below,
   rather than hiding behind a fixed-width single-line box. */
.narration-cell { width: 320px; }
textarea.editable-narration {
    min-width: 260px; resize: none; overflow-y: auto; overflow-x: hidden;
    white-space: normal; word-break: break-word; line-height: 1.35;
}
/* Possible-duplicate rows used to render at opacity:0.45, which made them
   look disabled/greyed-out rather than "flag this if it's a repeat entry".
   Now they stay fully readable — a soft amber tint + left rail marks the
   row instead, and the .dup-flag pill (see below) names the reason. */
table.data-table tbody tr.row-duplicate td { background: #fffaf0; }
table.data-table tbody tr.row-duplicate:hover td { background: #fef3dc; }
table.data-table tbody tr.row-duplicate td:first-child { box-shadow: inset 3px 0 0 var(--warning); }
table.data-table td.num { text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; }
table.data-table td.muted { color: var(--text-light); }

table.data-table select { padding: 0.4rem 0.6rem; font-size: 0.82rem; border-radius: 7px; }

/* ---------- Sr No. / row-select columns (Review Transactions) — the
   selection checkbox column sits at the LEFT of Sr No. (per your explicit
   instruction), both kept as narrow as the table allows. Sr No. is
   deliberately NOT the same thing as Voucher No. further along the row
   (it's the row's position in the original bank statement file, used to
   sort back to statement order when a statement lists transactions
   most-recent-first). ---------- */
table.data-table td.col-srno, table.data-table th.col-srno {
    width: 3.2rem; min-width: 3.2rem; text-align: center;
    color: var(--text-light); font-variant-numeric: tabular-nums; font-weight: 600;
}
table.data-table td.col-select, table.data-table th.col-select { width: 2.1rem; min-width: 2.1rem; text-align: center; }
table.data-table td.col-select input, table.data-table th.col-select input { width: auto; margin: 0; }

/* Editable Transaction Date cell */
input.editable-date { min-width: 132px; color-scheme: light; }

/* ---------- Floating bulk ledger-assignment bar — appears the moment one
   or more transactions are ticked and stays pinned to the bottom of the
   VIEWPORT (not the table), so it's reachable no matter how far down the
   table you've scrolled — same idea as the bulk-delete bar on the Ledgers
   page, but floating instead of inline, since this table is usually much
   longer. ---------- */
.bulk-assign-bar {
    position: fixed; left: 50%; bottom: 1.4rem; transform: translate(-50%, 24px);
    background: var(--text-dark); color: #fff; border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg); padding: 0.8rem 1.1rem; z-index: 9998;
    opacity: 0; pointer-events: none; transition: opacity 0.2s ease, transform 0.2s ease;
    max-width: calc(100vw - 2rem);
}
.bulk-assign-bar.show { opacity: 1; pointer-events: auto; transform: translate(-50%, 0); }
.bulk-assign-inner { display: flex; align-items: center; gap: 0.65rem; flex-wrap: wrap; }
.bulk-assign-bar .bulk-assign-count { font-size: 0.85rem; font-weight: 600; white-space: nowrap; padding-right: 0.3rem; }
.bulk-assign-bar select {
    background: #fff; color: var(--text-dark); border: none; padding: 0.5rem 0.7rem;
    border-radius: 8px; font-size: 0.83rem; width: auto; min-width: 150px;
}

/* ---------- Advanced filter panel, and the Voucher Series toggle popover
   next to it — both share this same popover look (position:absolute under
   their own toggle button, shown/hidden via the .show class), so the
   Voucher Series markup in review.html reuses this class directly rather
   than duplicating these rules. ---------- */
.filter-active-count {
    display: inline-block; width: 7px; height: 7px; border-radius: 50%;
    background: var(--accent-blue); margin-left: 0.35rem; vertical-align: middle;
}
.filter-panel {
    position: absolute; top: calc(100% + 0.5rem); right: 0; z-index: 60;
    background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg); padding: 1.1rem 1.2rem; width: 380px; max-width: calc(100vw - 2rem);
    display: none;
}
.filter-panel.show { display: block; animation: fadeInUp 0.15s ease both; }
.filter-panel .modal-close { top: 0.4rem; right: 0.4rem; }
.filter-panel .filter-row { display: flex; gap: 0.6rem; margin-bottom: 0.8rem; }
.filter-panel .filter-row:last-of-type { margin-bottom: 0; }
.filter-panel .filter-row > div { flex: 1; min-width: 0; }
.filter-panel label { font-size: 0.72rem; margin-bottom: 0.25rem; }
.filter-panel input, .filter-panel select { padding: 0.5rem 0.6rem; font-size: 0.82rem; margin-bottom: 0; }
.filter-panel-actions { display: flex; gap: 0.6rem; margin-top: 1rem; }

.dup-flag {
    display: inline-flex; align-items: center; gap: 0.3rem;
    margin-left: 0.5rem; padding: 0.1rem 0.5rem; border-radius: 999px;
    background: var(--warning-bg); color: #a9760f;
    font-size: 0.68rem; font-weight: 700; white-space: nowrap; vertical-align: middle;
}

.row-actions { display: flex; flex-direction: column; align-items: flex-start; gap: 0.4rem; }
.action-toggle {
    display: inline-flex; align-items: center; gap: 0.3rem;
    font-weight: 500; font-size: 0.74rem; color: var(--text-medium);
    cursor: pointer; margin-bottom: 0;
}
.action-toggle input[type=checkbox] { width: auto; }

/* row avatar (initials circle) for ledger/party names */
.row-avatar {
    display: inline-flex; align-items: center; justify-content: center;
    width: 26px; height: 26px; border-radius: 8px;
    font-size: 0.68rem; font-weight: 700; color: #fff;
    margin-right: 0.55rem; flex-shrink: 0; vertical-align: middle;
}
.cell-with-avatar { display: flex; align-items: center; }

/* ---------- Status badges (pill w/ dot) ---------- */
.badge {
    display: inline-flex; align-items: center; gap: 0.4rem;
    padding: 0.32rem 0.7rem 0.32rem 0.55rem; border-radius: 999px;
    font-size: 0.74rem; font-weight: 700;
}
.badge::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex-shrink: 0; }
.badge-matched { background: var(--success-bg); color: var(--success); }
.badge-review { background: var(--warning-bg); color: #a9760f; }
.badge-unmapped { background: var(--danger-bg); color: var(--danger); }
.badge-duplicate { background: var(--neutral-bg); color: var(--text-light); }
.badge-new { background: var(--light-blue); color: var(--accent-blue-dark); }

.confidence-bar { width: 54px; height: 5px; background: var(--neutral-bg); border-radius: 4px; overflow: hidden; display: inline-block; vertical-align: middle; margin-right: 0.45rem; }
/* display:block is required here — .confidence-fill is a <span> (inline by
   default), and plain inline elements silently IGNORE the width/height CSS
   properties entirely. Without this, the inline "width:NN%" set per-row in
   review.html has zero visual effect and the bar always renders empty,
   regardless of the actual confidence value. */
.confidence-fill { display: block; height: 100%; min-width: 2px; background: linear-gradient(90deg, var(--accent-blue), #35b34a); }

/* ---------- Status dropdown (Review Transactions) — colored text only,
   no pill background, so the 4 statuses are unmistakable at a glance:
   Need Review = red, Mapped = green, Unmapped (Suspense) = yellow,
   New Ledger = blue. ---------- */
select.status-select {
    font-weight: 700;
    padding: 0.4rem 0.55rem;
    border-radius: 7px;
    border: 1.5px solid var(--border-strong);
    background: var(--surface);
    min-width: 165px;
}
select.status-select.status-review { color: var(--danger); border-color: #f3c6cb; }
select.status-select.status-mapped { color: var(--success); border-color: #bfe8cd; }
select.status-select.status-suspense { color: #ca8a04; border-color: #f2dfa3; }
select.status-select.status-new_ledger { color: var(--accent-blue); border-color: var(--border-blue); }

/* ---------- Upload dropzone ---------- */
.dropzone {
    border: 2px dashed var(--border-blue);
    border-radius: var(--radius-lg);
    padding: 3rem 2rem;
    text-align: center;
    background: var(--lighter-blue);
    cursor: pointer;
    transition: all 0.2s ease;
}
.dropzone:hover, .dropzone.drag-over { background: var(--light-blue); border-color: var(--accent-blue); transform: translateY(-2px); box-shadow: var(--shadow-md); }
.dropzone .icon-circle {
    width: 60px; height: 60px; border-radius: 16px;
    background: #fff; color: var(--accent-blue);
    display: flex; align-items: center; justify-content: center;
    margin: 0 auto 1.1rem; box-shadow: var(--shadow-xs);
}
.dropzone .title { font-size: 1.05rem; font-weight: 700; color: var(--text-dark); margin-bottom: 0.35rem; }
.dropzone .subtitle { color: var(--text-medium); font-size: 0.85rem; }

/* ---------- Client cards / dashboard ---------- */
.client-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(270px, 1fr)); gap: 1.1rem; }
.client-card {
    background: var(--surface); border-radius: var(--radius-lg); padding: 1.4rem;
    box-shadow: var(--shadow-xs); border: 1px solid var(--border); border-top: 3px solid var(--accent-blue);
    transition: transform 0.18s ease, box-shadow 0.18s ease;
}
.client-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); }
.client-card .client-top { display: flex; align-items: center; gap: 0.7rem; margin-bottom: 0.9rem; }
.client-card h3 { color: var(--text-dark); font-size: 1.02rem; font-weight: 700; }
.client-card .meta { color: var(--text-light); font-size: 0.8rem; margin-top: 0.15rem; }
.add-client-card {
    display: flex; align-items: center; justify-content: center; gap: 0.5rem;
    border: 2px dashed var(--border-strong); border-radius: var(--radius-lg);
    color: var(--accent-blue); font-weight: 700; min-height: 130px;
    cursor: pointer; transition: all 0.18s ease; font-size: 0.9rem;
}
.add-client-card:hover { background: var(--light-blue); border-color: var(--accent-blue); }

/* ---------- Setup-choice cards (existing COA / brand-new company / connect
   your Tally) ---------- */
/* max-width sized so 3 cards land at the SAME per-card width the original
   2-card version had (auto-fit minmax(260px,1fr) inside an 820px container
   gave each of 2 cards ~400px) — otherwise adding the third "Connect your
   Tally" card just squeezes all three into the old 820px cap and makes
   every card visibly narrower than before, per your report. */
.setup-choice-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 1.2rem; max-width: 1240px; }
.setup-choice-card {
    display: flex; flex-direction: column; align-items: flex-start; gap: 0.3rem;
    background: var(--surface); border-radius: var(--radius-lg); padding: 1.6rem;
    box-shadow: var(--shadow-xs); border: 1px solid var(--border);
    text-decoration: none; color: inherit;
    transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}
.setup-choice-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); border-color: var(--accent-blue); }
.setup-choice-card .icon-circle {
    width: 52px; height: 52px; border-radius: 14px;
    background: var(--light-blue); color: var(--accent-blue);
    display: flex; align-items: center; justify-content: center; margin-bottom: 0.6rem;
}
.setup-choice-card h3 { font-size: 1.02rem; font-weight: 700; color: var(--text-dark); margin-bottom: 0.2rem; }
.setup-choice-card p { font-size: 0.85rem; line-height: 1.5; margin-bottom: 1.1rem; }
.setup-choice-card .btn { pointer-events: none; }

/* ---------- Auth pages ---------- */
.auth-shell {
    min-height: 125vh; /* see the 125vh zoom-compensation note on body, near the top of this file */
    display: flex; align-items: center; justify-content: center;
    background:
        radial-gradient(circle at 15% 20%, rgba(90,139,255,0.35), transparent 45%),
        radial-gradient(circle at 85% 80%, rgba(53,179,74,0.25), transparent 40%),
        linear-gradient(135deg, var(--primary-blue) 0%, var(--secondary-blue) 55%, #14295a 100%);
    padding: 2rem;
}
.auth-card {
    background: #fff; border-radius: 20px; box-shadow: var(--shadow-lg);
    width: 100%; max-width: 420px; padding: 2.5rem;
}
.auth-card img.logo { height: 42px; margin-bottom: 1.5rem; }
.auth-card h1 { font-size: 1.45rem; color: var(--text-dark); margin-bottom: 0.3rem; }
.auth-card .subtitle { color: var(--text-light); font-size: 0.88rem; margin-bottom: 1.7rem; }
.auth-card .btn { width: 100%; justify-content: center; padding: 0.85rem; margin-top: 0.5rem; }
.auth-switch { text-align: center; margin-top: 1.4rem; font-size: 0.86rem; color: var(--text-medium); }
.auth-divider { display: flex; align-items: center; gap: 0.8rem; margin: 1.1rem 0; color: var(--text-light); font-size: 0.78rem; }
.auth-divider::before, .auth-divider::after { content: ''; flex: 1; height: 1px; background: var(--border); }
.google-btn { display: flex; align-items: center; justify-content: center; gap: 0.6rem; }

/* ---------- Landing: simple two-box split (info left, login/signup right) ---------- */
.split-landing { display: flex; min-height: 125vh; } /* see the 125vh zoom-compensation note on body, near the top of this file */
.split-landing-left, .split-landing-right {
    flex: 1 1 50%; display: flex; flex-direction: column;
    align-items: center; justify-content: center; padding: 3rem 3rem;
    text-align: center;
}
.split-landing-left {
    color: #fff;
    background:
        radial-gradient(circle at 15% 20%, rgba(90,139,255,0.35), transparent 45%),
        radial-gradient(circle at 85% 80%, rgba(53,179,74,0.25), transparent 40%),
        linear-gradient(135deg, var(--primary-blue) 0%, var(--secondary-blue) 100%);
}
.split-landing-left img.logo { height: 52px; margin-bottom: 1.8rem; }
.split-landing-left h1 { font-size: 2.4rem; margin-bottom: 1.1rem; letter-spacing: -0.02em; max-width: 480px; }
.split-landing-left p { font-size: 1.02rem; opacity: 0.92; max-width: 460px; margin: 0 auto 2rem; }
.split-landing-steps {
    display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap;
    justify-content: center; font-size: 0.82rem; font-weight: 600;
    color: rgba(255,255,255,0.85); max-width: 480px;
}
.split-landing-steps .step-arrow { opacity: 0.55; }
.split-landing-right { background: var(--bg); }
.split-landing-card {
    background: #fff; border-radius: 20px; box-shadow: var(--shadow-lg);
    width: 100%; max-width: 380px; padding: 2.6rem 2.4rem; text-align: center;
    animation: fadeInUp 0.4s ease both;
}
.split-landing-card img.mark { height: 44px; margin-bottom: 1.3rem; }
.split-landing-card h2 { font-size: 1.4rem; color: var(--text-dark); margin-bottom: 0.4rem; }
.split-landing-card .subtitle { color: var(--text-light); font-size: 0.88rem; margin-bottom: 1.8rem; }
.split-landing-card .btn { width: 100%; justify-content: center; padding: 0.85rem; margin-bottom: 0.7rem; }

@media (max-width: 900px) {
    .split-landing { flex-direction: column; }
    .split-landing-left, .split-landing-right { padding: 2.5rem 1.5rem; }
}

/* ---------- Misc ---------- */
.text-muted { color: var(--text-light); }
.mt-1 { margin-top: 0.6rem; } .mt-2 { margin-top: 1.2rem; } .mt-3 { margin-top: 2rem; }
.flex-between { display: flex; align-items: center; justify-content: space-between; }
.flex-row { display: flex; align-items: center; gap: 0.6rem; }
.pill { background: var(--light-blue); color: var(--primary-blue); padding: 0.28rem 0.75rem; border-radius: 999px; font-size: 0.75rem; font-weight: 700; }
code, pre { font-family: 'JetBrains Mono', Consolas, monospace; }
pre.report-box { background: #0c1428; color: #cfe0ff; padding: 1.1rem; border-radius: var(--radius-sm); font-size: 0.8rem; overflow-x: auto; }
.empty-state { text-align: center; padding: 3rem 1.5rem; color: var(--text-light); }
.empty-state .icon-circle { width: 56px; height: 56px; border-radius: 16px; background: var(--light-blue); color: var(--accent-blue); display: flex; align-items: center; justify-content: center; margin: 0 auto 1rem; }

/* ---------- Info page (item 5/6): supported-banks chip grid + feedback
   attachment list ---------- */
.info-bank-grid { display: flex; flex-wrap: wrap; gap: 0.55rem; }
.info-bank-chip {
    display: inline-flex; align-items: center; gap: 0.4rem;
    padding: 0.4rem 0.8rem; border-radius: 999px;
    background: var(--success-bg); color: var(--success);
    font-size: 0.82rem; font-weight: 600;
}
.feedback-attach-row { display: flex; }
.feedback-attach-list { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.6rem; }
.feedback-attach-chip {
    background: var(--surface-alt); border: 1px solid var(--border); border-radius: 999px;
    padding: 0.3rem 0.75rem; font-size: 0.78rem; color: var(--text-medium);
}

/* ---------- Tag pills (profile: voucher types / master groups) ---------- */
.tag-list { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.tag-pill {
    display: inline-flex; align-items: center;
    padding: 0.4rem 0.85rem; border-radius: 999px;
    background: var(--light-blue); color: var(--accent-blue-dark);
    font-size: 0.8rem; font-weight: 600;
    transition: transform 0.12s ease, box-shadow 0.12s ease;
}
.tag-pill:hover { transform: translateY(-1px); box-shadow: var(--shadow-xs); }
.tag-pill.muted-pill { background: var(--surface-alt); color: var(--text-medium); border: 1px solid var(--border); }

/* ---------- Motion: subtle, modern entrance/interaction animations ---------- */
@keyframes tileIn {
    from { opacity: 0; transform: translateY(8px); }
    to { opacity: 1; transform: translateY(0); }
}
@keyframes fadeInUp {
    from { opacity: 0; transform: translateY(10px); }
    to { opacity: 1; transform: translateY(0); }
}
@keyframes fadeIn {
    from { opacity: 0; }
    to { opacity: 1; }
}
@keyframes spin {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
}
.refresh-btn:active .icon { animation: spin 0.5s linear; }

/* Small transient toast — used for the "Save as rule" real-time feedback
   (e.g. "also auto-mapped 3 other transactions"). Self-dismisses; see
   Relievv.showToast in review.js. Kept separate from the bigger XML
   generation summary modal (.xml-modal below), which needs to stay open
   longer and show more structured detail. */
.relievv-toast {
    position: fixed; bottom: 1.5rem; left: 50%; transform: translate(-50%, 20px);
    background: var(--text-dark); color: #fff; padding: 0.75rem 1.2rem;
    border-radius: var(--radius-sm); font-size: 0.85rem; max-width: 480px;
    box-shadow: 0 10px 30px rgba(0,0,0,0.25); z-index: 9999;
    opacity: 0; pointer-events: none; transition: opacity 0.25s ease, transform 0.25s ease;
}
.relievv-toast.show { opacity: 1; transform: translate(-50%, 0); pointer-events: auto; }

/* XML-generation result popup — shown after "Generate New Ledger XML" /
   "Generate Transaction XML" (see review.html + the ?generated= redirect
   param in statements/routes.py). Self-closes after 20s (see the countdown
   bar) or via the X / Close button / clicking the backdrop. */
.modal-backdrop {
    position: fixed; inset: 0; background: rgba(15, 20, 40, 0.5);
    display: flex; align-items: center; justify-content: center;
    z-index: 10000; opacity: 0; pointer-events: none; transition: opacity 0.2s ease;
    padding: 1rem;
}
.modal-backdrop.show { opacity: 1; pointer-events: auto; }
.modal-box {
    position: relative; background: var(--surface); border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg); padding: 1.6rem 1.8rem 1.4rem; width: 100%;
    max-width: 420px; transform: translateY(14px) scale(0.98); transition: transform 0.2s ease;
    overflow: hidden;
}
.modal-backdrop.show .modal-box { transform: translateY(0) scale(1); }
.modal-close {
    position: absolute; top: 0.7rem; right: 0.8rem; border: none; background: transparent;
    font-size: 1.3rem; line-height: 1; color: var(--text-light); cursor: pointer; padding: 0.2rem 0.4rem;
    border-radius: 6px;
}
.modal-close:hover { background: var(--surface-alt); color: var(--text-dark); }
.modal-icon {
    width: 46px; height: 46px; border-radius: 50%; display: flex; align-items: center;
    justify-content: center;
}
.modal-icon.success { background: var(--success-bg); color: var(--success); }
.modal-icon.warning { background: var(--warning-bg); color: var(--warning); }
.modal-icon.danger { background: var(--danger-bg); color: var(--danger); }
.modal-detail-grid {
    display: grid; grid-template-columns: 1fr 1fr; gap: 0.7rem 1rem; margin: 0.4rem 0 0.8rem;
}
.modal-detail-grid > div { display: flex; flex-direction: column; gap: 0.15rem; }
.modal-detail-grid .text-muted { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.02em; }
.modal-detail-grid strong { color: var(--text-dark); font-size: 0.9rem; word-break: break-word; }
.modal-actions { display: flex; gap: 0.6rem; margin-top: 1rem; }
.modal-timer-track {
    position: absolute; left: 0; right: 0; bottom: 0; height: 3px; background: var(--border);
}
.modal-timer-fill {
    height: 100%; width: 100%; background: var(--accent-blue); transition: width linear 0ms;
}
/* Bank-statement upload processing overlay — shown from the moment "Upload
   & process with AI" is clicked until the server finishes and redirects to
   the results popup (see upload_statement.html), so there's never a dead
   stretch where the page just looks frozen. */
.processing-overlay {
    position: fixed; inset: 0; background: rgba(15, 20, 40, 0.55);
    display: flex; align-items: center; justify-content: center;
    z-index: 10001; opacity: 0; pointer-events: none; transition: opacity 0.2s ease;
    padding: 1rem;
}
.processing-overlay.show { opacity: 1; pointer-events: auto; }
.processing-box {
    background: var(--surface); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
    padding: 2.3rem 2.2rem; width: 100%; max-width: 360px; text-align: center;
}
.processing-spinner {
    width: 46px; height: 46px; margin: 0 auto 1.3rem;
    border: 4px solid var(--surface-alt); border-top-color: var(--accent-blue);
    border-radius: 50%; animation: spin 0.85s linear infinite;
}
.processing-title { font-weight: 700; font-size: 1.05rem; color: var(--text-dark); margin-bottom: 0.35rem; }
.processing-step { font-size: 0.85rem; color: var(--text-medium); min-height: 1.3em; }

/* ---------- "Connect your Tally" feature: topbar badge, status dot,
   Tally Connecting status box, COA-sync progress bar. Reuses the existing
   badge/modal/confidence-bar visual language rather than introducing a new
   style — see review comments on each rule below. ---------- */
.tally-status-topbar-wrap { display: flex; flex-direction: column; align-items: flex-end; }
.tally-status-badge {
    display: inline-flex; align-items: center; gap: 0.55rem;
    padding: 0.42rem 0.85rem; border-radius: 999px;
    background: var(--surface-alt); border: 1px solid var(--border);
    font-size: 0.8rem; font-weight: 700; color: var(--text-medium);
    white-space: nowrap;
}
.status-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
.status-dot-green { background: var(--success); box-shadow: 0 0 0 3px var(--success-bg); }
.status-dot-grey { background: var(--text-light); box-shadow: 0 0 0 3px var(--neutral-bg); }

.tally-status-box {
    display: flex; align-items: center; gap: 0.9rem;
    padding: 0.95rem 1.1rem; background: var(--surface-alt); border-radius: var(--radius-sm);
}
.tally-status-box .status-dot { width: 14px; height: 14px; }

/* Simulated 0%->100% COA-sync progress bar (upload_coa.html) — same visual
   treatment as the auto-close countdown bar (.modal-timer-track/-fill)
   above, just taller and driven by JS-ticked width instead of a CSS
   transition on a fixed duration. */
.sync-progress-track {
    width: 100%; height: 8px; background: var(--border); border-radius: 999px; overflow: hidden;
}
.sync-progress-fill {
    height: 100%; width: 0%; background: linear-gradient(90deg, var(--accent-blue), #35b34a);
    transition: width 0.2s ease;
}

/* Two cards side by side (Tally Connecting Status + Select Tally Company;
   Upload Chart of Accounts + Sync Chart of Accounts from Tally) — each card
   keeps a sensible max width and wraps to stacked on narrow viewports
   rather than a rigid grid, since the right-hand card here is conditional
   (only rendered once connected/Tally-enabled). */
.side-by-side-cards { display: flex; gap: 1.2rem; align-items: flex-start; flex-wrap: wrap; margin-bottom: 1.5rem; }
.side-by-side-cards > .card { flex: 1 1 380px; max-width: 480px; margin-bottom: 0; }

.card { animation: fadeInUp 0.35s ease both; }
.content > *:nth-child(1) { animation-delay: 0s; }
.content > *:nth-child(2) { animation-delay: 0.04s; }
.content > *:nth-child(3) { animation-delay: 0.08s; }
.content > *:nth-child(4) { animation-delay: 0.12s; }
.flash { animation: fadeInUp 0.3s ease both; }
.client-card { animation: fadeInUp 0.3s ease both; }
table.data-table tbody tr { transition: background 0.12s ease; }
.badge { transition: transform 0.12s ease; }
.chip { animation: fadeIn 0.3s ease both; }
.sidebar-nav a, .btn, .stat-tile, .tag-pill, .client-card, .dropzone { will-change: transform; }

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
    }
}

@media (max-width: 900px) {
    .app-shell { flex-direction: column; }
    .sidebar { width: 100%; height: auto; position: relative; }
    .content { padding: 1.2rem; }
}
