/*
 * Expensieve theme tokens.
 *
 * Colours are stored as raw "R G B" channel triplets (not #hex) so that the
 * Tailwind config can wrap them as `rgb(var(--c-x) / <alpha-value>)` and
 * opacity modifiers such as `bg-surface/95` keep working.
 *
 * Light is defined on :root; dark overrides only the tokens under
 * [data-theme="dark"]. Nothing here should ever be a hard-coded colour.
 *
 * Contrast ratios noted below are WCAG 2.1 and are enforced by
 * tests/contrast_test.go -- do not change a token without running it.
 *
 * NAMING: a colour token must never share a name with a built-in Tailwind
 * utility suffix. `base` did, and Tailwind emitted both `.text-base
 * {font-size}` and `.text-base {color}` at equal specificity -- so the
 * wordmark went black whenever the colour rule happened to be emitted last.
 * Hence `canvas`, not `base`. TestTokenNamesDoNotShadowTailwind guards this.
 */

:root {
    --c-canvas:      248 250 252;   /* slate-50  */
    --c-surface:     255 255 255;   /* white     */
    --c-raised:      241 245 249;   /* slate-100 */
    --c-raised-hover:226 232 240;   /* slate-200 */
    --c-input:       251 252 253;
    --c-border:      226 232 240;   /* slate-200 */
    --c-border-ctl:  100 116 139;   /* slate-500 -- 4.63:1 vs input fill */
    --c-text:         15  23  42;   /* slate-900 */
    --c-text-2:       71  85 105;   /* slate-600 */
    --c-muted:        93 107 127;   /* slate-500 nudged darker -- 4.95:1 on raised */
    --c-brand:        79  70 229;   /* indigo-600, 6.29:1 with white */
    --c-brand-hover:  67  56 202;   /* indigo-700 */
    --c-brand-text:   67  56 202;   /* indigo-700 */
    --c-brand-chip:   99 102 241;   /* indigo-500 */
    --c-chip-text:    67  56 202;   /* indigo-700 */
    --c-success:       4 120  87;   /* emerald-700 */
    --c-success-hover:  6  95  70;   /* emerald-800 */
    --c-success-text:  4 120  87;
    --c-danger:      190  18  60;   /* rose-700 -- text/tinted pills, 5.52:1 */
    --c-danger-fill: 225  29  72;   /* rose-600 -- solid fill, white label */
    --c-info:          3 105 161;   /* sky-700  */
    --c-info-chip:    14 165 233;   /* sky-500  */
    --c-warning:     180  83   9;   /* amber-700 -- 4.73:1 on amber tint */
    --c-warning-chip:252 211  77;   /* amber-300 */
    --c-on-accent:   255 255 255;   /* text sitting on a filled success pill */

    /* soft tinted fills for pill buttons (Include / Delete / Excluded) */
    --c-brand-soft:       238 242 255;   /* indigo-50  */
    --c-brand-soft-hover: 224 231 255;   /* indigo-100 */
    --c-danger-soft:      255 241 242;   /* rose-50    */
    --c-danger-soft-hover:255 228 230;   /* rose-100   */
    --c-warning-soft:     255 251 235;   /* amber-50   */

    --chip-alpha: 0.10;
    --chip-ring-alpha: 0.25;
    --shadow-strength: 0.04;
}

