/* ------------------------------------------------------------------------
   Component styles for the FinVentures merchant portal.

   Every value here resolves to a token from tokens.css. Measurements come
   straight from the design handoff: 264px sidebar, 40px/48px content
   padding, 24px card padding, 20px grid gaps, 24px between stacked cards.
   ------------------------------------------------------------------------ */

*,
*::before,
*::after {
    box-sizing: border-box;
}

body {
    margin: 0;
    font-family: var(--font-primary);
    background: var(--fv-slate-100);
    color: var(--text-body);
    line-height: 1.5;
}

a {
    color: var(--text-link);
}

a:hover {
    color: var(--text-link-hover);
}

/* --- Shell -------------------------------------------------------------- */

/* height, not min-height, and the overflow hidden with it. Together these
   stop the PAGE scrolling and hand scrolling to the two columns instead, so
   the navigation stays put while a long table moves under it.

   With min-height the shell grew to fit its content, .content had nothing to
   overflow against, and its overflow:auto did nothing - the whole document
   scrolled and took the sidebar with it. */
.shell {
    display: flex;
    height: 100vh;
    overflow: hidden;
}

/* --- Sidebar ------------------------------------------------------------ */

.sidebar {
    width: 264px;
    flex: 0 0 264px;
    background: var(--fv-navy);
    display: flex;
    flex-direction: column;
    padding: 28px 16px;
    /* Eight nav rows plus the user block can exceed a short viewport, so the
       sidebar scrolls on its own rather than being clipped. */
    overflow-y: auto;
}

.sidebar__brand {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    margin-bottom: 24px;
}

/* The approved logo asset.

   96px rather than the prototype's 64px: it sits on the 4px spacing grid and
   clears the 80px minimum size the brand guidelines require, which the
   prototype's 64px tile did not.

   Deliberately NO border-radius. The logo is a square tile with its own black
   keyline; rounding the corners would clip that border, which counts as
   cropping the approved asset. object-fit: contain keeps it undistorted. */
.sidebar__logo {
    width: 96px;
    height: 96px;
    display: block;
    object-fit: contain;
}

.sidebar__wordmark {
    color: var(--fv-white);
    font-weight: var(--weight-bold);
    font-size: 15px;
    letter-spacing: var(--tracking-wide);
}

.sidebar__merchant {
    padding: 14px 12px 20px;
    border-bottom: 1px solid var(--fv-navy-800);
    margin-bottom: 12px;
}

.eyebrow-dark {
    color: var(--fv-slate-400);
    font-size: 11px;
    font-weight: var(--weight-bold);
    letter-spacing: var(--tracking-wide);
    text-transform: uppercase;
}

.sidebar__merchant-name {
    color: var(--fv-white);
    font-size: 16px;
    font-weight: var(--weight-bold);
    margin-top: 4px;
}

.sidebar__merchant-meta {
    color: var(--fv-slate-400);
    font-size: 12px;
    margin-top: 6px;
}

.nav {
    display: flex;
    flex-direction: column;
    gap: 4px;
    flex: 1;
}

.nav__row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 14px;
    border-radius: 8px;
    font-size: 15px;
    text-decoration: none;
    color: var(--fv-slate-400);
    font-weight: var(--weight-regular);
    transition: background var(--motion-fast) var(--ease),
                color var(--motion-fast) var(--ease);
}

.nav__row:hover {
    background: rgba(255, 255, 255, .06);
    color: var(--fv-white);
}

.nav__row.is-active {
    background: var(--fv-navy-800);
    color: var(--fv-white);
    font-weight: var(--weight-semibold);
}

.nav__icon {
    width: 18px;
    text-align: center;
}

.nav__label {
    flex: 1;
}

.nav__count {
    background: var(--fv-yellow);
    color: var(--fv-black);
    font-size: 11px;
    font-weight: var(--weight-bold);
    border-radius: var(--radius-pill);
    padding: 2px 8px;
    min-width: 20px;
    text-align: center;
}

.sidebar__user {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 20px;
    padding-top: 20px;
    border-top: 1px solid var(--fv-navy-800);
}

.sidebar__avatar {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--fv-yellow);
    color: var(--fv-black);
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    font-size: 16px;
}

.sidebar__user-name {
    color: var(--fv-white);
    font-size: 14px;
    font-weight: var(--weight-bold);
}

.sidebar__user-role {
    color: var(--fv-slate-400);
    font-size: 12px;
}

/* One-shot confirmation banner at the top of the content column.
   Uses the existing success tokens rather than inventing a green ramp:
   --state-success-bg is the same tint the alert icons use. */
.page-notice {
    display: flex;
    align-items: center;
    gap: 9px;
    margin-bottom: 20px;
    padding: 11px 14px;
    border-radius: var(--radius-md);
    font-size: 14px;
    background: var(--state-success-bg);
    border-left: 3px solid var(--fv-success);
    color: var(--text-body);
}

/* The Fees comparison's "your profile was updated" note.

   Neutral, not the green of .page-notice: that green means something went
   right, and this is information — nothing went right or wrong, the charges
   simply span two agreements. Slate, the colour this portal uses for context.

   Sits inside a flush card, so it takes the card's 24px side inset to line up
   with the table columns beneath it, and aligns its icon to the first line
   because the sentence wraps to two or three. */
.feecompare__note {
    align-items: flex-start;
    margin: 0 24px 16px;
    background: var(--surface-subtle);
    border-left-color: var(--fv-slate-400);
    line-height: 1.55;
}

.feecompare__note i {
    color: var(--fv-slate-400);
    margin-top: 3px;
}

.page-notice i {
    color: var(--fv-success);
}

