/* Finique theme. Brand source files: docs/brand/ (navy #0e1a3c, cream #f5f1e8, gold #d08a0f light /
   #f2b63c dark). tw-config.js maps the Tailwind names below to these variables.

   Theme-aware text colours (WCAG AA ≥ 4.5:1 on every surface they are used on, light and dark:
   white, cream page, slate-100 hover, brand-50 tints; navy page/card/hover, brand-500/15 tints).
   Templates use text-muted / text-soft / text-accent / text-pos / text-neg / text-warn, never raw
   slate/brand shades for text. Gold is decorative only (2.9:1 on white): never use it for text. */
/* Native controls (number spinners, scrollbars, date pickers) follow the page's theme: without
   this the browser draws them for a light page, so a number field's arrows vanish in dark mode. */
:root { color-scheme: light; }
.dark { color-scheme: dark; }
:root {
  --fp-muted: 89 96 117;     /* #596075  secondary text */
  --fp-soft: 61 71 99;       /* #3d4763  body copy on cards */
  --fp-accent: 42 71 153;    /* #2a4799  links, active nav */
  --fp-pos: 4 112 79;        /* #04704f  income, gains */
  --fp-neg: 179 18 58;       /* #b3123a  spend, losses */
  --fp-warn: 138 60 13;      /* #8a3c0d  warnings */
  --fp-on-brand: 245 241 232; /* cream text on the navy primary fill */
  --fp-gold: 208 138 15;     /* #d08a0f  the spark (decoration only) */
  /* brand scale: 600 = primary fill (navy), 700 = its hover, 500 = focus rings/tints */
  --fp-brand-50: 234 237 246;  --fp-brand-100: 215 221 238; --fp-brand-200: 182 194 224;
  --fp-brand-400: 108 128 189; --fp-brand-500: 42 71 153;   --fp-brand-600: 14 26 60;
  --fp-brand-700: 36 50 92;    --fp-brand-900: 11 20 48;
  /* app-icon tile (inverts per theme, as on the brand sheet) */
  --fp-tile: 14 26 60; --fp-tile-ink: 245 241 232; --fp-tile-spark: 242 182 60;
}
.dark {
  --fp-muted: 154 163 187;   /* #9aa3bb */
  --fp-soft: 207 212 225;    /* #cfd4e1 */
  --fp-accent: 169 189 245;  /* #a9bdf5 */
  --fp-pos: 60 207 152;      /* #3ccf98 */
  --fp-neg: 251 127 148;     /* #fb7f94 */
  --fp-warn: 246 195 91;     /* #f6c35b */
  --fp-on-brand: 14 26 60;   /* navy text on the cream primary fill */
  --fp-gold: 242 182 60;     /* #f2b63c */
  --fp-brand-50: 26 40 80;     --fp-brand-100: 36 52 95;    --fp-brand-200: 51 71 124;
  --fp-brand-400: 143 166 230; --fp-brand-500: 169 189 245; --fp-brand-600: 245 241 232;
  --fp-brand-700: 227 220 203; --fp-brand-900: 245 241 232;
  --fp-tile: 245 241 232; --fp-tile-ink: 14 26 60; --fp-tile-spark: 208 138 15;
}
html { font-family: "DM Sans Variable", "DM Sans", ui-sans-serif, system-ui, sans-serif; }
/* Fonts: Outfit (display: headings, brand name) echoes the geometric wordmark;
   DM Sans for body copy; JetBrains Mono for small spaced labels, like the brand sheet captions. */
h1, h2, h3, .font-display { font-family: "Outfit Variable", Outfit, ui-sans-serif, system-ui, sans-serif; letter-spacing: -.01em; }
.num, td.text-right, .tabular { font-variant-numeric: tabular-nums; }
/* links inside running text are underlined (not distinguishable by colour alone) */
p a:not([class*="rounded"]), li > p a { text-decoration: underline; text-underline-offset: 2px; }

/* Brand marks (partials/brand.html) */
.fp-brand-name { font-family: "Outfit Variable", Outfit, ui-sans-serif, system-ui, sans-serif; font-weight: 600; letter-spacing: -.015em; }
.fp-tile { fill: rgb(var(--fp-tile)); }
.fp-tile-ink { color: rgb(var(--fp-tile-ink)); }
.fp-tile-spark { fill: rgb(var(--fp-tile-spark)); }
/* active navigation item: a gold spark bar on the left edge */
.nav-on { box-shadow: inset 3px 0 0 rgb(var(--fp-gold)); }

