/* Mobile web view -- a separate, phone-first stylesheet from style.css
   (the desktop sidebar app). Deliberately small: a top app bar, a bottom
   tab bar, cards, chips, and a statement-line list. No sidebar, no theme
   picker -- one fixed palette matching the desktop app's default "Bank
   Green & Gold" theme for visual consistency. */

:root {
  /* Defaults match the "Bank Green & Gold" preset; templates/mobile/
     layout.html overrides all six per-request from the signed-in user's
     chosen theme (core/mobile_themes.py; Settings -> Color theme). The
     *-rgb companions let the rest of this file build translucent tints
     with rgba(var(--m-brand-rgb), 0.08) instead of a fixed color baked
     into every rule, so every preset gets themed shadows/badges/tints
     for free. */
  --m-brand: #0F4C33;
  --m-brand-rgb: 15,76,51;
  --m-brand-deep: #0A3323;
  --m-brand-deep-rgb: 10,51,35;
  --m-accent: #C9A227;
  --m-accent-rgb: 201,162,39;
  --m-ink: #172018;
  --m-ink-muted: #5B6D63;
  --m-line: #DCE7DF;
  --m-bg: #F5F8F4;
  --m-surface: #FFFFFF;
  --m-radius: 14px;
  --m-radius-sm: 9px;
  --m-shadow: 0 1px 2px rgba(16, 24, 40, 0.06), 0 1px 1px rgba(16, 24, 40, 0.04);
  --m-shadow-brand: 0 1px 2px rgba(var(--m-brand-rgb), 0.06), 0 10px 20px -12px rgba(var(--m-brand-rgb), 0.35);
  --m-danger: #B42318;
  --m-success: #12805C;
  --m-safe-bottom: env(safe-area-inset-bottom, 0px);
}

* { box-sizing: border-box; }
button { font-family: inherit; cursor: pointer; }

@keyframes m-fade-up {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: translateY(0); }
}

html, body {
  margin: 0;
  padding: 0;
  background: var(--m-bg);
  color: var(--m-ink);
  font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  -webkit-tap-highlight-color: transparent;
}

body.m-body {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  padding-bottom: calc(64px + var(--m-safe-bottom));
}

a { color: inherit; text-decoration: none; }

/* ---------- Page-loading bar ---------- */
/* A thin animated bar pinned to the very top of the screen, above even
   the sticky top bar -- shown for any tap that starts a real page
   navigation (see the loader script in layout.html's <body>). */
.m-page-loading-bar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  z-index: 50;
  background: linear-gradient(90deg, var(--m-accent), var(--m-brand), var(--m-accent));
  background-size: 200% 100%;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s ease;
}
.m-page-loading-bar.active {
  opacity: 1;
  animation: m-loading-slide 1s linear infinite;
}
@keyframes m-loading-slide {
  from { background-position: 200% 0; }
  to { background-position: -200% 0; }
}

/* ---------- Top app bar ---------- */
.m-topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.85rem 1rem;
  background: linear-gradient(135deg, var(--m-brand) 0%, var(--m-brand-deep) 130%);
  color: #fff;
  box-shadow: 0 2px 10px rgba(var(--m-brand-deep-rgb), 0.28);
}
.m-topbar .m-back {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.12);
  flex-shrink: 0;
}
.m-topbar .m-title {
  font-weight: 700;
  font-size: 1.02rem;
  line-height: 1.2;
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.m-topbar .m-title small {
  display: block;
  font-weight: 500;
  font-size: 0.72rem;
  opacity: 0.8;
}
.m-avatar {
  border-radius: 999px;
  background: var(--m-accent);
  color: var(--m-brand-deep);
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.m-topbar .m-avatar { width: 30px; height: 30px; font-size: 0.85rem; }
.m-install-btn {
  width: 32px;
  height: 32px;
  flex-shrink: 0;
  border: none;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.14);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
}
.m-install-btn:active { background: rgba(255, 255, 255, 0.24); }

/* ---------- Content ---------- */
.m-content {
  flex: 1;
  padding: 0.9rem 0.85rem 1.4rem;
  max-width: 640px;
  width: 100%;
  margin: 0 auto;
}

.m-section-title {
  font-size: 0.78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--m-ink-muted);
  margin: 1.1rem 0.15rem 0.5rem;
}
.m-section-title:first-child { margin-top: 0.1rem; }