/* Same banner, used to report that something could not be loaded rather than
   that something succeeded. Warning rather than danger: the merchant has lost
   nothing, the screen just cannot show it right now. */
.page-notice--warn {
    background: var(--state-warning-bg);
    border-left-color: var(--fv-gold);
}

.page-notice--warn i {
    color: var(--fv-gold);
}

/* Pushes the sign-out button to the far edge of the user row. */
.sidebar__logout {
    margin-left: auto;
}

.sidebar__logout-btn {
    background: none;
    border: none;
    padding: 6px;
    cursor: pointer;
    color: var(--fv-slate-400);
    font-size: 14px;
    line-height: 1;
    border-radius: 4px;
}

.sidebar__logout-btn:hover {
    color: var(--fv-white);
    background: var(--fv-navy-800);
}

/* Keyboard users need to see focus; the button is icon-only, so without this
   there is no indication of where they are. */
.sidebar__logout-btn:focus-visible {
    outline: 2px solid var(--fv-yellow);
    outline-offset: 2px;
}

/* --- Content column ----------------------------------------------------- */

.content {
    flex: 1;
    min-width: 0;
    padding: 40px 48px;
    overflow-y: auto;
}

.page-header {
    margin-bottom: 28px;
}

.page-title {
    font-size: 32px;
    font-weight: var(--weight-bold);
    color: var(--text-heading);
}

.page-subtitle {
    color: var(--text-muted);
    margin-top: 6px;
    font-size: 16px;
}

/* --- Card --------------------------------------------------------------- */

.card {
    background: var(--surface-card);
    border-radius: var(--radius-card);
    box-shadow: var(--shadow-sm);
    padding: 24px;
    transition: box-shadow var(--motion-base) var(--ease);
}

.card:hover {
    box-shadow: var(--shadow-md);
}

/* Table cards carry no padding; their header and table supply their own. */
.card--flush {
    padding: 0;
}

.card__header {
    padding: 20px 24px;
    font-size: 16px;
    font-weight: var(--weight-bold);
    color: var(--text-heading);
    border-bottom: 1px solid var(--border-subtle);
}

.card__title {
    font-size: 16px;
    font-weight: var(--weight-bold);
    color: var(--text-heading);
    margin-bottom: 20px;
}

/* --- Grids -------------------------------------------------------------
   Always auto-fit + minmax, never a fixed track count, so columns reflow
   and collapse by available width. */

.grid {
    display: grid;
    gap: 20px;
    margin-bottom: 20px;
}

.grid--kpi {
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}

.grid--charts {
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}

/* Three-up stat tiles: slightly wider minimum than the four-up KPI grid. */
.grid--stats {
    grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
}

/* --- KPI tile ----------------------------------------------------------- */

.kpi__label {
    color: var(--text-muted);
    font-size: 14px;
}

.kpi__value {
    font-size: 28px;
    font-weight: var(--weight-bold);
    color: var(--text-heading);
    margin-top: 10px;
}

.kpi__sub {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: 10px;
    font-size: 14px;
    font-weight: var(--weight-semibold);
}

/* --- Bar chart ---------------------------------------------------------- */

/* The bar chart.

   This used to burst out of its card and overlap the one beside it, and the
   cause is the most common flexbox trap there is: a flex item's default
   min-width is `auto`, which means "never shrink below your own content". The
   columns each held a 28px bar and a `white-space: nowrap` label, so seven of
   them plus six 16px gaps had a hard floor of roughly 360px. Put that in a
   330px card and flex cannot honour `flex: 1` — it overflows instead.

   Three changes fix it: min-width lets a column shrink, the bar sizes from the
   column rather than a fixed 28px, and the gap scales down before anything
   else has to. overflow-x is the backstop for a genuinely tiny card, matching
   how .table-wrap already handles wide tables. */
.bars {
    display: flex;
    align-items: flex-end;
    gap: clamp(5px, 1.6%, 16px);
    height: 230px;
    overflow-x: auto;
    /* Room for the scrollbar when it appears, so it never sits on the labels. */
    padding-bottom: 4px;
}

.bars__col {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-end;
    flex: 1 1 0;
    /* Wide enough for "May 21" at 11px; below this the container scrolls
       rather than the labels becoming unreadable. */
    min-width: 34px;
    height: 100%;
}

.bars__bar {
    width: 100%;
    max-width: 28px;
    background: var(--fv-navy);
    border-radius: 4px 4px 0 0;
}

.bars__label {
    font-size: 11px;
    color: var(--text-muted);
    margin-top: 8px;
    white-space: nowrap;
}

/* --- Donut -------------------------------------------------------------
   A CSS conic-gradient, not a charting library. The service builds the
   gradient string; this only sizes and clips it. */

/* The conic-gradient paints a filled pie; the mask punches the hole that makes
   it a donut. Without it a merchant whose activity is all one card type sees a
   plain navy circle with no information in it at all.

   A mask rather than a white circle on top: the card is not always white — a
   placeholder card is tinted — and an opaque plug would show as a pale disc
   sitting on a darker background. */
.donut {
    width: 140px;
    height: 140px;
    border-radius: 50%;
    margin: 0 auto 20px;
    -webkit-mask: radial-gradient(circle, transparent 54%, #000 55%);
    mask: radial-gradient(circle, transparent 54%, #000 55%);
}

.legend__row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-size: 13px;
    padding: 6px 0;
}

.legend__name {
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--text-body);
}

.legend__dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    flex: 0 0 auto;
}

.legend__pct {
    font-weight: var(--weight-semibold);
    color: var(--text-heading);
}

/* --- Table -------------------------------------------------------------
   Wrapped in .table-wrap so wide tables scroll inside their card rather
   than clipping or stretching the page. */