[data-theme="dark"] {
    --c-canvas:       11  17  32;   /* indigo-tinted near-slate-950 */
    --c-surface:      21  29  46;
    --c-raised:       30  39  57;
    --c-raised-hover: 41  52  74;
    --c-input:        26  35  53;
    --c-border:       41  53  72;
    --c-border-ctl:  100 116 139;   /* slate-500 -- 3.30:1 vs input fill */
    --c-text:        226 232 240;   /* slate-200, 15.27:1 (not pure white) */
    --c-text-2:      203 213 225;   /* slate-300, 12.68:1 */
    --c-muted:       148 163 184;   /* slate-400,  7.34:1 */
    --c-brand:        79  70 229;   /* unchanged -- still 6.29:1 with white */
    --c-brand-hover:  99 102 241;   /* indigo-500, lighter on hover in dark */
    --c-brand-text:  165 180 252;   /* indigo-300, 9.45:1 */
    --c-brand-chip:   99 102 241;   /* indigo-500 */
    --c-chip-text:   199 210 254;   /* indigo-200, 8.97:1 over chip fill */
    --c-success:      52 211 153;   /* emerald-400, 9.29:1 with slate-900 */
    --c-success-hover:110 231 183;   /* emerald-300 */
    --c-success-text: 52 211 153;   /* 9.79:1 on canvas */
    --c-danger:      253 164 175;   /* rose-300 -- text/tinted pills, 7.11:1 */
    --c-danger-fill: 225  29  72;   /* rose-600 -- solid fill, white label */
    --c-info:        125 211 252;   /* sky-300,  11.29:1 */
    --c-info-chip:    14 165 233;   /* sky-500 tint */
    --c-warning:     252 211  77;   /* amber-300, 13.06:1 */
    --c-warning-chip:252 211  77;
    --c-on-accent:    15  23  42;   /* slate-900 on the emerald fill */

    /* soft tinted fills -- dark equivalents of the *-50/*-100 light tints */
    --c-brand-soft:        36  44  80;
    --c-brand-soft-hover:  46  55  99;
    --c-danger-soft:       58  34  48;
    --c-danger-soft-hover: 74  42  60;
    --c-warning-soft:      58  50  34;

    --chip-alpha: 0.20;
    --chip-ring-alpha: 0.35;
    --shadow-strength: 0.30;
}

/*
 * Makes scrollbars, date pickers and <select> dropdowns render natively dark.
 * Without this the filter bar's date/select controls stay white in dark mode.
 */
html { color-scheme: light; }
[data-theme="dark"] { color-scheme: dark; }

/*
 * Native checkboxes keep painting the light UA control even under
 * color-scheme:dark (appearance:auto draws the glyph over any background we
 * set), so draw them ourselves. The `html` prefix raises specificity above
 * Tailwind's preflight, which the CDN injects after this stylesheet.
 */
html input[type="checkbox"] {
    appearance: none;
    -webkit-appearance: none;
    width: 1rem;
    height: 1rem;
    flex: none;
    border-radius: 0.25rem;
    border: 1px solid rgb(var(--c-border-ctl));
    background-color: rgb(var(--c-input));
    display: inline-block;
    position: relative;
    cursor: pointer;
    transition: background-color 120ms ease, border-color 120ms ease;
}
html input[type="checkbox"]:checked {
    background-color: rgb(var(--c-brand));
    border-color: rgb(var(--c-brand));
}
html input[type="checkbox"]:checked::after {
    content: "";
    position: absolute;
    left: 4px;
    top: 1px;
    width: 4px;
    height: 8px;
    border: solid #fff;
    border-width: 0 2px 2px 0;
    transform: rotate(45deg);
}
html input[type="checkbox"]:focus-visible {
    outline: 2px solid rgb(var(--c-brand-text));
    outline-offset: 2px;
}

/* --------------------------------------------------------- date field ---- */

/*
 * WebKit sizes input[type="date"] from its own shadow-DOM metrics, not from the
 * width/height we give it: on iOS the control rendered ~26px wider than the
 * selects beside it and overflowed the card, and even in desktop Safari it came
 * out ~64px tall against the selects' 38px. Three rounds of CSS aimed at the
 * control and its ::-webkit-datetime-edit pseudos failed to move it (issue #2).
 *
 * So stop styling the native control. The real input is laid over a plain box
 * of ours at opacity 0 -- it keeps its name/value/required, the native picker
 * still opens on tap, the label still targets it, but every visible pixel is
 * .date-field__display, which carries the same utility classes as the selects
 * and therefore cannot drift from them.
 */
