/* ============================================================
   MAIN.CSS — Design tokens, reset, base typography
   Theme: Flow — crypto-wallet dashboard, pure mono school.
   True black canvas. White is the accent. Color = data only
   (green up, red down). Money: JetBrains Mono · UI: Inter.
   ============================================================ */

:root {
  /* --- Base palette (true black, neutral greys) --- */
  --color-bg:           #000000;
  --color-surface:      #0d0d0f;
  --color-surface-2:    #151518;
  --color-border:       #222226;
  --color-border-light: #18181b;
  --color-text:         #f4f4f6;
  /* muted bumped from #6e6e78 (~3.7:1, failed WCAG AA) to ~4.8:1 on the
     dark surfaces; light is for very-low-emphasis text only */
  --color-text-muted:   #8a8a94;
  --color-text-light:   #5c5c66;

  /* Sidebar */
  --color-sidebar-bg:          #000000;
  --color-sidebar-border:      #161619;
  --color-sidebar-text:        #5c5c66;
  --color-sidebar-active-bg:   rgba(255,255,255,.08);
  --color-sidebar-active-text: #ffffff;

  /* Brand — white. The accent is the absence of color. */
  --color-primary:       #ffffff;
  --color-primary-dark:  #d9d9de;
  --color-primary-light: rgba(255,255,255,.08);

  /* Semantic — the only color on screen */
  --color-income:        #00d18f;
  --color-income-light:  rgba(0,209,143,.12);
  --color-expense:       #ff5c7a;
  --color-expense-light: rgba(255,92,122,.12);
  --color-transfer:      #d4a64a;
  --color-transfer-light:rgba(212,166,74,.12);

  /* Shadows */
  --shadow-sm:  0 1px 3px rgba(0,0,0,.6);
  --shadow-md:  0 6px 28px rgba(0,0,0,.7);
  --shadow-lg:  0 16px 56px rgba(0,0,0,.9);

  /* Card depth: lit-from-above top edge */
  --card-edge: inset 0 1px 0 rgba(255,255,255,.04);

  /* Layout */
  --sidebar-width:     248px;
  --topbar-height:     56px;
  --bottom-nav-height: 64px;
  /* Terminal grid: sharp corners everywhere */
  --radius-sm:  0;
  --radius-md:  0;
  --radius-lg:  0;
  --radius-xl:  0;

  /* Transitions */
  --transition:      0.15s ease;
  --transition-slow: 0.3s ease;

  /* Typography */
  --font-body:    'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
  --font-display: 'JetBrains Mono', 'Consolas', 'SF Mono', monospace;

  /* Accent — white (kept as a var so components stay themeable) */
  --color-accent:       #ffffff;
  --color-accent-light: rgba(255,255,255,.10);
  --color-accent-dark:  #c9c9cf;

  /* Text/hover that sits ON the primary color (buttons etc.) */
  --color-primary-contrast: #0a0a0a;
  --color-primary-hover:    #e6e6ea;

  /* Chrome (blurred topbar / bottom nav) + monochrome outlines */
  --chrome-topbar: rgba(0,0,0,.88);
  --chrome-bottom: rgba(0,0,0,.92);
  --mono-outline:        rgba(255,255,255,.22);
  --mono-outline-strong: rgba(255,255,255,.5);

  color-scheme: dark;
}

/* ============================================================
   LIGHT THEME — the "white" half of the black/white switch.
   Same Flow rules, inverted: paper-white canvas, black accent,
   color still = data only. Toggled from the topbar (nav.js),
   persisted as localStorage pf_theme, applied pre-paint (ui.js).
   ============================================================ */