.table-wrap {
    overflow-x: auto;
}

table.data {
    width: 100%;
    border-collapse: collapse;
    font-size: 14px;
}

table.data th {
    text-align: left;
    padding: 12px 24px;
    font-size: 11px;
    font-weight: var(--weight-bold);
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: var(--tracking-caps);
    border-bottom: 1px solid var(--border-subtle);
    white-space: nowrap;
}

table.data td {
    padding: 14px 24px;
    color: var(--text-body);
    border-bottom: 1px solid var(--border-subtle);
    white-space: nowrap;
}

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

/* --- Badge -------------------------------------------------------------- */

.badge {
    display: inline-block;
    padding: 2px 10px;
    border-radius: var(--radius-pill);
    font-size: 12px;
    font-weight: var(--weight-semibold);
    text-transform: capitalize;
}

.badge--success {
    background: var(--state-success-bg);
    color: var(--fv-success);
}

.badge--warning {
    background: var(--state-warning-bg);
    color: var(--fv-warning);
}

.badge--danger {
    background: var(--state-danger-bg);
    color: var(--fv-danger);
}

.badge--neutral {
    background: var(--fv-slate-200);
    color: var(--text-muted);
}

.badge--navy {
    background: var(--fv-navy);
    color: var(--fv-white);
}

/* A badge with a qualifier: one pill, two halves — "Capture | Pre-auth
   completion". The first half is the badge as it always is, in its tone; the
   second says how the terminal ran it, on a lighter tint of the same tone, so
   the pair reads as one object in every colour without a rule per tone.
   Used on the transactions table when TransactionType.addsTo(kind). */
.badge--pair {
    display: inline-flex;
    align-items: stretch;
    padding: 0;
    overflow: hidden;
    white-space: nowrap;
}

.badge--pair > span {
    padding: 2px 10px;
}

.badge__qual {
    border-left: 1px solid rgba(255, 255, 255, .9);
    background: rgba(255, 255, 255, .55);
    color: var(--text-body);
    font-weight: 500;
    text-transform: none;          /* .badge capitalises; "Pre-Auth Completion" is wrong */
}

/* --- Not-yet-built screens ---------------------------------------------- */

.placeholder {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: 64px 24px;
    color: var(--text-muted);
}

.placeholder__icon {
    font-size: 28px;
    color: var(--fv-slate-400);
    margin-bottom: 16px;
}

.placeholder__title {
    font-size: 16px;
    font-weight: var(--weight-bold);
    color: var(--text-heading);
    margin-bottom: 8px;
}

.placeholder__body {
    font-size: 14px;
    max-width: 48ch;
    margin: 0;
}

/* --- Page header with a right-aligned action --------------------------- */

.page-header--split {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
}

/* --- Buttons -----------------------------------------------------------
   Two variants from the design: alt (navy fill) and outline. Press scales
   to 98%; hover lifts navy to navy-800 and gives outline a slate wash. */

.btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 44px;
    padding: 0 18px;
    border-radius: var(--radius-input);
    font-family: inherit;
    font-size: 14px;
    font-weight: var(--weight-semibold);
    cursor: pointer;
    border: 1px solid transparent;
    transition: background var(--motion-fast) var(--ease),
                border-color var(--motion-fast) var(--ease),
                transform var(--motion-fast) var(--ease);
}

.btn:active {
    transform: scale(.98);
}

.btn:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px rgba(15, 23, 42, .35);
}

.btn--alt {
    background: var(--fv-navy);
    color: var(--fv-white);
}

.btn--alt:hover {
    background: var(--fv-navy-800);
}

.btn--outline {
    background: transparent;
    color: var(--text-heading);
    border-color: var(--border-default);
}

.btn--outline:hover {
    background: var(--fv-slate-100);
}

/* --- Form controls ------------------------------------------------------ */

.input {
    width: 100%;
    height: 44px;
    padding: 0 12px;
    font-family: inherit;
    font-size: 14px;
    color: var(--text-body);
    background: var(--surface-card);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-input);
}

.input:focus {
    outline: none;
    border-color: var(--fv-navy);
    box-shadow: 0 0 0 3px rgba(15, 23, 42, .35);
}

/* --- Filter bar --------------------------------------------------------- */

.filters {
    margin-bottom: 24px;
}

.filters__row {
    display: flex;
    gap: 16px;
    align-items: flex-end;
    flex-wrap: wrap;
}

.filters__search {
    flex: 1;
    min-width: 240px;
}

.filters__select {
    width: 160px;
}

.filters__select--wide {
    width: 200px;
}

.filters__meta {
    margin-top: 14px;
    display: flex;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 8px;
    font-size: 13px;
    color: var(--text-muted);
}

/* --- Table link --------------------------------------------------------- */

.tx-link {
    font-weight: var(--weight-semibold);
    text-decoration: none;
}

.tx-link:hover {
    text-decoration: underline;
}

/* --- Small uppercase section label -------------------------------------- */

.eyebrow {
    font-size: 11px;
    font-weight: var(--weight-bold);
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
    color: var(--text-muted);
}

/* --- Transaction drawer -------------------------------------------------
   The scrim is an <a> back to /transactions, so clicking outside closes the
   drawer with no JavaScript. */

.scrim {
    position: fixed;
    inset: 0;
    background: var(--scrim);
    z-index: 40;
    display: block;
}

.drawer {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    width: 480px;
    max-width: 100%;
    background: var(--surface-card);
    box-shadow: var(--shadow-lg);
    z-index: 41;
    display: flex;
    flex-direction: column;
}