.date-field {
    position: relative;
    display: block;
}

.date-field__input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    border: 0;
    background: transparent;
    opacity: 0;
    cursor: pointer;
    z-index: 1;
    -webkit-appearance: none;
    appearance: none;
}

/* Clicks must reach the input stacked above it. */
.date-field__display {
    pointer-events: none;
    /* Holds the selects' height even when the value is empty, which is how iOS
       renders an unset date input (no placeholder, unlike Chrome). */
    min-height: 2.125rem;
}

@media (min-width: 640px) {
    .date-field__display {
        min-height: 2.375rem;
    }
}

.date-field__text {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.date-field__text:empty::before {
    content: attr(data-placeholder);
    color: rgb(var(--c-muted));
}

/* Mirrors the selects' focus:border-brand / focus:ring-2 / focus:bg-surface. */
.date-field__input:focus + .date-field__display {
    border-color: rgb(var(--c-brand));
    background-color: rgb(var(--c-surface));
    box-shadow: 0 0 0 2px rgb(var(--c-brand) / 0.2);
}

/* Grid/flex items default to min-width:auto (= min-content), which is what let
   the date control push past its column in the first place. */
.filter-group {
    min-width: 0;
}


/* ---------------------------------------------------------------- nav ---- */

.nav-links a {
    padding: 0.5rem 0.875rem;
    border-radius: 0.75rem;
    font-size: 0.875rem;
    font-weight: 500;
    color: rgb(var(--c-text-2));
    transition: all 150ms ease;
    display: inline-flex;
    align-items: center;
    white-space: nowrap;
}
.nav-links a:hover {
    color: rgb(var(--c-text));
    background-color: rgb(var(--c-raised));
}
.nav-links a.active {
    background-color: rgb(var(--c-brand-chip) / var(--chip-alpha));
    color: rgb(var(--c-brand-text));
    font-weight: 600;
}

#mobile-nav a {
    display: block;
    padding: 0.5rem 0.75rem;
    border-radius: 0.5rem;
    font-size: 0.875rem;
    font-weight: 500;
    color: rgb(var(--c-text-2));
}
#mobile-nav a:hover {
    background-color: rgb(var(--c-raised));
}
#mobile-nav a.active {
    background-color: rgb(var(--c-brand-chip) / var(--chip-alpha));
    color: rgb(var(--c-brand-text));
    font-weight: 600;
}

/* -------------------------------------------------------------- chips ---- */

.chip,
.badge {
    display: inline-flex;
    align-items: center;
    padding: 0.25rem 0.625rem;
    border-radius: 9999px;
    font-size: 0.75rem;
    line-height: 1rem;
    font-weight: 600;
    font-style: normal;
    background-color: rgb(var(--c-brand-chip) / var(--chip-alpha));
    color: rgb(var(--c-chip-text));
    box-shadow: inset 0 0 0 1px rgb(var(--c-brand-chip) / var(--chip-ring-alpha));
}

.chip-source,
.badge-source {
    display: inline-flex;
    align-items: center;
    padding: 0.25rem 0.625rem;
    border-radius: 9999px;
    font-size: 0.75rem;
    line-height: 1rem;
    font-weight: 600;
    font-style: normal;
    background-color: rgb(var(--c-info-chip) / var(--chip-alpha));
    color: rgb(var(--c-info));
    box-shadow: inset 0 0 0 1px rgb(var(--c-info-chip) / var(--chip-ring-alpha));
}

.uncategorized {
    font-size: 0.75rem;
    color: rgb(var(--c-muted));
    font-style: italic;
}

/* ------------------------------------------------------------ amounts ---- */

.amount-main {
    font-weight: 700;
    color: rgb(var(--c-success-text));
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
}
.amount-original {
    font-size: 0.75rem;
    color: rgb(var(--c-muted));
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
    font-style: normal;
}