/* ---------- Cards ---------- */
.m-card {
  background: var(--m-surface);
  border: 1px solid var(--m-line);
  border-radius: var(--m-radius);
  box-shadow: var(--m-shadow-brand);
  padding: 0.9rem 1rem;
  margin-bottom: 0.65rem;
  /* NOT "... both" -- a fill-mode of forwards/both keeps this element
     associated with an (ended) transform indefinitely in some browsers,
     which quietly turns it into a *containing block* for any
     position:fixed descendant -- exactly what the color-picker modal
     is. That's why the modal opened from a card here (Favorites/Reports
     list) rendered squeezed into this card's own small box instead of
     covering the screen, instead of the KPI cards (no entrance
     animation) where it opened correctly. Dropping the fill mode (so it
     defaults to "none") lets the transform stop applying the instant
     the 0.25s intro finishes, well before anyone taps a card -- the
     visible fade-in looks identical either way. */
  animation: m-fade-up 0.25s ease;
  transition: box-shadow 0.18s ease, transform 0.18s ease;
}
.m-card.m-tap {
  display: block;
  transition: transform 0.08s ease, box-shadow 0.15s ease;
}
.m-card.m-tap:active { transform: scale(0.98); background: var(--m-bg); }

/* A "run card" is a container: the tappable body (nav to the run) plus a
   row of real buttons (star / reorder) that sit OUTSIDE the <a>, so they
   stay independently clickable instead of both firing on every tap. */
.m-run-card {
  /* NOT overflow:hidden -- that would also clip the color-picker's
     dropdown popup (a child of .m-run-actions, opening below the card),
     which is a real bug users hit: the popup either got cut off or
     vanished entirely. The two things overflow:hidden used to be for
     (the ::before accent stripe and .m-run-body's :active background)
     now round their OWN corners to match instead (see below), so
     nothing needs the parent to clip. */
  padding: 0;
  position: relative;
}
.m-run-card::before {
  content: "";
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 3px;
  border-radius: var(--m-radius) 0 0 var(--m-radius);
  background: linear-gradient(var(--m-accent), var(--m-brand));
  opacity: 0;
  transition: opacity 0.15s ease;
}
.m-run-card.m-is-favorite::before { opacity: 1; }
/* A per-card color (Settings has no app-wide theme -- this is set per
   report, from the color dot on the card itself) recolors the WHOLE
   card -- background gradient, border and a shadow tinted to match --
   not just a thin accent stripe, so it reads clearly at a glance while
   scanning a list. The plain favorite-star stripe (::before, above) is
   hidden once a color is set since the full background already carries
   the color. --card-accent-rgb is the same theme's brand_rgb, passed
   alongside --card-accent/--card-accent-deep by _run_card.html, used
   here for the rgba() shadow and translucent white overlays below. */