.drawer__header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    padding: 24px;
    border-bottom: 1px solid var(--border-subtle);
}

/* The transaction id, one part per line (TransactionDetail.idParts). The
   first part leads, at the size the whole id used to have; the rest are
   monospaced, a size down, so a 34-digit reference fits the drawer and can
   be read digit by digit against another system. */
.drawer__id {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin-top: 4px;
    min-width: 0;
    color: var(--text-heading);
}

.drawer__id-part {
    font-family: ui-monospace, "SFMono-Regular", "Cascadia Mono", Consolas, monospace;
    font-size: 15px;
    font-weight: var(--weight-semibold);
    color: var(--text-body);
    overflow-wrap: anywhere;
}

.drawer__id-part:first-child {
    font-family: inherit;
    font-size: 22px;
    font-weight: var(--weight-bold);
    color: var(--text-heading);
}

.drawer__close {
    color: var(--text-muted);
    font-size: 18px;
    padding: 4px;
    text-decoration: none;
    line-height: 1;
}

.drawer__close:hover {
    color: var(--text-heading);
}

.drawer__body {
    flex: 1;
    overflow-y: auto;
    padding: 24px;
}

.drawer__amount {
    display: flex;
    align-items: baseline;
    gap: 12px;
    font-size: 32px;
    font-weight: var(--weight-bold);
    color: var(--text-heading);
    margin-bottom: 8px;
}

.drawer__currency {
    font-size: 13px;
    font-weight: var(--weight-regular);
    color: var(--text-muted);
}

.drawer__badges {
    display: flex;
    gap: 8px;
    margin-bottom: 24px;
}

.drawer__section {
    margin-bottom: 12px;
}

.breakdown {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-bottom: 28px;
}

.breakdown__row {
    display: flex;
    justify-content: space-between;
    font-size: 14px;
}

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

.details {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.details__row {
    display: flex;
    justify-content: space-between;
    gap: 16px;
    font-size: 14px;
    padding-bottom: 10px;
    border-bottom: 1px solid var(--border-subtle);
}

.details__label {
    color: var(--text-muted);
    flex: 0 0 45%;
}

.details__value {
    color: var(--text-body);
    text-align: right;
    word-break: break-word;
}

.drawer__footer {
    display: flex;
    gap: 12px;
    padding: 20px 24px;
    border-top: 1px solid var(--border-subtle);
    background: var(--surface-subtle);
}

/* --- Three-line stat tile ----------------------------------------------
   The settlements and fees variant: 26px value, coloured sub-line, and a
   muted second line. Distinct from the dashboard's 28px KPI with an arrow. */

.stat__label {
    color: var(--text-muted);
    font-size: 14px;
}

.stat__value {
    font-size: 26px;
    font-weight: var(--weight-bold);
    color: var(--text-heading);
    margin-top: 10px;
}

.stat__sub {
    font-size: 14px;
    font-weight: var(--weight-semibold);
    margin-top: 8px;
}

.stat__sub2 {
    color: var(--text-muted);
    font-size: 13px;
    margin-top: 4px;
}

/* --- Settlement bank account -------------------------------------------- */

/* The design specifies 48px below this card, wider than the usual 24px. */
.bank {
    margin-bottom: 48px;
}

.bank__panel {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    background: var(--surface-subtle);
    border-radius: var(--radius-md);
    padding: 14px 16px;
}

.bank__identity {
    display: flex;
    align-items: center;
    gap: 14px;
}

.bank__mark {
    width: 40px;
    height: 40px;
    flex: 0 0 auto;
    border-radius: var(--radius-md);
    background: var(--fv-navy);
    color: var(--fv-white);
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: var(--weight-bold);
}

.bank__name {
    font-weight: var(--weight-bold);
    color: var(--text-heading);
    font-size: 15px;
}

.bank__number {
    color: var(--text-muted);
    font-size: 13px;
}

.bank__verified {
    display: flex;
    align-items: center;
    gap: 6px;
    color: var(--fv-success);
    font-size: 12px;
    margin-top: 2px;
}

/* --- Small button ------------------------------------------------------- */

.btn--sm {
    height: 36px;
    padding: 0 14px;
    font-size: 13px;
}

/* --- Negative money in a table cell ------------------------------------- */

.amount--negative {
    color: var(--fv-danger);
}

/* --- Fees & Billing ----------------------------------------------------- */

/* Both margins, not just the bottom.

   These cards sit as standalone siblings rather than inside a grid, so there
   is no gap between them and nothing above supplies one — the card before the
   fee trend is flush against it with only its own bottom margin, which it does
   not have. A bottom-only margin works until something lands directly above,
   which is exactly what happened when the card-type table moved up. 24px
   matches .grid--spaced so the vertical rhythm holds down the whole screen. */
.feetrend,
.feetable {
    margin-top: 24px;
    margin-bottom: 24px;
}

/* The fee trend's title with its span select on the right.

   centre rather than the baseline .card__headrow uses elsewhere: that row
   pairs two lines of text, whereas this pairs a 16px title with a 36px
   control, and baseline alignment sets the title level with the text inside
   the box rather than with the box.

   The 20px gap below moves from the title to the row. Left on the title it
   would sit inside the flex row, making the row taller underneath the title
   only, and the select would no longer centre on it. */
.feetrend__head {
    align-items: center;
    margin-bottom: 20px;
}

.feetrend__head .card__title {
    margin-bottom: 0;
}

/* .input is width:100% for forms, where a field should fill its column. Here
   it is a compact control beside a heading, so it sizes to its longest option
   ("Last 12 months") and matches .btn--sm's height. */
.feetrend__span {
    width: auto;
    height: 36px;
    padding-right: 28px;
}

/* The fee chart is shorter than the dashboard's and prints values above the
   bars, so it needs its own height and a wider gap for the 36px bars. */
.bars--fees {
    height: 190px;
    gap: 24px;
}

.bars__value {
    font-size: 12px;
    color: var(--text-muted);
    margin-bottom: 6px;
}

/* Navy, the same as the Dashboard's volume bars.

   This used to be --fv-danger, on the reasoning that a fee is money going out.
   Two things were wrong with that. On a Fees screen every figure is a fee, so
   painting them in the danger colour made the whole screen read as an error
   report. And danger was #DC3545, the exact hex the retired placeholder
   convention used for "this figure is invented" — so a merchant looking at a
   live fee chart could not tell it from a fake one, and asked. Red is kept for
   things that are actually wrong. */
.bars__bar--fee {
    width: 36px;
    background: var(--fv-navy);
}

/* Fee amounts read as money going out. */
.amount--fee {
    color: var(--fv-danger);
    font-weight: var(--weight-bold);
}

/* Rate card summary row. */
.row--total td {
    font-weight: var(--weight-bold);
    color: var(--text-heading);
    background: var(--surface-subtle);
}

/* --- Reports ------------------------------------------------------------ */

.header-actions {
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
}

.grid--pair {
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
}

.grid--spaced {
    margin-top: 24px;
}

.card__headrow {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
}

.card__header--split {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
}

.card__title--tight {
    margin-bottom: 0;
}

.card__subtitle {
    color: var(--text-muted);
    font-size: 13px;
    margin-top: 4px;
    margin-bottom: 20px;
    font-weight: var(--weight-regular);
}

.card__header .card__subtitle {
    margin-bottom: 0;
}

.link-action {
    font-size: 13px;
    font-weight: var(--weight-semibold);
    text-decoration: none;
    white-space: nowrap;
}

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

/* --- Period filter bar --------------------------------------------------- */

.period {
    margin-bottom: 24px;
}

.period__row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 12px;
}