/* Typographic roles (one look per role across every page):
   .eyebrow  small uppercase label above a value or a group: KPI labels, section groups, table headers
   .badge    uppercase status chip (colours come from the element's own bg/text classes)
   .note     muted italic aside: provenance, estimates, hints
   .qualifier lighter part of a heading: "Where it went · Last 30 days" */
.eyebrow { font-family: "JetBrains Mono Variable", "JetBrains Mono", ui-monospace, monospace; font-size: .7rem; line-height: 1rem; font-weight: 500; text-transform: uppercase; letter-spacing: .1em; color: rgb(var(--fp-muted)); }
.badge { display: inline-block; font-size: .65rem; line-height: 1rem; font-weight: 600; text-transform: uppercase; letter-spacing: .05em; border-radius: .25rem; padding: 0 .375rem; white-space: nowrap; }
.note { font-style: italic; color: rgb(var(--fp-muted)); }
.qualifier { font-weight: 400; color: rgb(var(--fp-muted)); }
/* money and counts line up in KPI cards and tables (only there: tabular figures also widen
   punctuation such as the hyphen in "what-if") */
.eyebrow + div, main td, main dd { font-variant-numeric: tabular-nums; }
/* the narrowest phones (320–359px): wide-spaced labels like "LIABILITIES" would run into a
   third-width card's edge */
@media (max-width: 359.98px) { .eyebrow { letter-spacing: .03em; overflow-wrap: anywhere; } }

/* Date picker (flatpickr, js/datepicker.js) in the app's palette. flatpickr.css loads after this
   file, so every rule is prefixed with html / .dark to win on specificity. */