/* --------------------------------------------------- excluded rows ------- */

tr.tx-excluded {
    opacity: 0.6;
    background-color: rgb(var(--c-raised) / 0.6);
    font-style: italic;
}
tr.tx-excluded strong {
    font-weight: 400;
    text-decoration: line-through;
    color: rgb(var(--c-muted));
}
tr.tx-excluded .amount-main {
    font-weight: 400;
    color: rgb(var(--c-muted));
}

.excluded-label {
    display: inline-flex;
    align-items: center;
    font-size: 10px;
    text-transform: uppercase;
    font-weight: 700;
    letter-spacing: 0.05em;
    color: rgb(var(--c-warning));
    background-color: rgb(var(--c-warning-chip) / 0.15);
    padding: 0.125rem 0.375rem;
    border-radius: 0.25rem;
    margin-left: 0.375rem;
    font-style: normal;
    border: 1px solid rgb(var(--c-warning-chip) / 0.3);
}

/* ------------------------------------------------ theme switcher UI ------ */

.theme-opt {
    padding: 0.5rem 1rem;
    border-radius: 0.6rem;
    font-size: 0.8125rem;
    font-weight: 600;
    color: rgb(var(--c-text-2));
    background-color: transparent;
    border: none;
    cursor: pointer;
    transition: all 150ms ease;
}
.theme-opt:hover {
    color: rgb(var(--c-text));
}
.theme-opt[aria-pressed="true"] {
    background-color: rgb(var(--c-surface));
    color: rgb(var(--c-brand-text));
    box-shadow: 0 1px 3px rgb(0 0 0 / var(--shadow-strength));
}
.theme-opt:focus-visible {
    outline: 2px solid rgb(var(--c-brand-text));
    outline-offset: 2px;
}

/* --------------------------------- mobile transaction card layout -------- */

/* Long category / payment-source names must stay inside their own cell.
   Desktop: the <colgroup> in index.html pins Source to 9rem, so a wider chip
   (e.g. "Mandiri Signature (CC)") overflowed visibly into the Note column.
   Mobile: the card grid could not shrink the chips, so the "date meta" row
   grew past the viewport and collided with the date.
   Both are the same failure -- a nowrap chip that can neither shrink nor clip. */
.table-container td[data-label="Category"],
.table-container td[data-label="Source"] {
    overflow: hidden;
}

.table-container td[data-label="Category"] > *,
.table-container td[data-label="Source"] > * {
    min-width: 0;   /* flex/grid items refuse to shrink below min-content without this */
    max-width: 100%;
}

.table-container .chip,
.table-container .chip-source,
.table-container .uncategorized {
    display: inline-block;   /* text-overflow needs a block-ish box; inline-flex swallows it */
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: middle;
}

/* The rule above is more specific than Tailwind's single-class .md\:hidden, so it
   would un-hide the mobile-only duplicate source chip on desktop. Restate the
   intent at a specificity that wins. */
@media (min-width: 768px) {
    .table-container .chip-source.md\:hidden {
        display: none;
    }
}