.period__group {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
}

.period__legend {
    font-weight: var(--weight-bold);
    color: var(--text-heading);
    font-size: 15px;
}

.pills {
    display: flex;
    gap: 8px;
}

.pill {
    padding: 8px 16px;
    border-radius: 8px;
    font-size: 14px;
    font-weight: var(--weight-semibold);
    text-decoration: none;
    background: var(--fv-slate-100);
    color: var(--text-body);
    transition: background var(--motion-fast) var(--ease),
                color var(--motion-fast) var(--ease);
}

.pill:hover {
    background: var(--fv-slate-200);
    color: var(--text-heading);
}

.pill.is-active {
    background: var(--fv-navy);
    color: var(--fv-white);
}

.pill.is-active:hover {
    background: var(--fv-navy-800);
    color: var(--fv-white);
}

.period__range {
    display: flex;
    align-items: center;
    gap: 10px;
    color: var(--text-muted);
    font-size: 14px;
}

.period__range .input {
    width: 160px;
    height: 40px;
}

/* --- KPI versus target -------------------------------------------------- */

.kpicard {
    margin-bottom: 24px;
}

.progress {
    margin-bottom: 18px;
}

.progress:last-child {
    margin-bottom: 0;
}

.progress__head {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    font-size: 14px;
    margin-bottom: 8px;
    flex-wrap: wrap;
}

.progress__label {
    font-weight: var(--weight-bold);
    color: var(--text-heading);
}

.progress__value {
    color: var(--text-muted);
    margin-left: 10px;
}

.progress__target {
    color: var(--text-muted);
    white-space: nowrap;
}

.progress__badge {
    font-weight: var(--weight-bold);
    margin-left: 6px;
}

.progress__track {
    height: 8px;
    background: var(--fv-slate-200);
    border-radius: var(--radius-pill);
    overflow: hidden;
}

.progress__fill {
    height: 100%;
    border-radius: var(--radius-pill);
    transition: width var(--motion-base) var(--ease);
}

/* --- Trend charts -------------------------------------------------------
   The SVG carries its own viewBox, so width:100% scales the whole coordinate
   space. No JavaScript and no charting library involved. */

.trend {
    width: 100%;
    height: 180px;
    display: block;
}

.trend__labels {
    display: flex;
    justify-content: space-between;
    font-size: 11px;
    color: var(--text-muted);
    margin-top: 4px;
}

/* --- Decline reasons ----------------------------------------------------- */

.decline {
    margin-bottom: 16px;
}

.decline:last-child {
    margin-bottom: 0;
}

.decline__head {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    font-size: 14px;
    margin-bottom: 6px;
    color: var(--text-body);
}

.decline__count {
    color: var(--text-heading);
    font-weight: var(--weight-semibold);
}

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

.decline__track {
    height: 6px;
    background: var(--fv-slate-200);
    border-radius: var(--radius-pill);
    overflow: hidden;
}

.decline__fill {
    height: 100%;
    background: var(--fv-danger);
    border-radius: var(--radius-pill);
}

.decline__action {
    color: var(--text-muted);
    font-size: 12px;
    margin-top: 6px;
}

/* --- Table cell variants -------------------------------------------------- */

/* Long prose in a table should wrap rather than force a scrollbar. */
.cell--wrap {
    white-space: normal;
    min-width: 280px;
}

.cell--actions {
    display: flex;
    gap: 14px;
}

/* Two lines in one cell: identifier above, human name beneath. */
.cell__primary {
    font-weight: var(--weight-semibold);
    color: var(--text-heading);
}

.cell__secondary {
    font-size: 12px;
    color: var(--text-muted);
}

/* --- Reconciliation ------------------------------------------------------ */