html[data-theme="light"] {
  --color-bg:           #f5f5f7;
  --color-surface:      #ffffff;
  --color-surface-2:    #ececef;
  --color-border:       #d9d9de;
  --color-border-light: #e7e7ec;
  --color-text:         #101014;
  --color-text-muted:   #5c5c66;
  --color-text-light:   #8a8a94;

  --color-sidebar-bg:          #ffffff;
  --color-sidebar-border:      #e7e7ec;
  --color-sidebar-text:        #8a8a94;
  --color-sidebar-active-bg:   rgba(0,0,0,.07);
  --color-sidebar-active-text: #000000;

  /* Brand — black. The accent is still the absence of color. */
  --color-primary:       #101014;
  --color-primary-dark:  #2e2e34;
  --color-primary-light: rgba(0,0,0,.06);

  /* Semantic — darkened for AA contrast on white */
  --color-income:        #00875d;
  --color-income-light:  rgba(0,135,93,.10);
  --color-expense:       #d4315b;
  --color-expense-light: rgba(212,49,91,.10);
  --color-transfer:      #96731f;
  --color-transfer-light:rgba(150,115,31,.12);

  --shadow-sm:  0 1px 3px rgba(20,20,26,.10);
  --shadow-md:  0 6px 28px rgba(20,20,26,.12);
  --shadow-lg:  0 16px 56px rgba(20,20,26,.18);

  --card-edge: inset 0 1px 0 rgba(255,255,255,.85);

  --color-accent:       #101014;
  --color-accent-light: rgba(0,0,0,.08);
  --color-accent-dark:  #33333a;

  --color-primary-contrast: #ffffff;
  --color-primary-hover:    #2e2e34;

  --chrome-topbar: rgba(255,255,255,.9);
  --chrome-bottom: rgba(255,255,255,.94);
  --mono-outline:        rgba(0,0,0,.25);
  --mono-outline-strong: rgba(0,0,0,.55);

  color-scheme: light;
}

/* --- Reset --- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* The `hidden` attribute must always win — several components set an explicit
   `display` on classes (e.g. `.dash-crypto { display:flex }`) which would
   otherwise override the UA `[hidden] { display:none }` and leave toggled-off
   sections (crypto, forecast, empty states) visible. */
[hidden] { display: none !important; }

html { scroll-behavior: smooth; }

body {
  font-family: var(--font-body);
  font-size: 14px;
  line-height: 1.6;
  color: var(--color-text);
  background-color: var(--color-bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-variant-numeric: tabular-nums;
}

a { color: var(--color-primary); text-decoration: none; }
a:hover { text-decoration: underline; }

button { font-family: inherit; cursor: pointer; border: none; background: none; }

/* ============================================================
   APP LOADER — minimalist boot popup. Sits in the markup so it
   paints with the first frame, then fades out once the page's data
   is ready. Rather than a separate full-screen wash, it's a small
   centered card over a dimmed, blurred view of the app itself — so
   it reads as "loading inside the site", not a different screen.
   Functional motion only: one hairline sweep, no ambient flourish.
   ============================================================ */
#app-loader {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.5);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  /* Stay invisible for the first beat: a load that finishes inside this delay
     hides the loader before it ever paints, so quick loads don't flash a
     pop-in. Only slower loads fade the loader in. */
  opacity: 0;
  animation: appLoaderReveal 0.25s ease 0.2s forwards;
  transition: opacity 0.3s ease, visibility 0.3s ease;
}
#app-loader.is-hidden { opacity: 0; visibility: hidden; pointer-events: none; animation: none; }
@keyframes appLoaderReveal { to { opacity: 1; } }

/* no panel — just the mark + sweep floating on the blurred scrim */
.app-loader__card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  padding: 0;
  background: none;
  border: none;
  box-shadow: none;
}

.app-loader__mark {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.0625rem;
  letter-spacing: 0.02em;
  color: #ffffff;
}
/* terminal cursor — matches the "Flow_" brand wordmark on the login screen */
.app-loader__mark::after { content: '_'; color: var(--color-text-muted); }
.app-loader__bar {
  position: relative;
  width: 104px;
  height: 2px;
  background: var(--color-border);
  overflow: hidden;
}
.app-loader__bar::after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 40%;
  background: #ffffff;
  animation: appLoaderSweep 1.1s ease-in-out infinite;
}
@keyframes appLoaderSweep {
  0%   { transform: translateX(-120%); }
  100% { transform: translateX(350%); }
}
@media (prefers-reduced-motion: reduce) {
  .app-loader__bar::after { animation: none; width: 100%; opacity: .4; }
  /* keep the reveal delay (so quick loads still don't flash) but skip the fade */
  #app-loader { animation-duration: 0.01ms; transition: none; }
}

/* ============================================================
   BALANCE CHART — Cash / Net-worth controls + disclosure note
   ============================================================ */