.m-run-card.m-has-color::before { opacity: 0; }
.m-run-card.m-has-color {
  background: linear-gradient(135deg, var(--card-accent) 0%, var(--card-accent-deep) 100%);
  border-color: transparent;
  box-shadow:
    0 14px 26px -14px rgba(var(--card-accent-rgb), 0.6),
    0 3px 8px -2px rgba(var(--card-accent-rgb), 0.3);
}
.m-run-card.m-has-color .m-run-scope,
.m-run-card.m-has-color .m-run-period,
.m-run-card.m-has-color .m-chevron { color: var(--card-accent-text, #fff); }
.m-run-card.m-has-color .m-run-period { opacity: 0.85; }
.m-run-card.m-has-color .m-badge {
  background: var(--card-accent-overlay, rgba(255, 255, 255, 0.2));
  color: var(--card-accent-text, #fff);
  border-color: transparent;
}
.m-run-card.m-has-color .m-run-actions { border-top-color: var(--card-accent-overlay, rgba(255, 255, 255, 0.22)); }
.m-run-card.m-has-color .m-star-btn,
.m-run-card.m-has-color .m-reorder-btn,
.m-run-card.m-has-color .m-color-toggle { color: var(--card-accent-text, #fff); opacity: 0.9; }
.m-run-card.m-has-color .m-star-btn.m-star-active { color: #FFE38A; opacity: 1; }
.m-run-card.m-has-color .m-star-btn:active,
.m-run-card.m-has-color .m-reorder-btn:active,
.m-run-card.m-has-color .m-color-toggle:active { background: var(--card-accent-overlay-strong, rgba(255, 255, 255, 0.32)); }
.m-run-card.m-has-color .m-color-dot-preview { border-color: var(--card-accent-text, #fff); opacity: 0.85; }
.m-run-card.m-has-color .m-run-body:active { background: var(--card-accent-overlay, rgba(0, 0, 0, 0.14)); }
.m-run-card:active { box-shadow: 0 1px 2px rgba(var(--m-brand-rgb), 0.1); }
.m-run-card.m-has-color:active {
  box-shadow:
    0 6px 14px -10px rgba(var(--card-accent-rgb), 0.55),
    0 2px 5px -1px rgba(var(--card-accent-rgb), 0.3);
}
.m-run-body {
  display: block;
  padding: 0.9rem 1rem 0.7rem;
  /* Rounds its own top corners to match the card (see .m-run-card's
     comment on why the card itself no longer clips overflow) so its
     :active background below doesn't square off past the card's
     rounded top-left/top-right corners. */
  border-radius: var(--m-radius) var(--m-radius) 0 0;
  transition: background 0.1s ease;
}
.m-run-body:active { background: var(--m-bg); }
.m-run-card .m-run-top {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 0.6rem;
}
.m-run-card .m-run-scope {
  font-weight: 700;
  font-size: 0.95rem;
  color: var(--m-brand);
}
.m-run-card .m-run-period {
  font-size: 0.82rem;
  color: var(--m-ink-muted);
  margin-top: 0.15rem;
}
.m-run-card .m-run-meta {
  margin-top: 0.5rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
}
.m-chevron { color: var(--m-ink-muted); opacity: 0.6; flex-shrink: 0; }

.m-run-actions {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.35rem 0.6rem 0.5rem;
  border-top: 1px solid var(--m-line);
}
.m-run-actions form { display: contents; }
.m-star-btn, .m-reorder-btn {
  border: none;
  background: transparent;
  color: var(--m-ink-muted);
  width: 34px;
  height: 34px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background 0.12s ease, color 0.12s ease, transform 0.12s ease;
}
.m-star-btn:active, .m-reorder-btn:active { transform: scale(0.9); background: var(--m-bg); }
.m-star-btn.m-star-active { color: var(--m-accent); }
.m-reorder-btn:disabled { opacity: 0.3; }
.m-star-btn { margin-left: auto; }

/* Per-card color picker: a native <details>/<summary> disclosure (no JS
   needed to OPEN it) showing 16 tappable color swatches + a clear
   button, as a proper CENTERED MODAL rather than a small dropdown.
   Earlier this opened as a little popup anchored to the toggle button --
   that's what kept getting clipped or tucked behind other UI depending
   on where the card sat on screen (see mobile_bright_theme /
   color_popup_fix history). A modal fixed to the viewport and always
   centered has no "where does it open relative to this card" problem at
   all: it looks and behaves identically whether it was opened from a
   KPI card, a Favorites card, or the Reports list. A little JS (see
   templates/mobile/layout.html) lets tapping the dark backdrop or the
   X close it -- opening still needs none. */
.m-color-picker { position: relative; }
.m-color-toggle {
  list-style: none;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.12s ease;
}
.m-color-toggle::-webkit-details-marker { display: none; }
.m-color-toggle:active { background: var(--m-bg); }
.m-color-dot-preview {
  width: 16px;
  height: 16px;
  border-radius: 999px;
  background: var(--dot, transparent);
  border: 2px solid var(--dot, var(--m-line));
}
.m-color-dot-preview.m-color-none {
  background: transparent;
  border: 2px dashed var(--m-ink-muted);
  opacity: 0.55;
}

/* The full-screen backdrop + centering layer. Always fixed to the
   viewport (not the card), so it's dead-center on screen no matter
   which card's color dot opened it, and always above everything else
   on the page (topbar/bottomnav are z-index 20). */
.m-color-options {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.1rem;
  background: rgba(15, 23, 42, 0.55);
  animation: m-fade-in 0.15s ease both;
}
/* The actual white panel, centered by the backdrop above. */
.m-color-modal {
  width: 100%;
  max-width: 360px;
  max-height: 82vh;
  overflow-y: auto;
  background: var(--m-surface);
  border-radius: var(--m-radius);
  padding: 1rem 1rem 1.1rem;
  box-shadow: 0 24px 48px -16px rgba(16, 24, 40, 0.4);
  animation: m-modal-pop 0.18s ease both;
}
.m-color-modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.85rem;
  font-weight: 700;
  font-size: 0.95rem;
  color: var(--m-ink);
}
.m-color-modal-close {
  width: 30px;
  height: 30px;
  flex-shrink: 0;
  border: none;
  border-radius: 999px;
  background: var(--m-bg);
  color: var(--m-ink-muted);
  display: flex;
  align-items: center;
  justify-content: center;
}
.m-color-modal-close:active { background: var(--m-line); }
/* The 16 swatches themselves -- a 4x4 grid of noticeably bigger, easier
   to tap squares (was a cramped row of 24px dots). */
.m-color-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.65rem;
}
.m-color-grid form { display: contents; }
.m-color-dot {
  width: 100%;
  aspect-ratio: 1;
  min-height: 54px;
  border-radius: 14px;
  border: 3px solid transparent;
  background: var(--dot);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.1s ease, border-color 0.1s ease;
}
.m-color-dot:active { transform: scale(0.9); }
.m-color-dot.active { border-color: var(--m-ink); box-shadow: 0 0 0 2px var(--m-surface) inset; }
.m-color-dot.m-color-clear {
  background: var(--m-bg);
  border: 2px dashed var(--m-line);
  color: var(--m-ink-muted);
}
/* "Or pick your own" -- a color wheel (native <input type=color>, so no
   picker UI to build/maintain) paired with a plain hex text field so a
   known brand hex can just be typed in, both kept in sync by a little JS
   (see templates/mobile/layout.html's data-hex-pair listener) but the
   text field + Apply button alone are enough to set a color with no JS
   at all, same as every other control in this picker. */
.m-color-custom {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.85rem;
  padding-top: 0.85rem;
  border-top: 1px solid var(--m-line);
}
.m-color-custom-swatch {
  width: 40px;
  height: 40px;
  flex-shrink: 0;
  padding: 0;
  border: 2px solid var(--m-line);
  border-radius: 10px;
  background: none;
  cursor: pointer;
}
.m-color-custom-hex {
  flex: 1;
  min-width: 0;
  height: 40px;
  padding: 0 0.7rem;
  border: 1px solid var(--m-line);
  border-radius: 10px;
  background: var(--m-surface);
  color: var(--m-ink);
  font-size: 0.9rem;
  font-family: inherit;
  text-transform: uppercase;
}
.m-color-custom-hex.active { border-color: var(--m-brand); border-width: 2px; }
.m-color-custom-apply {
  height: 40px;
  padding: 0 0.9rem;
  flex-shrink: 0;
  border: none;
  border-radius: 10px;
  background: var(--m-brand);
  color: #fff;
  font-weight: 700;
  font-size: 0.85rem;
}
.m-color-custom-apply:active { background: var(--m-brand-deep); }
@keyframes m-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes m-modal-pop {
  from { opacity: 0; transform: scale(0.94) translateY(6px); }
  to { opacity: 1; transform: scale(1) translateY(0); }
}

/* ---------- Badges / chips ---------- */
.m-badge {
  display: inline-flex;
  align-items: center;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  padding: 0.15rem 0.5rem;
  border-radius: 999px;
  background: var(--m-bg);
  color: var(--m-ink-muted);
  border: 1px solid var(--m-line);
}
.m-badge.m-badge-brand { background: rgba(var(--m-brand-rgb), 0.08); color: var(--m-brand); border-color: rgba(var(--m-brand-rgb), 0.18); }
.m-badge.m-badge-gold { background: rgba(var(--m-accent-rgb), 0.16); color: var(--m-brand-deep); border-color: rgba(var(--m-accent-rgb), 0.32); }

.m-chip-row {
  display: flex;
  gap: 0.4rem;
  overflow-x: auto;
  padding: 0.15rem 0.05rem 0.6rem;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.m-chip-row::-webkit-scrollbar { display: none; }
.m-chip {
  flex-shrink: 0;
  padding: 0.4rem 0.85rem;
  border-radius: 999px;
  border: 1px solid var(--m-line);
  background: var(--m-surface);
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--m-ink);
  white-space: nowrap;
}
.m-chip.active { background: var(--m-brand); border-color: var(--m-brand); color: #fff; }
.m-chip.pending { color: var(--m-ink-muted); opacity: 0.55; }

/* ---------- Sheet grid (run detail) ---------- */
.m-sheet-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.6rem;
}
.m-sheet-tile {
  background: var(--m-surface);
  border: 1px solid var(--m-line);
  border-radius: var(--m-radius-sm);
  padding: 0.75rem 0.8rem;
  box-shadow: var(--m-shadow-brand);
  transition: transform 0.12s ease, box-shadow 0.12s ease;
}
.m-sheet-tile.m-tap:active { transform: scale(0.96); box-shadow: var(--m-shadow); }
.m-sheet-tile .m-sheet-form { font-size: 0.7rem; font-weight: 700; color: var(--m-accent); letter-spacing: 0.02em; }
.m-sheet-tile .m-sheet-title { font-size: 0.85rem; font-weight: 600; margin-top: 0.15rem; line-height: 1.25; }
.m-sheet-tile.m-sheet-pending { opacity: 0.5; }
.m-sheet-tile.m-sheet-pending .m-sheet-form { color: var(--m-ink-muted); }

/* ---------- KPI cards (Home) ---------- */
.m-kpi-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.6rem;
  margin-bottom: 0.3rem;
}
/* Every KPI card carries its own accent (a random-but-stable default, or
   the color the person picked from its own dot picker -- see
   blueprints.mobile._default_kpi_color / kpi_color()) as three inline
   custom properties: --kpi-accent, --kpi-accent-deep, --kpi-accent-rgb.
   The whole card is tinted with it -- background gradient AND a shadow
   colored to match, not just an accent line -- for a livelier, more
   "dashboard" feel than the plain white report cards. */
.m-kpi-card {
  /* NOT overflow:hidden -- same reasoning as .m-run-card above: this
     card's own color-picker popup opens from its top-right corner and
     was getting clipped by this, which is why only a sliver of the
     10-color popup was ever visible instead of the whole thing. Nothing
     else in this card needs the parent to clip (background-clip already
     respects border-radius on its own). */
  position: relative;
  background: linear-gradient(135deg, var(--kpi-accent) 0%, var(--kpi-accent-deep) 100%);
  border: 1px solid transparent;
  border-radius: var(--m-radius-sm);
  padding: 0.8rem 0.85rem;
  box-shadow:
    0 12px 22px -12px rgba(var(--kpi-accent-rgb), 0.6),
    0 3px 8px -2px rgba(var(--kpi-accent-rgb), 0.35);
  color: var(--kpi-accent-text, #fff);
  transition: transform 0.12s ease, box-shadow 0.12s ease;
}
.m-kpi-card:active {
  /* NOT transform: scale(...) -- :active applies to this card while
     ANY descendant is pressed too, including a color swatch inside its
     own (position:fixed) color-picker modal. A transform here would
     make this card the modal's containing block for as long as the
     swatch is held down, so the fixed modal would suddenly shrink down
     to this small card's box mid-tap -- the exact "popup keeps
     misbehaving, can't actually pick a color" bug reported on KPI
     cards specifically (report/favorite cards never had a transform
     here, only a box-shadow change, which is why they were fine). The
     box-shadow "press" feedback below is kept; only the scale is gone. */
  box-shadow:
    0 6px 14px -8px rgba(var(--kpi-accent-rgb), 0.55),
    0 2px 5px -1px rgba(var(--kpi-accent-rgb), 0.3);
}
.m-kpi-icon {
  width: 30px;
  height: 30px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--kpi-accent-overlay, rgba(255, 255, 255, 0.22));
  color: var(--kpi-accent-text, #fff);
  margin-bottom: 0.5rem;
}
.m-kpi-label { font-size: 0.75rem; color: var(--kpi-accent-text, #fff); opacity: 0.85; font-weight: 600; }
.m-kpi-value { font-size: 1.05rem; font-weight: 800; color: var(--kpi-accent-text, #fff); margin-top: 0.15rem; letter-spacing: -0.01em; }
.m-kpi-growth { font-size: 0.72rem; font-weight: 700; margin-top: 0.3rem; }
.m-kpi-growth.up { color: var(--kpi-growth-up, #BFF7D9); }
.m-kpi-growth.down { color: var(--kpi-growth-down, #FFD0C7); }
.m-kpi-growth.flat { color: var(--kpi-growth-flat, rgba(255, 255, 255, 0.75)); }

/* The color-dot TOGGLE sits in a KPI card's own top-right corner, over
   its (colored) background -- needs a translucent treatment matching
   THIS card's own overlay tint (dark on a pale card, white on a
   saturated one) instead of always assuming a dark background. Once
   open, the modal itself (.m-color-options/.m-color-modal above) is
   always centered on the viewport, identically for every card -- no
   per-card positioning needed any more. */
.m-kpi-color-picker { position: absolute; top: 0.45rem; right: 0.45rem; }
.m-kpi-color-picker .m-color-toggle { width: 26px; height: 26px; background: var(--kpi-accent-overlay, rgba(255, 255, 255, 0.16)); }
.m-kpi-color-picker .m-color-toggle:active { background: var(--kpi-accent-overlay-strong, rgba(255, 255, 255, 0.3)); }
.m-kpi-color-picker .m-color-dot-preview { border-color: var(--kpi-accent-text, #fff); opacity: 0.85; }

/* ---------- Filter panel ---------- */
.m-filter-toggle {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--m-brand);
  padding: 0.55rem 0.2rem;
}
.m-filter-panel {
  background: var(--m-surface);
  border: 1px solid var(--m-line);
  border-radius: var(--m-radius);
  padding: 0.9rem 1rem;
  margin-bottom: 0.7rem;
}
.m-filter-panel .form-label { font-size: 0.78rem; font-weight: 600; color: var(--m-ink-muted); }
.m-filter-panel .form-select, .m-filter-panel .form-control { font-size: 0.9rem; }

/* ---------- Statement line list ---------- */
.m-line {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.7rem;
  padding: 0.55rem 0;
  border-bottom: 1px solid var(--m-line);
}
.m-line:last-child { border-bottom: none; }
.m-line .m-line-label { font-size: 0.88rem; line-height: 1.3; }
.m-line .m-line-amounts { text-align: right; flex-shrink: 0; font-variant-numeric: tabular-nums; }
.m-line .m-line-cur { font-size: 0.92rem; font-weight: 600; }
.m-line .m-line-prev { font-size: 0.73rem; color: var(--m-ink-muted); }
.m-line.m-line-header .m-line-label { font-weight: 700; color: var(--m-brand); margin-top: 0.3rem; }
.m-line.m-line-subtotal { background: rgba(var(--m-brand-rgb), 0.045); margin: 0 -1rem; padding: 0.55rem 1rem; border-radius: 8px; }
.m-line.m-line-subtotal .m-line-label, .m-line.m-line-subtotal .m-line-cur { font-weight: 700; }
.m-line.m-line-grandtotal { background: rgba(var(--m-accent-rgb), 0.14); margin: 0 -1rem; padding: 0.6rem 1rem; border-radius: 8px; }
.m-line.m-line-grandtotal .m-line-label, .m-line.m-line-grandtotal .m-line-cur { font-weight: 800; color: var(--m-brand-deep); }

/* ---------- Bottom nav ---------- */
.m-bottomnav {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 20;
  display: flex;
  background: var(--m-surface);
  border-top: 1px solid var(--m-line);
  box-shadow: 0 -2px 10px rgba(16, 24, 40, 0.06);
  padding-bottom: var(--m-safe-bottom);
}
.m-bottomnav a {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.15rem;
  padding: 0.55rem 0 0.5rem;
  font-size: 0.68rem;
  font-weight: 600;
  color: var(--m-ink-muted);
}
.m-bottomnav a.active { color: var(--m-brand); }
.m-bottomnav a.active svg { stroke: var(--m-brand); }

/* ---------- Empty / error states ---------- */
.m-empty {
  text-align: center;
  padding: 2.5rem 1rem;
  color: var(--m-ink-muted);
}
.m-empty svg { opacity: 0.35; margin-bottom: 0.6rem; }
.m-alert {
  background: rgba(180, 35, 24, 0.08);
  border: 1px solid rgba(180, 35, 24, 0.25);
  color: var(--m-danger);
  border-radius: var(--m-radius-sm);
  padding: 0.7rem 0.9rem;
  font-size: 0.85rem;
  margin-bottom: 0.7rem;
}

@media (min-width: 480px) {
  .m-sheet-grid { grid-template-columns: repeat(3, 1fr); }
}

/* ---------- Sign-in screen ---------- */
.m-login {
  max-width: 360px;
  margin: 1.2rem auto 0;
  padding: 0 0.25rem;
  text-align: center;
}
.m-login-logo { margin-bottom: 0.9rem; }
.m-login-logo img { border-radius: 16px; box-shadow: var(--m-shadow); }
.m-login-eyebrow {
  text-transform: uppercase;
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  color: var(--m-accent);
  font-weight: 700;
  margin-bottom: 0.3rem;
}
.m-login-title { font-size: 1.35rem; margin: 0 0 0.3rem; color: var(--m-ink); }
.m-login-sub { font-size: 0.86rem; color: var(--m-ink-muted); margin: 0 0 1.4rem; }
.m-login-form {
  background: var(--m-surface);
  border: 1px solid var(--m-line);
  border-radius: var(--m-radius);
  box-shadow: var(--m-shadow);
  padding: 1.1rem;
  text-align: left;
}
.m-login-label { display: block; font-size: 0.8rem; font-weight: 600; color: var(--m-ink); margin: 0.7rem 0 0.3rem; }
.m-login-label:first-child { margin-top: 0; }
.m-login-input {
  width: 100%;
  padding: 0.7rem 0.85rem;
  border: 1px solid var(--m-line);
  border-radius: var(--m-radius-sm);
  font-size: 0.95rem;
  background: var(--m-bg);
  color: var(--m-ink);
}
.m-login-input:focus { outline: none; border-color: var(--m-brand); background: var(--m-surface); }
.m-login-btn {
  width: 100%;
  margin-top: 1.1rem;
  padding: 0.75rem;
  border: none;
  border-radius: var(--m-radius-sm);
  background: var(--m-brand);
  color: #fff;
  font-size: 0.95rem;
  font-weight: 700;
}
.m-login-btn:active { background: var(--m-brand-deep); }
.m-login-alt {
  display: block;
  margin-top: 1rem;
  font-size: 0.82rem;
  color: var(--m-ink-muted);
  text-decoration: underline;
}
.m-login-foot {
  margin-top: 1.6rem;
  font-size: 0.72rem;
  color: var(--m-ink-muted);
  opacity: 0.8;
}

/* ---------- PIN pad ---------- */
.m-pin-form { text-align: center; }
.m-pin-input {
  display: block;
  width: 100%;
  max-width: 220px;
  margin: 0 auto 1.2rem;
  padding: 0.7rem 0;
  border: 1px solid var(--m-line);
  border-radius: var(--m-radius-sm);
  background: var(--m-surface);
  box-shadow: var(--m-shadow-brand);
  font-size: 1.6rem;
  letter-spacing: 0.7em;
  text-align: center;
  color: var(--m-ink);
}
.m-pin-input:focus { outline: none; border-color: var(--m-brand); }

/* Dot-box PIN entry: a row of empty circles that fill in as digits are
   typed, instead of a single masked text field. The actual <input> stays
   in the DOM (so a real keyboard and password managers still work) but is
   stretched invisibly over the dots -- tapping anywhere on the box
   focuses it, and its own JS keeps the dots in sync with its value. */
.m-pin-box { position: relative; width: 100%; max-width: 220px; margin: 0 auto 1.2rem; }
.m-pin-dots {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 1rem;
  padding: 1.15rem 0;
  border: 1px solid var(--m-line);
  border-radius: var(--m-radius-sm);
  background: var(--m-surface);
  box-shadow: var(--m-shadow-brand);
}
.m-pin-dot {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 2px solid var(--m-line);
  background: transparent;
  transition: background 0.12s ease, border-color 0.12s ease, transform 0.12s ease;
}
.m-pin-dot.filled { background: var(--m-brand); border-color: var(--m-brand); transform: scale(1.1); }
.m-pin-box.m-pin-box-error .m-pin-dots { border-color: var(--m-danger, #b3261e); }
/* PIN unlock screen only (pin.html): no card box behind the dots -- just
   the dots themselves floating on the page background. The dots' own
   circles are unaffected; only the surrounding surface/border/shadow the
   dots normally sit in is removed. */
.m-pin-dots-transparent {
  background: transparent;
  border-color: transparent;
  box-shadow: none;
  padding-top: 0;
  padding-bottom: 0;
}
.m-pin-real-input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  border: 0;
  padding: 0;
  margin: 0;
  background: transparent;
  z-index: 2;
}
.m-keypad {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.6rem;
  max-width: 260px;
  margin: 0 auto 1.2rem;
}
.m-key {
  aspect-ratio: 1 / 1;
  border: 1px solid var(--m-line);
  background: var(--m-surface);
  border-radius: 999px;
  font-size: 1.25rem;
  font-weight: 700;
  color: var(--m-ink);
  box-shadow: var(--m-shadow);
  transition: transform 0.1s ease, background 0.1s ease;
}
.m-key:active { transform: scale(0.9); background: var(--m-bg); }
.m-key-back { color: var(--m-ink-muted); }
.m-key-back svg { display: block; margin: 0 auto; }

/* ---------- Settings ---------- */
.m-settings-row-title { font-weight: 700; font-size: 0.92rem; }
.m-settings-row-sub { font-size: 0.8rem; color: var(--m-ink-muted); margin-top: 0.15rem; }
.m-settings-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.85rem;
}
.m-settings-actions form { display: contents; }
.m-btn-solid, .m-btn-outline {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.55rem 1rem;
  border-radius: var(--m-radius-sm);
  font-size: 0.85rem;
  font-weight: 700;
  border: 1px solid var(--m-brand);
}
.m-btn-solid { background: var(--m-brand); color: #fff; border-color: var(--m-brand); }
.m-btn-solid:active { background: var(--m-brand-deep); }
.m-btn-outline { background: transparent; color: var(--m-brand); }
.m-btn-outline:active { background: rgba(var(--m-brand-rgb), 0.08); }
.m-btn-outline.m-btn-danger { color: var(--m-danger); border-color: rgba(180, 35, 24, 0.4); }
.m-btn-outline.m-btn-danger:active { background: rgba(180, 35, 24, 0.08); }

.m-settings-link {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.85rem 1rem;
  font-size: 0.9rem;
  font-weight: 600;
  border-bottom: 1px solid var(--m-line);
}
.m-settings-link:last-child { border-bottom: none; }
.m-settings-link svg { color: var(--m-ink-muted); }
.m-settings-link:active { background: var(--m-bg); }

/* ---------- Trends widgets ---------- */
.m-trend-card {
  padding: 1rem 1rem 0.8rem;
  position: relative;
  overflow: hidden;
  transition: box-shadow 0.15s ease;
}
.m-trend-card::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  background: linear-gradient(90deg, var(--trend-accent, var(--m-brand)), color-mix(in srgb, var(--trend-accent, var(--m-brand)) 40%, transparent));
}
.m-trend-card:active { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--trend-accent, var(--m-brand)) 30%, transparent); }
.m-trend-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.6rem;
  margin-bottom: 0.5rem;
}
.m-trend-label { font-size: 0.85rem; font-weight: 700; color: var(--m-ink); }
.m-trend-value { font-size: 1.2rem; font-weight: 800; color: var(--trend-accent, var(--m-brand)); margin-top: 0.1rem; }
.m-trend-chart { color: var(--trend-accent, var(--m-brand)); margin-top: 0.2rem; }
.m-trend-head-right { display: flex; flex-direction: column; align-items: flex-end; gap: 0.35rem; }
.m-trend-reorder { display: flex; gap: 0.3rem; }
.m-trend-reorder form { margin: 0; }
.m-trend-move-btn {
  border: 1px solid var(--m-line);
  background: var(--m-surface);
  color: var(--m-ink-muted);
  width: 1.6rem;
  height: 1.6rem;
  border-radius: 50%;
  font-size: 0.65rem;
  line-height: 1;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.m-trend-move-btn:active { background: var(--m-bg); }
.m-trend-move-btn:disabled { opacity: 0.3; }

/* ---------- Trends: key financial ratios strip ---------- */
.m-ratio-strip { padding: 1rem 1rem 0.9rem; margin-bottom: 0.9rem; overflow: hidden; position: relative; }
.m-ratio-period { font-size: 0.72rem; font-weight: 500; color: var(--m-ink-muted); text-transform: none; letter-spacing: normal; margin-left: 0.4rem; }
.m-ratio-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(92px, 1fr));
  gap: 0.6rem;
}
.m-ratio-tile {
  --ratio-accent: var(--m-brand);
  background: linear-gradient(160deg, color-mix(in srgb, var(--ratio-accent) 12%, var(--m-bg)) 0%, var(--m-bg) 65%);
  border: 1px solid color-mix(in srgb, var(--ratio-accent) 22%, transparent);
  border-radius: 12px;
  padding: 0.6rem 0.5rem 0.55rem;
  text-align: center;
  position: relative;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
  animation: m-ratio-tile-in 0.45s ease-out both;
  animation-delay: var(--ratio-delay, 0ms);
}
.m-ratio-tile:active { transform: scale(0.96); }
@keyframes m-ratio-tile-in {
  from { opacity: 0; transform: translateY(6px) scale(0.97); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .m-ratio-tile { animation: none; }
}
.m-ratio-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--ratio-accent) 18%, transparent);
  color: var(--ratio-accent);
  margin-bottom: 0.3rem;
}
.m-ratio-value { font-size: 1.08rem; font-weight: 800; color: var(--ratio-accent); }
.m-ratio-label { font-size: 0.68rem; font-weight: 700; color: var(--m-ink); margin-top: 0.15rem; }
.m-ratio-formula { font-size: 0.58rem; color: var(--m-ink-muted); margin-top: 0.1rem; line-height: 1.25; }
.m-ratio-note { font-size: 0.66rem; color: var(--m-ink-muted); margin-top: 0.75rem; line-height: 1.4; }
/* A negative ratio overrides its own accent color with a warning red --
   whatever the ratio's normal identity color is, a negative reading
   always reads as "down/loss", consistent with the red used for a "down"
   MoM badge and a negative chart bar/point elsewhere on this page. */
.m-ratio-tile.m-ratio-negative {
  --ratio-accent: #C81E3A;
  border-color: color-mix(in srgb, #C81E3A 30%, transparent);
}

/* ---------- Trends: bar/line toggle + tap tooltip ---------- */
.m-chart-view-toggle {
  display: inline-flex;
  border: 1px solid var(--m-line);
  border-radius: 999px;
  padding: 2px;
  margin-bottom: 0.7rem;
  background: var(--m-surface);
}
.m-chart-view-toggle button {
  border: none;
  background: transparent;
  color: var(--m-ink-muted);
  font-size: 0.78rem;
  font-weight: 700;
  padding: 0.35rem 0.9rem;
  border-radius: 999px;
}
.m-chart-view-toggle button.active { background: var(--m-brand); color: #fff; }
.m-trend-hint { font-size: 0.7rem; color: var(--m-ink-muted); margin-top: 0.3rem; text-align: center; }
.m-chart-mark { cursor: pointer; }
.m-chart-mark:focus { outline: 2px solid var(--m-brand); outline-offset: 1px; }
/* A month's bar or point fades/rises in on load -- a subtle, purely
   decorative entrance so the chart feels alive rather than just
   appearing fully formed; harmless if reduced-motion disables it. */
.m-chart-bar {
  transform-box: fill-box;
  transform-origin: bottom;
  animation: m-chart-bar-in 0.35s ease-out both;
}
.m-chart-bar-neg { transform-origin: top; }
@keyframes m-chart-bar-in {
  from { transform: scaleY(0.2); opacity: 0; }
  to { transform: scaleY(1); opacity: 1; }
}
.m-chart-line-path {
  stroke-dasharray: 900;
  stroke-dashoffset: 900;
  animation: m-chart-line-in 0.7s ease-out forwards;
}
@keyframes m-chart-line-in { to { stroke-dashoffset: 0; } }
@media (prefers-reduced-motion: reduce) {
  .m-chart-bar, .m-chart-line-path { animation: none; }
}
/* The dashed reference line at value=0, drawn only when a chart has at
   least one negative month -- lets a below-the-line bar/point read
   clearly as "negative" rather than just "shorter". */
.m-chart-zero-line {
  stroke: currentColor;
  stroke-opacity: 0.3;
  stroke-width: 1;
  stroke-dasharray: 3 3;
}
/* Only one of the two pre-rendered charts is shown at a time -- see
   templates/mobile/layout.html's toggle JS, which flips this attribute
   on the shared .m-trends-widgets wrapper rather than re-rendering
   anything, so switching is instant with no server round trip. */
.m-trends-widgets[data-chart-view="bar"] .m-chart-line-wrap { display: none; }
.m-trends-widgets[data-chart-view="line"] .m-chart-bar-wrap { display: none; }
.m-chart-tooltip {
  position: fixed;
  z-index: 45;
  max-width: 220px;
  background: var(--m-ink, #1f2937);
  color: #fff;
  font-size: 0.78rem;
  line-height: 1.45;
  white-space: pre-line;
  padding: 0.55rem 0.7rem;
  border-radius: 10px;
  box-shadow: 0 8px 20px -6px rgba(16, 24, 40, 0.35);
  pointer-events: none;
}