html .flatpickr-calendar { font-family: inherit; border-radius: .75rem; box-shadow: 0 10px 25px -5px rgb(14 26 60 / .15), 0 0 0 1px #e1d9c8; }
html .flatpickr-day.selected, html .flatpickr-day.selected:hover, html .flatpickr-day.selected:focus { background: rgb(var(--fp-brand-600)); border-color: rgb(var(--fp-brand-600)); color: rgb(var(--fp-on-brand)); }
html .flatpickr-day.today:not(.selected) { border-color: rgb(var(--fp-gold)); }
html .flatpickr-day.prevMonthDay, html .flatpickr-day.nextMonthDay { color: rgb(var(--fp-muted)); }
html .flatpickr-day.flatpickr-disabled { color: rgb(var(--fp-muted) / .5); }
html span.flatpickr-weekday, .dark span.flatpickr-weekday { color: rgb(var(--fp-muted)); font-weight: 600; }
.dark .flatpickr-calendar { background: #132045; box-shadow: 0 10px 25px -5px rgb(0 0 0 / .5), 0 0 0 1px #2e3a5e; }
.dark .flatpickr-calendar.arrowTop::after { border-bottom-color: #132045; }
.dark .flatpickr-calendar.arrowBottom::after { border-top-color: #132045; }
.dark .flatpickr-calendar.arrowTop::before, .dark .flatpickr-calendar.arrowBottom::before { border-color: transparent; }
.dark .flatpickr-months .flatpickr-month, .dark .flatpickr-current-month input.cur-year,
.dark .flatpickr-current-month .flatpickr-monthDropdown-months { color: #ede7da; fill: #ede7da; background: transparent; }
.dark .flatpickr-current-month .flatpickr-monthDropdown-months option { background: #132045; }
.dark .flatpickr-months .flatpickr-prev-month, .dark .flatpickr-months .flatpickr-next-month { color: #ede7da; fill: #ede7da; }
.dark .flatpickr-months .flatpickr-prev-month:hover svg, .dark .flatpickr-months .flatpickr-next-month:hover svg { fill: rgb(var(--fp-accent)); }
/* the year field's up/down arrows only showed on hover: keep them visible so the year reads as
   changeable (typing a year works too) */
html .flatpickr-current-month .numInputWrapper span { opacity: .6; }
html .flatpickr-current-month .numInputWrapper span:hover { opacity: 1; }
html .flatpickr-current-month input.cur-year { font-weight: 500; }
.dark .numInputWrapper span.arrowUp::after { border-bottom-color: #ede7da; }
.dark .numInputWrapper span.arrowDown::after { border-top-color: #ede7da; }
.dark .flatpickr-day { color: #ede7da; }
.dark .flatpickr-day:hover, .dark .flatpickr-day:focus, .dark .flatpickr-day.prevMonthDay:hover, .dark .flatpickr-day.nextMonthDay:hover { background: #1d2a4f; border-color: #1d2a4f; }
.dark .flatpickr-day.today:not(.selected):hover { color: #ede7da; }

/* In-app dialog and toasts (partials/dialogs.html, js/dialogs.js). Own classes rather than Tailwind:
   toasts are created at runtime, after the Play CDN has generated its CSS. */
.fp-dialog { width: min(28rem, calc(100vw - 2rem)); margin: auto; border: 0; border-radius: 1rem; padding: 1.5rem; color: inherit; background: #fff; box-shadow: 0 20px 40px -12px rgb(14 26 60 / .35), 0 0 0 1px #e1d9c8; }
.dark .fp-dialog { background: #132045; box-shadow: 0 20px 40px -12px rgb(0 0 0 / .6), 0 0 0 1px #2e3a5e; }
.fp-dialog::backdrop { background: rgb(11 20 48 / .55); backdrop-filter: blur(2px); }
.fp-dialog [hidden] { display: none !important; }
.fp-dialog-title { font-size: 1.125rem; line-height: 1.5rem; font-weight: 600; }
.fp-dialog-body { margin-top: .5rem; font-size: .875rem; line-height: 1.375rem; color: rgb(var(--fp-soft)); }
.fp-dialog-field { margin-top: 1rem; }
.fp-dialog-field label { display: block; margin-bottom: .375rem; font-size: .875rem; font-weight: 500; }
.fp-dialog-field input, .fp-dialog-field select { width: 100%; border-radius: .5rem; border: 1px solid #cbc2af; background: #fff; color: inherit; font: inherit; font-size: .875rem; padding: .5rem .75rem; }
.dark .fp-dialog-field input, .dark .fp-dialog-field select { border-color: #2e3a5e; background: #0b1430; }
.fp-dialog-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: .5rem; margin-top: 1.5rem; }
.fp-btn { border-radius: .5rem; padding: .5rem 1rem; font-size: .875rem; font-weight: 500; transition: background-color .15s; }
.fp-btn-secondary { box-shadow: inset 0 0 0 1px #cbc2af; }
.fp-btn-secondary:hover { background: #ede7da; }
.dark .fp-btn-secondary { box-shadow: inset 0 0 0 1px #2e3a5e; }
.dark .fp-btn-secondary:hover { background: #1d2a4f; }
.fp-btn-primary { background: rgb(var(--fp-brand-600)); color: rgb(var(--fp-on-brand)); }
.fp-btn-primary:hover { background: rgb(var(--fp-brand-700)); }
.fp-btn-danger { background: #be123c; color: #fff; }   /* 6.3:1 */
.fp-btn-danger:hover { background: #9f1239; }
.fp-dialog :focus-visible, .fp-toast :focus-visible { outline: 2px solid rgb(var(--fp-brand-500)); outline-offset: 2px; }

.fp-toasts { position: fixed; z-index: 60; right: 1rem; bottom: 1rem; left: 1rem; display: flex; flex-direction: column; align-items: center; gap: .5rem; pointer-events: none; }
@media (min-width: 640px) { .fp-toasts { left: auto; align-items: flex-end; } }
.fp-toasts > div { display: flex; flex-direction: column; gap: .5rem; align-items: inherit; }
.fp-toast { pointer-events: auto; display: flex; align-items: flex-start; gap: .625rem; width: min(24rem, calc(100vw - 2rem)); padding: .75rem .75rem .75rem 1rem; border-radius: .75rem; font-size: .875rem; line-height: 1.25rem; background: #fff; box-shadow: 0 10px 25px -8px rgb(14 26 60 / .3), 0 0 0 1px #e1d9c8; border-left: 4px solid currentColor; animation: fp-toast-in .2s ease-out; }
.dark .fp-toast { background: #1d2a4f; box-shadow: 0 10px 25px -8px rgb(0 0 0 / .6), 0 0 0 1px #2e3a5e; }
.fp-toast-success { border-left-color: rgb(var(--fp-pos)); }
.fp-toast-error { border-left-color: rgb(var(--fp-neg)); }
.fp-toast-info { border-left-color: rgb(var(--fp-accent)); }
.fp-toast-icon { flex: none; width: 1.25rem; height: 1.25rem; }
.fp-toast-success .fp-toast-icon { color: rgb(var(--fp-pos)); }
.fp-toast-error .fp-toast-icon { color: rgb(var(--fp-neg)); }
.fp-toast-info .fp-toast-icon { color: rgb(var(--fp-accent)); }
.fp-toast-text { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.fp-toast-close { flex: none; border-radius: .375rem; padding: .125rem; color: rgb(var(--fp-muted)); }
.fp-toast-close:hover { background: #ede7da; }
.dark .fp-toast-close:hover { background: #2e3a5e; }
.fp-toast-x { width: 1rem; height: 1rem; }
.fp-toast-out { opacity: 0; transform: translateY(.25rem); transition: opacity .2s, transform .2s; }
@keyframes fp-toast-in { from { opacity: 0; transform: translateY(.5rem); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .fp-toast, .fp-toast-out { animation: none; transition: none; } }

/* No sideways page scroll on phones. (1) Absolutely positioned children (the sr-only labels in
   table cells) escape a static overflow-x container and widen the page: make those containers the
   containing block. (2) Grid items default to min-width: auto and grow to their content. :where()
   keeps specificity at 0, so an explicit Tailwind position/min-width class still wins. */
:where(.overflow-x-auto) { position: relative; }
:where(main .grid > *) { min-width: 0; }

/* Dropdowns look the same in every browser. Safari draws <select> as a glossy native button and
   ignores border/background unless appearance is off; the chevron is ours (muted token colours).
   select[class] outranks Tailwind's px-* so the chevron always has room. The date picker's month
   dropdown is left to flatpickr: the extra padding made it cover the year field next to it. */
select:not([multiple]):not(.flatpickr-monthDropdown-months) {
  -webkit-appearance: none; -moz-appearance: none; appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%23596075' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 8 4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right .5rem center; background-size: 1rem 1rem;
}
select:not([multiple]):not(.flatpickr-monthDropdown-months)[class],
select:not([multiple]):not(.flatpickr-monthDropdown-months) { padding-right: 2rem; }
.dark select:not([multiple]):not(.flatpickr-monthDropdown-months) {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%239aa3bb' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 8 4 4 4-4'/%3E%3C/svg%3E");
}

/* App lock keypad and install steps (account.html, lock.html) */
.fp-step { display: inline-grid; place-items: center; flex: none; width: 1.625rem; height: 1.625rem; border-radius: 9999px; font-size: .75rem; font-weight: 600; background: rgb(var(--fp-brand-600) / .12); color: rgb(var(--fp-accent)); }
.dark .fp-step { background: rgb(var(--fp-brand-600) / .18); }
.fp-key { height: 3.25rem; border-radius: 9999px; font-size: 1.25rem; font-weight: 500; box-shadow: inset 0 0 0 1px #cbc2af; transition: background-color .15s; }
.fp-key:hover:not(:disabled) { background: #ede7da; }
.dark .fp-key { box-shadow: inset 0 0 0 1px #2e3a5e; }
.dark .fp-key:hover:not(:disabled) { background: #1d2a4f; }
.fp-key:focus-visible { outline: 2px solid rgb(var(--fp-brand-500)); outline-offset: 2px; }

/* Installed app with the title bar hidden (window-controls-overlay, e.g. an install made before
   the manifest dropped it, or Edge's "hide title bar"): the window's own minimise / maximise /
   close buttons sit over the page's top-right corner. Keep the header clear of them and let its
   empty part drag the window. */
@media (display-mode: window-controls-overlay) {
  .fp-app-header {
    height: max(3.5rem, env(titlebar-area-height, 0px));
    padding-right: calc(100vw - env(titlebar-area-x, 0px) - env(titlebar-area-width, 100vw) + 1rem);
    -webkit-app-region: drag; app-region: drag;
  }
  .fp-app-header a, .fp-app-header button, .fp-app-header summary, .fp-app-header details,
  .fp-app-header form, .fp-app-header input, .fp-app-header select { -webkit-app-region: no-drag; app-region: no-drag; }
}

/* ---------------------------------------------------------------- phones and small tablets
   Below lg the sidebar becomes a bottom tab bar (partials/mobile_nav.html), a floating + button
   and section tabs. Everything here is mobile-only, so the desktop layout is untouched. */
.fp-bottom-bar { position: fixed; z-index: 30; left: 0; right: 0; bottom: 0; display: flex; padding-bottom: env(safe-area-inset-bottom, 0px); background: rgb(255 255 255 / .94); border-top: 1px solid #e1d9c8; backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); }
.dark .fp-bottom-bar { background: rgb(19 32 69 / .94); border-top-color: #2e3a5e; }
.fp-bottom-bar a:focus-visible, .fp-bottom-bar button:focus-visible { outline: 2px solid rgb(var(--fp-brand-500)); outline-offset: -4px; border-radius: .5rem; }
.fp-fab { position: fixed; z-index: 31; right: 1rem; bottom: calc(4.75rem + env(safe-area-inset-bottom, 0px)); }
.fp-fab > summary:focus-visible { outline: 2px solid rgb(var(--fp-brand-500)); outline-offset: 3px; }
.fp-fab[open] > summary { transform: rotate(45deg); }
.fp-fab > summary { transition: transform .15s; }
.fp-tabs { scrollbar-width: none; }
.fp-tabs::-webkit-scrollbar { display: none; }
@media (max-width: 1023.98px) {
  /* room for the bottom bar (and the + button over the last row) */
  body { padding-bottom: calc(5.5rem + env(safe-area-inset-bottom, 0px)); }
  .fp-toasts { bottom: calc(5.25rem + env(safe-area-inset-bottom, 0px)); }
}
@media (max-width: 639.98px) {
  /* page intros: keep the first line, the rest behind the reader's tap ("more" is native: the
     paragraph expands on focus/tap via .fp-intro-open set by app.js) */
  main h1 { font-size: 1.5rem; line-height: 2rem; }
  .fp-intro { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; cursor: pointer; }
  .fp-intro.fp-intro-open { display: block; -webkit-line-clamp: unset; }
  .fp-footer { padding-bottom: 1rem; }
  /* header action rows: compact buttons that wrap instead of squeezing */
  .fp-actions { width: 100%; }
  .fp-actions > * { padding: .4rem .7rem; }
}
/* asset / liability rows: details left, amount right; on phones the edit buttons sit under it */
.fp-wrow { display: flex; align-items: center; gap: .75rem 1rem; }
@media (max-width: 639.98px) {
  .fp-wrow { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: start; gap: .25rem .75rem; }
  .fp-wrow-end { grid-column: 2; grid-row: 1; }
  .fp-wrow-act { grid-column: 2; grid-row: 2; justify-content: flex-end; margin-right: -.25rem; }
  .fp-wrow > div:first-child, .fp-wrow > div.min-w-0 { grid-column: 1; grid-row: 1 / span 2; }
}
/* phones: forms open as bottom sheets (full width, rounded top, above the home indicator) */
@media (max-width: 639.98px) {
  .fp-sheet > form, .fp-sheet > div { max-width: none; border-radius: 1.25rem 1.25rem 0 0; max-height: 92vh; max-height: 92dvh; padding-bottom: calc(1.5rem + env(safe-area-inset-bottom, 0px)); }
  .fp-sheet-head { border-radius: 1.25rem 1.25rem 0 0; }
}

/* viewport-fit=cover (base.html): the page runs edge to edge, so keep content clear of a notch or
   rounded corner when the phone is held sideways (the bottom bar already pads for the home bar) */
@media (max-width: 1023.98px) {
  header.fp-app-header, main#main { padding-left: max(1rem, env(safe-area-inset-left, 0px)); padding-right: max(1rem, env(safe-area-inset-right, 0px)); }
}

/* a sheet, dialog or the menu drawer is open: the page behind stays put (app.js fpLockScroll) */
html.fp-locked, html.fp-locked body { overflow: hidden; overscroll-behavior: none; }

/* ---------------------------------------------------------------- touch screens (any phone or
   tablet, whatever its size, and any phone-width screen): finger-sized targets and no
   zoom-on-focus. Desktop with a mouse is untouched. */
/* an italic tag at the end of a truncated line ("expected") keeps its last letter: the slant
   sticks out of the box and the truncation would clip it ("expectea") */
.truncate .note { padding-right: .15em; }

@media (pointer: coarse), (max-width: 639.98px) {
  /* touch-sized checkboxes and radios (their label is tappable too) */
  input[type=checkbox], input[type=radio] { width: 1.25rem; height: 1.25rem; }
  /* iOS zooms the page into any field whose text is under 16px (and doesn't zoom back), which
     looks like fields overlapping; 16px avoids it on every phone */
  input:not([type=checkbox]):not([type=radio]):not([type=range]), select, textarea { font-size: 16px !important; }
  /* small text actions ("See 3 transactions →", "Dismiss", icon buttons) get an invisible tap
     area of at least ~32px around them, without moving anything */
  main :is(a, button, summary):not(.absolute):not(.fixed):not(.sticky):not(.sr-only),
  .fp-sheet :is(a, button):not(.absolute):not(.sr-only) { position: relative; }
  main :is(a, button, summary):not(.absolute):not(.fixed):not(.sticky):not(.sr-only)::after,
  .fp-sheet :is(a, button):not(.absolute):not(.sr-only)::after { content: ""; position: absolute; inset: -6px -4px; }
}