.metric__value {
    font-size: 28px;
    font-weight: var(--weight-bold);
    margin-top: 10px;
}

.metric__sub {
    font-size: 13px;
    margin-top: 8px;
    font-weight: var(--weight-semibold);
}

/* An emphasised card. The accent is a left border rather than a tinted fill,
   so the card still reads as part of the same family. */
.card--accent {
    border-left: 3px solid var(--fv-navy);
}

.openbatch {
    margin-bottom: 24px;
}

.openbatch__header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 16px;
    padding: 24px;
    border-bottom: 1px solid var(--border-subtle);
}

.openbatch__eyebrow {
    display: flex;
    align-items: center;
    gap: 10px;
}

.openbatch__title {
    font-size: 22px;
    font-weight: var(--weight-bold);
    color: var(--text-heading);
    margin-top: 6px;
}

.openbatch__meta {
    color: var(--text-muted);
    font-size: 13px;
    margin-top: 4px;
}

.openbatch__figures {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 20px;
    padding: 24px;
}

.figure__label {
    color: var(--text-muted);
    font-size: 13px;
}

.figure__value {
    font-size: 22px;
    font-weight: var(--weight-bold);
    margin-top: 8px;
}

.figure__sub {
    color: var(--text-muted);
    font-size: 12px;
    margin-top: 4px;
}

.openbatch__section {
    border-top: 1px solid var(--border-subtle);
}

.openbatch__section--padded {
    padding: 24px;
}

.openbatch__sectionhead {
    padding: 20px 24px 12px;
}

.openbatch__section--padded .openbatch__sectionhead {
    padding: 0 0 16px;
}

/* --- Sales by brand ------------------------------------------------------ */

.brand {
    margin-bottom: 14px;
}

.brand:last-child {
    margin-bottom: 0;
}

.brand__head {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    font-size: 14px;
    margin-bottom: 6px;
    color: var(--text-body);
}

.brand__name {
    display: flex;
    align-items: center;
    gap: 8px;
}

.brand__amount {
    color: var(--text-heading);
    font-weight: var(--weight-semibold);
}

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

.brand__track {
    height: 6px;
    background: var(--fv-slate-200);
    border-radius: var(--radius-pill);
    overflow: hidden;
}

.brand__fill {
    height: 100%;
    border-radius: var(--radius-pill);
}

/* --- Amount emphasis in tables -------------------------------------------- */

.amount--positive {
    color: var(--fv-success);
    font-weight: var(--weight-bold);
}

/* An em dash where a figure would be: muted, not alarming. */
.amount--none {
    color: var(--text-muted);
}

.icon--danger {
    color: var(--fv-danger);
    margin-right: 8px;
}

.icon--muted {
    color: var(--text-muted);
    margin-right: 8px;
}

/* --- Notifications ------------------------------------------------------- */

/* Stops a shorter column stretching to match a taller neighbour. */
.grid--top {
    align-items: start;
}

.stack {
    display: flex;
    flex-direction: column;
    gap: 20px;
}

.alert {
    display: flex;
    gap: 14px;
    padding: 18px 24px;
    border-bottom: 1px solid var(--border-subtle);
}

.alert:last-child {
    border-bottom: none;
}

.alert__icon {
    width: 34px;
    height: 34px;
    border-radius: 50%;
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
}

.alert__body {
    flex: 1;
    min-width: 0;
}

.alert__top {
    display: flex;
    justify-content: space-between;
    gap: 12px;
}

.alert__titlewrap {
    display: flex;
    align-items: center;
    gap: 8px;
}

.alert__dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--fv-navy);
    flex: 0 0 auto;
}

.alert__title {
    font-weight: var(--weight-semibold);
    color: var(--text-heading);
    font-size: 14px;
}

.alert__time {
    color: var(--text-muted);
    font-size: 12px;
    white-space: nowrap;
}

.alert__text {
    color: var(--text-muted);
    font-size: 13px;
    margin-top: 4px;
}

/* --- Switch --------------------------------------------------------------
   Built on a real <input type="checkbox">: focusable, operable with Space,
   and announced correctly by screen readers. The input is made transparent
   and the track and thumb are painted over it. A div-based toggle would look
   the same and lose every one of those behaviours. */

.switches {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.switches--roomy {
    gap: 20px;
}

.switch {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    margin: 0;
}

.switch__control {
    position: relative;
    display: inline-block;
    width: 40px;
    height: 22px;
    flex: 0 0 auto;
    margin-top: 1px;
}

.switch__input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    opacity: 0;
    cursor: pointer;
    z-index: 1;
}

.switch__track {
    position: absolute;
    inset: 0;
    background: var(--fv-slate-200);
    border-radius: var(--radius-pill);
    pointer-events: none;
    transition: background var(--motion-base) var(--ease);
}

.switch__thumb {
    position: absolute;
    top: 3px;
    left: 3px;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--fv-white);
    pointer-events: none;
    box-shadow: var(--shadow-sm);
    transition: transform var(--motion-base) var(--ease);
}

.switch__input:checked ~ .switch__track {
    background: var(--fv-navy);
}

.switch__input:checked ~ .switch__thumb {
    transform: translateX(18px);
}

.switch__input:focus-visible ~ .switch__track {
    box-shadow: 0 0 0 3px rgba(15, 23, 42, .35);
}