@media (max-width: 768px) {
    .table-container {
        background: transparent;
        border: none;
        box-shadow: none;
    }
    .table-container table,
    .table-container thead,
    .table-container tbody,
    .table-container th,
    .table-container td,
    .table-container tr {
        display: block;
    }
    .table-container thead {
        display: none;
    }
    .table-container tbody {
        display: flex;
        flex-direction: column;
        gap: 0.75rem;
        padding: 0;
    }
    .table-container tbody tr {
        background: rgb(var(--c-surface));
        border: 1px solid rgb(var(--c-border));
        border-radius: 1rem;
        padding: 0.875rem 1rem;
        box-shadow: 0 1px 3px 0 rgb(0 0 0 / var(--shadow-strength));
        display: grid;
        /* Column 1 must not shrink below its content: it carries the date, which
           is whitespace-nowrap, so a 0 minimum let the date overflow its track
           and slide underneath the chips in column 2 (issue #1). Column 2 keeps
           a 0 minimum so the chips absorb the squeeze and ellipsis instead. */
        grid-template-columns: minmax(min-content, 1fr) minmax(0, auto);
        grid-template-areas:
            "merchant amount"
            "date meta"
            "note note"
            "actions actions";
        row-gap: 0.4rem;
        column-gap: 0.75rem;
        align-items: center;
    }
    .table-container tbody tr:hover {
        background-color: rgb(var(--c-surface));
    }
    .table-container td {
        border: none !important;
        padding: 0 !important;
    }
    .table-container td.td-merchant {
        grid-area: merchant;
        display: flex;
        align-items: baseline;
        flex-wrap: wrap;
        gap: 0.25rem;
        min-width: 0;
    }
    .table-container td.td-merchant strong {
        font-size: 0.9375rem;
        font-weight: 700;
        color: rgb(var(--c-text));
    }
    .table-container td.td-amount {
        grid-area: amount;
        text-align: right;
        display: flex;
        justify-content: flex-end;
    }
    .table-container td.td-amount .amount-container {
        display: flex;
        flex-direction: column;
        align-items: flex-end;
    }
    .table-container td.td-amount .amount-main {
        font-size: 0.9375rem;
    }
    .table-container td.td-date {
        grid-area: date;
        font-size: 0.75rem;
        color: rgb(var(--c-muted));
    }
    .table-container td[data-label="Category"] {
        grid-area: meta;
        display: flex;
        justify-content: flex-end;
        gap: 0.35rem;
        flex-wrap: wrap;
        min-width: 0;
    }
    .table-container td[data-label="Source"] {
        display: none;
    }
    .table-container td[data-label="Note"] {
        grid-area: note;
        font-size: 0.75rem;
        color: rgb(var(--c-muted));
        background-color: rgb(var(--c-raised));
        border-radius: 0.5rem;
        padding: 0.35rem 0.6rem !important;
        margin-top: 0.15rem;
    }
    .table-container td[data-label="Note"]:empty,
    .table-container td[data-label="Note"]:has(.uncategorized) {
        display: none;
    }
    .table-container td.td-actions {
        grid-area: actions;
        border-top: 1px solid rgb(var(--c-border)) !important;
        padding-top: 0.5rem !important;
        margin-top: 0.25rem;
        display: flex;
        justify-content: flex-end;
    }
    .table-container td.td-actions .actions-cell {
        display: flex;
        gap: 0.5rem;
        width: 100%;
        justify-content: flex-end;
    }
    .table-container td.td-actions .actions-cell a,
    .table-container td.td-actions .actions-cell button {
        padding: 0.35rem 0.75rem;
        font-size: 0.75rem;
        border-radius: 0.5rem;
        min-height: 2rem;
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }
    .table-container td.empty-state-cell {
        display: block;
        grid-template-areas: none;
        text-align: center;
        padding: 2rem 0 !important;
    }
}

/* ----------------------------------------------------------- safe area ---- */

header.sticky {
    padding-top: env(safe-area-inset-top, 0px);
}

.fixed.bottom-6 {
    bottom: calc(1.5rem + env(safe-area-inset-bottom, 0px));
}

/* ------------------------------------------------------- filter card ---- */

/* <summary> ships a browser-drawn marker (a triangle in Chrome, nothing
   visible in some WebKit builds) that we replace with .filter-chevron, an
   SVG we can rotate consistently everywhere. */
#filter-details > summary {
    -webkit-appearance: none;
    appearance: none;
}
#filter-details > summary::-webkit-details-marker {
    display: none;
}
#filter-details > summary::marker {
    content: "";
}

#filter-details[open] > summary .filter-chevron {
    transform: rotate(180deg);
}