.balance-head-controls { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
.balance-mode { flex: 0 0 auto; }
.balance-mode-note {
  margin-top: 8px;
  font-size: 0.6875rem;
  color: var(--color-text-muted);
  letter-spacing: 0.01em;
}

/* ============================================================
   MILESTONE POP — one-shot net-worth celebration. Event-driven
   (fires only when a round number is first crossed), not ambient:
   scales in, holds, fades out, then removes itself.
   ============================================================ */
.milestone-pop {
  position: fixed;
  top: 18%;
  left: 50%;
  z-index: 10000;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 20px 34px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  box-shadow: var(--shadow-lg);
  text-align: center;
  animation: milestoneIn 0.5s cubic-bezier(.16, 1, .3, 1) both;
}
.milestone-pop--out { animation: milestoneOut 0.45s ease forwards; }
.milestone-pop__label {
  font-size: 0.625rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--color-text-muted);
}
.milestone-pop__value {
  font-size: clamp(1.75rem, 4vw, 2.5rem);
  font-weight: 700;
  color: #ffffff;
  letter-spacing: -0.04em;
  line-height: 1.1;
}
.milestone-pop__sub { font-size: 0.75rem; color: var(--color-income); letter-spacing: 0.02em; }
@keyframes milestoneIn {
  from { opacity: 0; transform: translate(-50%, 12px) scale(.94); }
  to   { opacity: 1; transform: translate(-50%, 0) scale(1); }
}
@keyframes milestoneOut {
  from { opacity: 1; transform: translate(-50%, 0) scale(1); }
  to   { opacity: 0; transform: translate(-50%, -8px) scale(.98); }
}
@media (prefers-reduced-motion: reduce) {
  .milestone-pop, .milestone-pop--out { animation: none; }
}

input, select, textarea { font-family: inherit; font-size: inherit; }

ul, ol { list-style: none; }
img    { max-width: 100%; display: block; }

/* --- Typography --- */
h1 { font-size: 1.5rem;    font-weight: 700; letter-spacing: -0.03em; }
h2 { font-size: 1.125rem;  font-weight: 600; letter-spacing: -0.02em; }
h3 { font-size: 0.9375rem; font-weight: 600; letter-spacing: -0.01em; }

/* Display figures — the money. JetBrains Mono, ledger-style. */
.font-display {
  font-family: var(--font-display);
  letter-spacing: -0.04em;
}

.text-accent  { color: var(--color-accent); }
.text-muted   { color: var(--color-text-muted); }
.text-light   { color: var(--color-text-light); }
.text-income  { color: var(--color-income); }
.text-expense { color: var(--color-expense); }
.text-primary { color: var(--color-primary); }

.font-medium   { font-weight: 500; }
.font-semibold { font-weight: 600; }
.font-bold     { font-weight: 700; }

/* --- Change pill (wallet staple: green up / red down) --- */
.flow-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 8px;
  border-radius: 0;
  font-family: var(--font-display);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.flow-pill--up   { background: var(--color-income-light);  color: var(--color-income); }
.flow-pill--down { background: var(--color-expense-light); color: var(--color-expense); }
.flow-pill--flat { background: var(--color-surface-2);     color: var(--color-text-muted); }

/* --- Animations --- */
@keyframes fadeInUp {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes fadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes scaleIn {
  from { opacity: 0; transform: scale(0.95); }
  to   { opacity: 1; transform: scale(1); }
}
@keyframes valueIn {
  from { opacity: 0; transform: translateY(5px); }
  to   { opacity: 1; transform: translateY(0); }
}

.animate-fade-in-up { animation: fadeInUp 0.3s ease both; }
.animate-fade-in    { animation: fadeIn   0.25s ease both; }
.animate-scale-in   { animation: scaleIn  0.2s ease both; }

/* Stagger children */
.stagger > *:nth-child(1) { animation-delay: 0ms; }
.stagger > *:nth-child(2) { animation-delay: 40ms; }
.stagger > *:nth-child(3) { animation-delay: 80ms; }
.stagger > *:nth-child(4) { animation-delay: 120ms; }
.stagger > *:nth-child(5) { animation-delay: 160ms; }
.stagger > *:nth-child(6) { animation-delay: 200ms; }
.stagger > *:nth-child(7) { animation-delay: 240ms; }
.stagger > *:nth-child(8) { animation-delay: 280ms; }

/* Value update flash */
@keyframes valueUpdate {
  0%   { opacity: 0.3; transform: translateY(3px); }
  100% { opacity: 1;   transform: translateY(0); }
}
.value-updated { animation: valueUpdate 0.25s ease both; }

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

/* --- Utility --- */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}
.truncate { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