.switch__text {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.switch__label {
    font-size: 14px;
    color: var(--text-heading);
    font-weight: var(--weight-semibold);
}

.switch__desc {
    font-size: 12px;
    color: var(--text-muted);
}

/* --- Team & Roles --------------------------------------------------------- */

.person {
    display: flex;
    align-items: center;
    gap: 10px;
}

.person__avatar {
    width: 30px;
    height: 30px;
    flex: 0 0 auto;
    border-radius: 50%;
    background: var(--fv-navy);
    color: var(--fv-white);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    font-weight: var(--weight-bold);
}

.link-action--danger {
    color: var(--fv-danger);
}

.rolecard__head {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 10px;
}

.rolecard__name {
    font-size: 16px;
    font-weight: var(--weight-bold);
    color: var(--text-heading);
}

.rolecard__desc {
    color: var(--text-muted);
    font-size: 14px;
    margin-bottom: 14px;
}

.rolecard__eyebrow {
    margin-bottom: 8px;
}

.permission {
    display: flex;
    gap: 8px;
    font-size: 13px;
    color: var(--text-body);
    padding: 3px 0;
}

.permission__tick {
    color: var(--fv-success);
    font-size: 11px;
    margin-top: 4px;
    flex: 0 0 auto;
}

/* ==================================================================
   Placeholder data — removed 2026-09-28
   ==================================================================
   `ph` marked a value, a row or a whole card whose figures were invented,
   and painted them red; `.ph-note` explained the colour at the foot of the
   page; `.live` opted a cell back out for rows that mixed the two.

   All three are gone. A colour is a caption on a claim the screen has
   already made — by the time a merchant reads the legend they have read the
   number — and red was already this portal's colour for a fee that failed
   or a field in error, so it made a permanent, harmless fact look like a
   fault. A section with nothing real to show now says so in its own words,
   in place: see fragments/notbuilt.html and .notbuilt below.

   `.live` survives as a class in two templates. It no longer does anything
   and can be dropped when those tables are next touched; it is left alone
   here rather than editing markup that is behind a false flag anyway.
   ================================================================== */


/* Explains an empty fee-profile card. Muted, because it is an explanation
   rather than a warning: "no profile assigned yet" is a normal state for a
   newly onboarded merchant, not an error to alarm them about. */
.fee-profile__note {
    margin: 0;
    padding: 4px 0 4px 0;
    font-size: 14px;
    line-height: 1.55;
    color: var(--text-muted);
}

/* Pager under the transactions table. */
.pager {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 16px;
    padding: 16px 24px;
    border-top: 1px solid var(--border-subtle);
}

.pager__label {
    font-size: 13px;
    color: var(--text-muted);
}

/* Explains an empty table. Muted, because "no transactions yet" is a normal
   state for a newly onboarded merchant, not an error to alarm them with. */
.table-empty {
    margin: 0;
    padding: 8px 0;
    font-size: 14px;
    line-height: 1.55;
    color: var(--text-muted);
}

/* ========================================================================
   Responsive

   The shell was built at one width: a fixed 264px sidebar beside a content
   column with 48px of side padding. That is fine on a desktop and falls apart
   on anything narrower, so these are the breakpoints that keep it usable.

   Ordered largest to smallest, each one only overriding what the previous
   rules got wrong at that size. No layout is redefined from scratch.
   ======================================================================== */

/* --- Laptops and small desktops ---------------------------------------- */
@media (max-width: 1280px) {
    .content {
        padding: 32px 28px;
    }

    /* Below this the three-up chart row leaves each card too narrow for a
       donut and its legend side by side. Two columns reads better than three
       cramped ones. */
    .grid--charts {
        grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    }
}

/* --- Tablets ------------------------------------------------------------
   The sidebar becomes a horizontal strip above the content. Hiding it would
   remove the only navigation, and a 264px column on a 900px screen costs a
   third of the width for eight links. */
@media (max-width: 1024px) {
    /* Stacked, so the two columns no longer scroll independently - the page
       scrolls again and the height/overflow lock above must be released, or
       everything below the first viewport becomes unreachable. */
    .shell {
        flex-direction: column;
        height: auto;
        overflow: visible;
    }

    .sidebar {
        overflow-y: visible;
    }

    .sidebar {
        width: 100%;
        flex: 0 0 auto;
        padding: 16px 20px;
    }

    /* Brand and merchant sit side by side rather than stacked, so the strip
       stays shallow and the content is not pushed off the first screen. */
    .sidebar__brand {
        flex-direction: row;
        align-items: center;
        justify-content: flex-start;
        gap: 12px;
        margin-bottom: 12px;
    }

    .sidebar__logo {
        width: 48px;
        height: 48px;
    }

    .sidebar__merchant {
        padding: 0 0 12px;
        margin-bottom: 12px;
    }

    /* Nav becomes a wrapping row of pills. */
    .nav {
        flex-direction: row;
        flex-wrap: wrap;
        gap: 6px;
    }

    .nav__row {
        padding: 8px 12px;
        font-size: 14px;
    }

    .nav__label {
        flex: 0 0 auto;
    }

    .sidebar__user {
        margin-top: 12px;
        padding-top: 12px;
    }

    .content {
        padding: 24px 20px;
        /* The column no longer scrolls independently of the page once the
           sidebar is above it; leaving overflow:auto here would create a
           second scrollbar inside the first. */
        overflow: visible;
    }
}

/* --- Phones ------------------------------------------------------------- */
@media (max-width: 680px) {
    .content {
        padding: 20px 14px;
    }

    .page-title {
        font-size: 24px;
    }

    .page-subtitle {
        font-size: 14px;
    }

    /* One card per row. auto-fit with a 220px minimum would still try to fit
       two on a 360px phone and clip the figures. */
    .grid--kpi,
    .grid--charts,
    .grid--stats {
        grid-template-columns: 1fr;
    }

    .card {
        padding: 18px;
    }

    /* A split header stacks rather than squeezing the action button. */
    .page-header--split {
        flex-direction: column;
        align-items: flex-start;
        gap: 12px;
    }

    /* Filter controls go full width instead of shrinking to unusable slivers. */
    .filters__row {
        flex-direction: column;
        align-items: stretch;
    }

    .filters__select,
    .filters__select--wide,
    .filters__search {
        width: 100%;
        min-width: 0;
    }

    .filters__meta {
        flex-direction: column;
        align-items: flex-start;
        gap: 4px;
    }

    /* The drawer is a full-screen sheet on a phone; a 480px panel would sit
       off the edge of the viewport. */
    .drawer {
        width: 100%;
        max-width: 100%;
    }

    .pager {
        flex-wrap: wrap;
        gap: 10px;
    }
}

/* --- Print and reduced motion -------------------------------------------
   Not screen sizes, but the same idea: the interface adapting to how it is
   actually being used. */
@media print {
    .sidebar,
    .pager,
    .filters {
        display: none;
    }

    .content {
        padding: 0;
    }

    .card {
        box-shadow: none;
        border: 1px solid var(--border-subtle);
        break-inside: avoid;
    }
}

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

/* "Not built yet" panel for Settlements and Reconciliation.

   Deliberately calm: gold rather than red, an hourglass rather than a warning
   triangle. Nothing has failed and nothing is lost — this data is not captured
   anywhere yet — and an alarming panel would send merchants to support over a
   roadmap item. */
.notbuilt {
    background: var(--surface-card);
    border-radius: var(--radius-card);
    border-left: 3px solid var(--fv-gold);
    box-shadow: var(--shadow-sm);
    padding: 22px 24px;
    max-width: 72ch;
    /* .card carries no vertical margin in this stylesheet - spacing comes from
       wrappers (.grid margin-bottom, .grid--spaced margin-top, .kpicard
       margin-bottom). A not-built panel replaces one of those cards, so it has
       to supply the same rhythm or whatever follows sits flush against it. */
    margin-bottom: 24px;
}

/* Inside a grid the gap already spaces siblings; the margin would add to it. */
.grid .notbuilt {
    margin-bottom: 0;
    max-width: none;
}

.notbuilt__head {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 16px;
    font-weight: var(--weight-bold);
    color: var(--text-heading);
}

.notbuilt__head i {
    color: var(--fv-gold);
}

.notbuilt__detail {
    margin: 10px 0 0 0;
    font-size: 14px;
    line-height: 1.6;
    color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   Could not be loaded — see fragments/unavailable.html

   A card whose data exists but did not arrive this time. It is an ordinary
   .card, so it takes the grid cell the real chart would have and the page
   keeps its shape.

   Deliberately quieter than .notbuilt: no gold rule down the side, no bold
   headline. The two must not look alike, because they tell a merchant
   opposite things — "nobody has built this" and "try again in a moment" —
   and a reader should be able to tell which from across the room. A timed-out
   report has cost them nothing, so nothing here is a warning colour.
   -------------------------------------------------------------------------- */
.unavailable__body {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 12px 0 4px;
}

.unavailable__icon {
    flex: 0 0 auto;
    margin-top: 3px;
    color: var(--text-muted);
}

.unavailable__text {
    margin: 0;
    max-width: 48ch;
    font-size: 14px;
    line-height: 1.6;
    color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   Agreed rate vs charged

   A flagged cell marks a charge that does not match the merchant's own agreed
   rate. Deliberately not the placeholder red: that red means "this figure is
   invented". These figures are real — the disagreement between them is the
   point, and conflating the two would teach the reader to ignore both.

   Background rather than colour alone, so the flag does not rely on colour
   vision to be noticed.
   -------------------------------------------------------------------------- */
table.data td.cell--flag {
    background: var(--state-warning-bg);
    font-weight: 600;
}

/* Absence of an agreed rule, which is information rather than a fault. */
table.data td.cell--muted {
    color: var(--text-muted);
    font-style: italic;
}

/* --------------------------------------------------------------------------
   Period label above the dashboard tiles

   The summary endpoint is called without dates, which ledger defines as the
   merchant's whole history. Saying so costs one line and stops every figure
   below being read as this month's.
   -------------------------------------------------------------------------- */
.kpi-period {
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 10px;
}

/* Empty state for the activity feed. Nothing to report is a real answer -
   no oversized sales, no refunds, no silent terminals - and saying so reads
   very differently from a card that failed to load. */
.alert--empty .alert__title {
    color: var(--text-muted);
}

.alert--empty .alert__body {
    padding-left: 0;
}

/* --------------------------------------------------------------------------
   Period selector above the dashboard tiles

   One control governing the whole screen. It replaced a static caption, which
   was honest but concealed that the tiles and the charts answered over
   different spans.
   -------------------------------------------------------------------------- */
.kpi-period {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px 14px;
    margin-bottom: 14px;
}

.kpi-period__label {
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
}

/* The window ledger says it covered, beside the period pills. Quieter than the
   pills themselves: it confirms rather than controls. */
.kpi-period__stated {
    font-family: var(--font-primary);
    font-size: 12.5px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------------------------
   Trend chart legend

   Only drawn when a chart has more than one line, which today means the gross
   and net pair. The gap between those two lines is what fees and refunds cost
   the merchant — the legend is what makes that gap readable rather than a
   puzzle.
   -------------------------------------------------------------------------- */
.trend__key {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 18px;
    margin-bottom: 6px;
}

.trend__keyitem {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-size: 12.5px;
    color: var(--text-muted);
}

.trend__keydot {
    width: 10px;
    height: 10px;
    border-radius: var(--radius-pill);
    flex: 0 0 auto;
}
