:root {
  color-scheme: dark;
  font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  background: #170b0d;
  color: #f7f1ef;
}

* {
  box-sizing: border-box;
}

/* Safety net, not a fix for any specific element — a single unaccounted-for
   wide child anywhere in this large a codebase would otherwise force a
   horizontal scrollbar on the whole page, which is far more disruptive on a
   phone (where it also fights the browser's own edge-swipe gestures) than
   on desktop. */
html {
  overflow-x: hidden;
}

body {
  margin: 0;
  min-height: 100vh;
  background: radial-gradient(circle at top, #4a1120 0%, #170b0d 55%, #0a0505 100%);
  /* Without this, the gradient scales to the body's full scrollable height
     rather than the viewport — a collapsed page (shorter) reaches its dark
     55%/100% stops much sooner than an expanded page (taller), so the same
     viewport-height view looks darker with everything collapsed and lighter
     with a card open. Fixed attachment sizes/positions the gradient against
     the viewport instead, so it looks identical regardless of page length. */
  background-attachment: fixed;
  /* Belt-and-suspenders alongside html's own overflow-x:hidden above — some
     mobile browsers treat <body>, not <html>, as the actual scrolling
     element, so both need it set for horizontal scroll to be reliably
     blocked rather than just usually blocked. */
  overflow-x: hidden;
}

button,
input,
select {
  font: inherit;
}

button {
  transition: transform 0.15s ease;
}

/* Keeps a label readable to screen readers/form autofill without taking up
   visual space next to a control whose own value already reads as a label
   (e.g. the Period pill showing "This week" needs no "Period:" caption). */
.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;
}

button:hover:not(:disabled) {
  transform: scale(1.05);
}

button:active:not(:disabled) {
  transform: scale(0.97);
}

.app-shell {
  /* Scales past 1200px on wider viewports instead of staying pinned to a
     fixed width — otherwise a big monitor just shows the same layout
     surrounded by empty margins, which reads as everything being cramped
     into a small box in the middle of the screen. 96vw (rather than
     stopping short) means only a thin, consistent margin is ever left
     unused; the 2400px ceiling is just a safety net for the accounts
     panel's stat-cards/position rows on 5K+ displays, not a target width
     — most screens never get near it. The middle (accounts) column is
     the grid's 1fr track, so all of this extra width lands there rather
     than stretching the fixed-ish form/news panels. */
  max-width: clamp(1200px, 96vw, 2400px);
  margin: 0 auto;
  padding: 32px 20px 48px;
}

.hero {
  display: flex;
  justify-content: space-between;
  gap: 24px;
  align-items: center;
  margin-bottom: 24px;
  padding: 28px;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 24px;
  background: rgba(23, 11, 13, 0.78);
  backdrop-filter: blur(16px);
  /* backdrop-filter makes .hero its own stacking context, which traps the
     currency dropdown's z-index inside it — with no z-index of its own,
     .hero (and everything in it, dropdown included) paints *before*
     .content-grid in plain DOM order, so the panels below render on top
     of the menu wherever it overflows past the hero card's bottom edge.
     Raising .hero itself above that layer is what actually fixes it. */
  position: relative;
  z-index: 1;
}

.logo {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 16px;
}

.logo-icon {
  flex-shrink: 0;
}

.logo-text {
  font-size: 1.3rem;
  font-weight: 800;
  letter-spacing: 0.01em;
  color: #f7f1ef;
}

.eyebrow {
  margin: 0 0 8px;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  font-size: 0.8rem;
  color: #fbbf24;
}

h1,
h2,
p {
  margin-top: 0;
}

.hero h1 {
  font-size: clamp(1.8rem, 2.4vw, 2.8rem);
  max-width: 630px;
  margin-bottom: 10px;
}

.hero-copy {
  max-width: 600px;
  color: #c2a3a8;
  margin-bottom: 0;
}

.hero-card {
  min-width: 250px;
  padding: 20px;
  border-radius: 18px;
  background: linear-gradient(135deg, #9f1239, #b45309);
  box-shadow: 0 20px 40px rgba(180, 83, 9, 0.25);
}

.hero-card p {
  margin-bottom: 6px;
  color: rgba(255, 255, 255, 0.83);
}

.hero-card strong {
  display: block;
  font-size: 2rem;
  margin-bottom: 6px;
}

.hero-card-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.hero-card-top p {
  margin-bottom: 0;
}

.hero-card-top-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

.privacy-toggle-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  flex-shrink: 0;
  background: rgba(0, 0, 0, 0.2);
  color: #f7f1ef;
  border: 1px solid rgba(255, 255, 255, 0.25);
  border-radius: 8px;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease;
}

.privacy-toggle-btn:hover {
  background: rgba(0, 0, 0, 0.32);
  border-color: rgba(255, 255, 255, 0.4);
}

.privacy-toggle-btn .privacy-eye-off-icon {
  display: none;
}

.privacy-toggle-btn[aria-pressed="true"] .privacy-eye-icon {
  display: none;
}

.privacy-toggle-btn[aria-pressed="true"] .privacy-eye-off-icon {
  display: block;
}

.currency-dropdown {
  position: relative;
}

.currency-dropdown-btn {
  display: flex;
  align-items: center;
  gap: 7px;
  background: rgba(0, 0, 0, 0.2);
  color: #f7f1ef;
  border: 1px solid rgba(255, 255, 255, 0.25);
  border-radius: 8px;
  padding: 5px 10px;
  font-size: 0.8rem;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease;
}

.currency-dropdown-btn:hover {
  background: rgba(0, 0, 0, 0.32);
  border-color: rgba(255, 255, 255, 0.4);
}

.dropdown-chevron {
  flex-shrink: 0;
  transition: transform 0.2s ease;
}

.currency-dropdown.open .dropdown-chevron {
  transform: rotate(180deg);
}

.currency-dropdown-menu {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 30;
  min-width: 140px;
  margin: 0;
  padding: 6px;
  list-style: none;
  background: #1c0f12;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 12px;
  box-shadow: 0 16px 36px rgba(0, 0, 0, 0.4);

  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px) scale(0.97);
  transform-origin: top right;
  transition: opacity 0.16s ease, transform 0.16s ease, visibility 0s linear 0.16s;
}

.currency-dropdown.open .currency-dropdown-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
  transition: opacity 0.16s ease, transform 0.16s ease;
}

.currency-dropdown-menu li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 7px 10px;
  border-radius: 7px;
  color: #d9bcc0;
  font-size: 0.85rem;
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease;
}

.currency-dropdown-menu li:hover {
  background: rgba(217, 119, 6, 0.16);
  color: #fbbf24;
}

.currency-dropdown-menu li.selected {
  background: rgba(52, 211, 153, 0.14);
  color: #34d399;
  font-weight: 600;
}

.currency-dropdown-menu .currency-symbol {
  color: #a8888d;
}

.currency-dropdown-menu li:hover .currency-symbol,
.currency-dropdown-menu li.selected .currency-symbol {
  color: inherit;
}

.user-badge {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-top: 14px;
  color: #c2a3a8;
  font-size: 0.9rem;
}

.user-badge strong {
  color: #f7f1ef;
}

.content-grid {
  display: grid;
  /* First and third tracks are custom properties so the form and news
     panels are both independently draggable (see the two
     .panel-resize-handle elements and their pointer handlers in app.js)
     — the middle (accounts) column is minmax(280px, 1fr), so it's always
     whatever's left over, growing or shrinking as either side is dragged.
     Wrapping all three in minmax(..., value) — rather than the bare
     fixed-px/1fr tracks this used to be — means the row's total can never
     exceed the grid's own width: if app.js's clamping ever left a track
     wider than there's actually room for (e.g. right after the app-shell
     itself got narrower), the browser shrinks tracks to fit instead of
     overflowing the news panel past the hero card's right edge above it,
     which is what actually keeps both flush and the page symmetric. */
  grid-template-columns:
    minmax(0, var(--form-panel-width, 340px))
    minmax(280px, 1fr)
    minmax(0, var(--news-panel-width, 360px));
  gap: 24px;
  /* "start" rather than "stretch": the accounts panel's own natural height
     is the reference other panels get matched to (see syncPortfolioPanelHeights
     in app.js) — with "stretch" a grid row sizes to the tallest column and
     then stretches every column to that, which would drag the accounts
     panel's own height along with whatever height gets set on its siblings
     instead of leaving it as the fixed reference. */
  align-items: start;
}

/* The expenses page only ever has two panels (the add-expense form and the
   spending overview) — with the shared 3-column template above, the third
   (360px) track meant for a news-style side panel just sits empty next to
   the overview instead of being used by it. Redefine it as a plain
   form + fill-the-rest layout so "Spending overview" actually gets that
   reclaimed width instead of stopping short in the middle column.
   Scoped to the same min-width as the mobile breakpoint below collapses
   at, so this id-scoped rule doesn't outrank that single-column override
   on narrow screens by specificity. */
@media (min-width: 901px) {
  #page-expenses .content-grid {
    grid-template-columns: 340px 1fr;
  }
}

/* The Budget page is the same two-panel shape as Expenses (a form, and a
   results readout) so it reuses the same column split — but unlike
   Expenses/Portfolio there's nothing else on this page below the panels, so
   leaving .content-grid's inherited align-items: start would size both
   panels to their own short content and strand a tall block of empty space
   underneath on anything but a very short viewport. Stretching them to a
   viewport-relative min-height instead makes the two boxes actually fill
   the tab. The 260px subtracted is the nav row + page padding above them
   (see .app-shell's own padding/.app-nav's margin-bottom) — not pixel-exact
   on every viewport, just enough that the panels read as filling the
   screen rather than floating in the middle of it. */
@media (min-width: 901px) {
  #page-budget .content-grid {
    grid-template-columns: 340px 1fr;
    align-items: stretch;
    min-height: calc(100vh - 260px);
  }

  #page-budget .panel {
    height: 100%;
  }
}

.panel {
  padding: 22px;
  border-radius: 22px;
  background: rgba(24, 12, 14, 0.88);
  border: 1px solid rgba(255, 255, 255, 0.08);
}

/* Lets the grid track (see .content-grid's minmax(0, ...) tracks) actually
   shrink this panel below its content's natural width instead of the
   "Add account" form's labels/button forcing it wider — same reasoning as
   .news-panel's own min-width: 0. */
.form-panel {
  min-width: 0;
}

.account-form {
  display: grid;
  gap: 14px;
}

.account-form label {
  display: grid;
  gap: 6px;
  color: #e8d5d8;
  font-size: 0.95rem;
  /* Same min-width:auto default-sizing issue as .custom-select-label above
     (this is a grid item of .account-form rather than a flex item, but the
     same rule applies to grid items too) — without this, a label wrapping
     a custom-select whose content doesn't truncate cleanly can force this
     entire grid row, and everything up the ancestor chain, wider than the
     viewport. Confirmed via headless-browser check that fixing
     .custom-select-label's own flex-level version of this bug alone
     wasn't enough; both levels were needed. */
  min-width: 0;
}

.account-form input,
.account-form select,
.account-form textarea {
  border: 1px solid rgba(255, 255, 255, 0.12);
  padding: 10px 12px;
  border-radius: 12px;
  background: #241318;
  color: #f7f1ef;
}

.account-form textarea {
  font-family: inherit;
  resize: vertical;
}

/* ── Custom select ─────────────────────────────────────────────── */
/* Every <select> in the app (account type, expense category/period, the
   inline account-edit type picker) is enhanced into this at runtime — same
   floating-listbox look as the currency switcher above the total, instead of
   the browser's native <select> popup. See enhanceSelect() in app.js. */

.custom-select {
  position: relative;
  /* Third and final level of the same min-width:auto default-sizing chain
     as .account-form label and .custom-select-label above — this is the
     direct grid-item wrapper around the oversized button, and without
     this override it was still the actual remaining bottleneck even after
     fixing the other two levels (confirmed via headless-browser re-check). */
  min-width: 0;
}

/* Doubled up as ".account-form .custom-select-btn" too — three of the four
   custom selects (account type, expense category, inline account-edit type)
   sit inside a ".account-form" container, and the plain ".account-form
   button" rule (class + element = higher specificity than one class alone)
   would otherwise win and repaint this as the gradient pill submit-button
   style instead of a flat select-like box. */
.custom-select-btn,
.account-form .custom-select-btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  width: 100%;
  border: 1px solid rgba(255, 255, 255, 0.12);
  padding: 10px 12px;
  border-radius: 12px;
  background: #241318;
  color: #f7f1ef;
  text-align: left;
  font-weight: 400;
  cursor: pointer;
}

.custom-select-btn:hover,
.account-form .custom-select-btn:hover {
  border-color: rgba(255, 255, 255, 0.25);
}

.custom-select-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  /* The classic flexbox truncation gotcha: as a flex item (child of
     .custom-select-btn's display:flex) this defaults to min-width:auto,
     i.e. its full untruncated text width as a hard floor — the ellipsis
     above never actually gets a chance to apply, and everything up the
     ancestor chain gets dragged wider to fit instead. Confirmed live via
     a headless-browser check at phone width: this was the actual cause
     of horizontal page scroll on the Settings page specifically (the one
     panel with no ancestor already forcing a min-width:0 to contain it),
     though the same underlying bug affects every select enhanced by
     enhanceSelect() in app.js, not just that page. */
  min-width: 0;
}

.custom-select.open .dropdown-chevron {
  transform: rotate(180deg);
}

.custom-select-menu {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  right: 0;
  z-index: 30;
  margin: 0;
  padding: 6px;
  list-style: none;
  background: #1c0f12;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 12px;
  box-shadow: 0 16px 36px rgba(0, 0, 0, 0.4);
  max-height: 280px;
  overflow-y: auto;

  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px) scale(0.98);
  transform-origin: top;
  transition: opacity 0.16s ease, transform 0.16s ease, visibility 0s linear 0.16s;
}

.custom-select.open .custom-select-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
  transition: opacity 0.16s ease, transform 0.16s ease;
}

.custom-select-menu li {
  padding: 8px 10px;
  border-radius: 7px;
  color: #d9bcc0;
  font-size: 0.92rem;
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease;
}

.custom-select-menu li:hover {
  background: rgba(217, 119, 6, 0.16);
  color: #fbbf24;
}

.custom-select-menu li.selected {
  background: rgba(52, 211, 153, 0.14);
  color: #34d399;
  font-weight: 600;
}

.account-form button {
  border: 0;
  border-radius: 999px;
  padding: 12px 16px;
  background: linear-gradient(135deg, #be123c, #d97706);
  color: white;
  cursor: pointer;
  font-weight: 600;
}

/* Same .account-form button {...} specificity fight as .expense-type-btn
   above — without this, the auth gate's "Restore from a backup file
   instead" link (inside .account-form) would repaint as an orange gradient
   pill instead of the plain text link it's meant to be. */
.account-form .link-btn {
  border: 0;
  background: transparent;
  color: #fbbf24;
  padding: 0;
  font-weight: 400;
  text-decoration: underline;
}

.section-heading {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  /* A guaranteed minimum, on top of whatever justify-content: space-between
     distributes — without it, a heading with wide-enough sibling content
     (e.g. Entries' subtitle + sort control) could shrink until there's no
     free space left to distribute, leaving the heading text touching it
     with zero gap. flex-wrap is the fallback for when even that isn't
     enough room: the sibling drops to its own line below instead of
     forcing an even tighter squeeze. */
  gap: 8px 16px;
  flex-wrap: wrap;
  margin-bottom: 18px;
}

.section-heading p {
  color: #a8888d;
  margin: 0;
}

/* position: relative anchors the form-side .panel-resize-handle, which
   sits just outside this panel's left edge, straddling the gap to the
   "Add account" form next to it. min-width: 0 lets the grid track (see
   .content-grid's minmax(280px, 1fr) middle column) be the actual
   authority on this panel's floor, rather than its content's natural
   width silently overriding it. */
#accounts-panel {
  position: relative;
  min-width: 0;
}

.accounts-list {
  display: grid;
  gap: 14px;
}

.account-card {
  border: 1px solid rgba(255, 255, 255, 0.09);
  border-radius: 18px;
  padding: 16px;
  background: #1c0f12;
  /* Without this, a grid item's default min-width is its content's
     min-content size — with the header's nowrap value text, that could
     exceed the accounts panel's actual (squeezed) width, and the card
     would overflow .accounts-list rather than shrink, visually bleeding
     out past the panel's border into the news panel next to it. */
  min-width: 0;
}

.account-card-edit {
  border-color: rgba(251, 191, 36, 0.35);
}

.account-edit-actions {
  display: flex;
  gap: 10px;
  margin-top: 4px;
}

.account-edit-actions button {
  width: auto;
}

.cancel-account-edit-btn {
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.15);
  color: #c2a3a8;
}

.account-card-header {
  display: flex;
  align-items: center;
  /* Once the name (see .account-card-title's min-width below) can't fit
     next to the value/chevron anymore, this drops the value/chevron to
     their own line below instead of continuing to squeeze the name into
     an ever-narrower column — which is what actually keeps a wrapped
     name readable across 2-3 lines instead of one word per line. */
  flex-wrap: wrap;
  margin-bottom: 10px;
  cursor: pointer;
  border-radius: 10px;
}

.account-card-header:hover {
  background: rgba(255, 255, 255, 0.03);
}

.drag-handle {
  flex-shrink: 0;
  cursor: grab;
  color: #a8888d;
  font-size: 1rem;
  line-height: 1;
  padding: 2px 4px;
  margin-right: 2px;
  user-select: none;
  touch-action: none;
}

.drag-handle:active {
  cursor: grabbing;
}

.account-card.dragging {
  position: fixed;
  margin: 0;
  top: 0;
  left: 0;
  z-index: 1000;
  cursor: grabbing;
  box-shadow: 0 20px 45px rgba(0, 0, 0, 0.45);
  transform-origin: center;
  pointer-events: none;
  will-change: transform;
}

.account-card-placeholder {
  border: 2px dashed rgba(251, 191, 36, 0.35);
  border-radius: 18px;
  background: rgba(251, 191, 36, 0.06);
}

body.dragging-active {
  cursor: grabbing;
  user-select: none;
}

.account-card-header-right {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-left: auto;
  margin-right: 10px;
  /* Without this, flex's default shrink distribution weighs by each
     item's own natural (unwrapped) width — a long wrapped account name
     is huge unwrapped, so it would take on almost none of the actual
     shrinking and this column would get squeezed instead, landing the
     value/chevron visually inside the wrapped title. See
     .account-card-title's flex-grow, which is the other half of this. */
  flex-shrink: 0;
}

.chevron {
  display: inline-block;
  color: #a8888d;
  transition: transform 0.2s ease;
}

.chevron.open {
  transform: rotate(180deg);
}

.account-card h3 {
  margin: 0 0 4px;
}

.account-card .meta {
  color: #a8888d;
  font-size: 0.95rem;
  word-break: break-all;
}

.headline-sub {
  margin-left: 10px;
  font-size: 0.95rem;
  font-weight: 600;
}

/* Always present in the DOM (open or closed) so toggling is a class flip on
   an existing element instead of inserting/removing nodes — a transition
   needs a "before" state to animate from, which a freshly-inserted element
   doesn't have. grid-template-rows 0fr→1fr animates to the content's natural
   height without JS measuring it. */
.account-detail-wrap {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 360ms cubic-bezier(0.4, 0, 0.2, 1);
}

.account-detail-wrap.open {
  grid-template-rows: 1fr;
}

.account-detail {
  margin-top: 14px;
  overflow: hidden;
  min-height: 0;
}

.wallet-addresses {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 16px;
}

.wallet-address {
  font-family: "SFMono-Regular", Consolas, monospace;
  font-size: 0.78rem;
  color: #c2a3a8;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 999px;
  padding: 4px 12px;
}

.account-card-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 12px;
}

.badge {
  display: inline-block;
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 0.8rem;
  background: rgba(217, 119, 6, 0.16);
  color: #fbbf24;
  text-transform: capitalize;
}

.account-card-title {
  /* flex-basis: 140px is a floor on how narrow the name's own wrapping
     column is allowed to get before .account-card-header's flex-wrap
     kicks in and drops the value/chevron to their own line — below that,
     shrinking further would force near-single-word lines instead of the
     2-3 comfortable ones a wrapped name is meant to read as. min-width
     matches it for the same reason (flex-basis alone doesn't stop this
     shrinking past it once wrapping isn't an option, e.g. mid-drag). */
  flex: 1 1 140px;
  min-width: 140px;
}

/* Wraps onto a second/third line instead of eliding — unlike the .meta
   line below it, the account's own name is the one thing in this row we
   don't want cut short, so a squeezed accounts panel grows the card
   taller here rather than hiding part of the name. */
.account-card-title h3 {
  overflow-wrap: break-word;
}

/* Overrides .account-card .meta's word-break: break-all (meant for long
   wallet addresses elsewhere) for this specific spot: this meta line sits
   in the same flex row as account-card-value, so at a squeezed accounts
   panel width, letting it wrap instead of truncate pushed the row taller
   and the vertically-centered value ended up sitting mid-way through the
   wrapped text instead of beside a single line. */
.account-card-title .meta {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.account-card-value {
  font-size: 1.1rem;
  font-weight: 700;
  white-space: nowrap;
}

.positions-list {
  display: grid;
  gap: 8px;
  padding-left: 0;
  list-style: none;
  margin: 10px 0 0;
}

.positions-list li {
  display: flex;
  justify-content: space-between;
  color: #d9bcc0;
  font-size: 0.95rem;
}

/* ── Linked expenses (account card detail) ─────────────────────── */

.linked-expenses {
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.linked-expenses-heading {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
}

.linked-expenses-heading h4 {
  margin: 0;
  font-size: 0.95rem;
  color: #e8d5d8;
}

.linked-expenses-list {
  display: grid;
  gap: 8px;
  padding-left: 0;
  list-style: none;
  margin: 0;
}

.linked-expense-row {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 0.88rem;
}

.linked-expense-desc {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: #f7f1ef;
}

.linked-expense-amount {
  font-weight: 600;
  white-space: nowrap;
}

.remove-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  background: transparent;
  color: #8b2635;
  cursor: pointer;
  line-height: 1;
  padding: 3px 4px;
  border-radius: 6px;
  transition: color 0.15s ease, background 0.15s ease;
}

.remove-btn:hover {
  color: #fb7185;
  background: rgba(251, 113, 133, 0.14);
}

.account-card-footer-actions {
  display: flex;
  align-items: center;
  gap: 14px;
}

.edit-btn {
  display: inline-flex;
  align-items: center;
  border: 0;
  background: transparent;
  color: #a8888d;
  cursor: pointer;
  line-height: 1;
  padding: 3px 4px;
  border-radius: 6px;
  transition: color 0.15s ease, background 0.15s ease;
}

.edit-btn:hover {
  color: #fbbf24;
  background: rgba(251, 191, 36, 0.14);
}

/* ── Avanza section ────────────────────────────────────────────── */

.panel-divider {
  border: 0;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  margin: 22px 0;
}

.avanza-note {
  color: #a8888d;
  font-size: 0.88rem;
  margin-bottom: 14px;
}

.avanza-btn {
  display: block;
  width: 100%;
  border: 0;
  border-radius: 999px;
  padding: 12px 16px;
  background: linear-gradient(135deg, #be123c, #d97706);
  color: white;
  cursor: pointer;
  font: inherit;
  font-weight: 600;
  margin-top: 8px;
}

/* .avanza-btn is written for <button>s (text is centered, never underlined,
   by default) — the "Open BankID app" link is an <a> instead (so tapping it
   is a plain navigation the OS can hand off to the BankID app), which needs
   both set explicitly. */
#avanza-bankid-open-app-btn {
  text-align: center;
  text-decoration: none;
  box-sizing: border-box;
}

.avanza-btn-secondary {
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.15);
  color: #c2a3a8;
  margin-top: 6px;
}

.avanza-btn:disabled {
  opacity: 0.55;
  cursor: default;
}

.avanza-waiting-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: 16px 0;
  text-align: center;
  color: #c2a3a8;
}

.spinner {
  width: 36px;
  height: 36px;
  border: 3px solid rgba(255, 255, 255, 0.1);
  border-top-color: #d97706;
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

/* Thin indeterminate progress bar pinned to the top of the viewport —
   shown for the duration of any in-flight request (see beginLoading/
   endLoading in app.js), so there's always a visible sign something is
   loading, even for actions that don't have their own inline spinner. */
.global-loading-bar {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 3px;
  z-index: 9999;
  pointer-events: none;
  opacity: 0;
  overflow: hidden;
  transition: opacity 0.15s ease;
}

.global-loading-bar.active {
  opacity: 1;
}

.global-loading-bar::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  width: 40%;
  background: linear-gradient(90deg, transparent, #34d399, #d97706, transparent);
  animation: global-loading-slide 1.1s ease-in-out infinite;
}

@keyframes global-loading-slide {
  0%   { left: -40%; }
  100% { left: 100%; }
}

.avanza-connected-header {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 8px;
}

.connected-badge {
  background: rgba(52, 211, 153, 0.16);
  color: #34d399;
}

/* ── Statistics section ────────────────────────────────────────── */

.stats-cards {
  display: grid;
  /* auto-flow: column (instead of auto-fit's wrapping row-grid) keeps every
     card on one row. Columns have no min-width floor (minmax(0, 1fr)) so
     they shrink to divide whatever panel width is available instead of
     ever forcing the row to scroll horizontally — the card padding/font
     sizes below are tuned to still read fine once compressed. */
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  gap: 10px;
  margin-bottom: 28px;
}

.stat-card {
  background: #1c0f12;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 16px;
  padding: 12px 10px;
  /* Grid items default to a min-width of their content's intrinsic size,
     which would push the row wider than the panel and defeat the shrink
     above — this lets the card (and its text, via the ellipsis rules
     below) actually shrink below that. */
  min-width: 0;
}

.stat-label {
  font-size: 0.72rem;
  color: #a8888d;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-bottom: 6px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.stat-value {
  font-size: 1.05rem;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.gain { color: #34d399; }
.loss { color: #fb7185; }

.positions-rows {
  display: grid;
  gap: 10px;
  font-size: 0.93rem;
}

.position-row {
  padding: 12px 14px;
  border-radius: 12px;
  background: #1c0f12;
  border: 1px solid rgba(255, 255, 255, 0.05);
}

.position-row:hover {
  background: rgba(255, 255, 255, 0.025);
}

.position-row-editing {
  border-color: rgba(251, 191, 36, 0.35);
}

.position-row-editing:hover {
  background: #1c0f12;
}

.position-row-main {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

.position-value {
  font-weight: 700;
  color: #f7f1ef;
  white-space: nowrap;
  /* Never the side that gives way in a flex row next to a truncating
     title (e.g. .avanza-account-title) — the number staying intact
     matters more than the name next to it. */
  flex-shrink: 0;
}

.position-row-main-right {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
}

.position-hide-btn {
  border: 0;
  background: transparent;
  color: #a8888d;
  cursor: pointer;
  font-size: 1.1rem;
  line-height: 1;
  padding: 2px 4px;
  border-radius: 6px;
  opacity: 0;
  transition: opacity 0.15s ease, color 0.15s ease, background 0.15s ease;
}

.position-row:hover .position-hide-btn {
  opacity: 1;
}

.position-hide-btn:hover {
  color: #fb7185;
  background: rgba(251, 113, 133, 0.14);
}

.position-delete-btn {
  display: inline-flex;
  align-items: center;
  border: 0;
  background: transparent;
  color: #a8888d;
  cursor: pointer;
  line-height: 1;
  padding: 3px 4px;
  border-radius: 6px;
  opacity: 0;
  transition: opacity 0.15s ease, color 0.15s ease, background 0.15s ease;
}

.position-row:hover .position-delete-btn {
  opacity: 1;
}

.position-delete-btn:hover {
  color: #fb7185;
  background: rgba(251, 113, 133, 0.16);
}

.position-edit-btn {
  display: inline-flex;
  align-items: center;
  border: 0;
  background: transparent;
  color: #a8888d;
  cursor: pointer;
  line-height: 1;
  padding: 3px 4px;
  border-radius: 6px;
  opacity: 0;
  transition: opacity 0.15s ease, color 0.15s ease, background 0.15s ease;
}

.position-row:hover .position-edit-btn {
  opacity: 1;
}

.position-edit-btn:hover {
  color: #fbbf24;
  background: rgba(251, 191, 36, 0.14);
}

.save-crypto-edit-btn,
.cancel-crypto-edit-btn {
  display: inline-flex;
  align-items: center;
  border: 0;
  background: transparent;
  cursor: pointer;
  line-height: 1;
  padding: 3px 4px;
  border-radius: 6px;
}

.save-crypto-edit-btn {
  color: #34d399;
}

.save-crypto-edit-btn:hover {
  background: rgba(52, 211, 153, 0.14);
}

.cancel-crypto-edit-btn {
  color: #a8888d;
}

.cancel-crypto-edit-btn:hover {
  color: #fb7185;
  background: rgba(251, 113, 133, 0.14);
}

.asset-name-edit {
  display: flex;
  gap: 6px;
  flex: 1;
  min-width: 160px;
}

.asset-name-edit input {
  border: 1px solid rgba(255, 255, 255, 0.12);
  padding: 5px 8px;
  border-radius: 8px;
  background: #241318;
  color: #f7f1ef;
  font-size: 0.9rem;
}

.asset-name-edit .edit-field-symbol {
  width: 76px;
  text-transform: uppercase;
}

.asset-name-edit .edit-field-name {
  flex: 1;
  min-width: 100px;
}

.position-row-details input,
.edit-field-date-trigger {
  border: 1px solid rgba(255, 255, 255, 0.12);
  padding: 5px 8px;
  border-radius: 8px;
  background: #241318;
  color: #f7f1ef;
  font-size: 0.9rem;
  width: 100%;
  min-width: 110px;
  color-scheme: dark;
}

.edit-field-date-trigger {
  display: flex;
  align-items: center;
  gap: 6px;
  text-align: left;
  cursor: pointer;
  font: inherit;
}

.edit-field-date-trigger svg {
  flex-shrink: 0;
  color: #c2a3a8;
}

.edit-field-date-trigger:hover {
  border-color: rgba(251, 191, 36, 0.4);
}

.edit-field-date-trigger:hover svg {
  color: #fbbf24;
}

/* .account-form button {...} above is a generic rule (any <button> in a
   .account-form) that outranks .edit-field-date-trigger's own styling on
   every property they both set (border/padding/border-radius/background/
   color/font-weight) — the date trigger used inside the Everyday Expenses
   form would otherwise render as an orange pill button instead of the same
   dark calendar-trigger field used for a crypto position's date. Scoping
   the class to .account-form here raises its specificity just enough to
   win those properties back. */
.account-form .edit-field-date-trigger {
  border: 1px solid rgba(255, 255, 255, 0.12);
  padding: 5px 8px;
  border-radius: 8px;
  background: #241318;
  color: #f7f1ef;
  font-weight: 400;
}

.date-picker-popup {
  position: absolute;
  z-index: 1200;
  width: 240px;
  padding: 12px;
  border-radius: 14px;
  background: #241318;
  border: 1px solid rgba(255, 255, 255, 0.12);
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.5);
}

.date-picker-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
}

.date-picker-title {
  display: flex;
  align-items: center;
  gap: 4px;
  font-weight: 600;
  font-size: 0.9rem;
}

.date-picker-title-btn {
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  cursor: pointer;
  padding: 2px 4px;
  border-radius: 6px;
}

.date-picker-title-btn:hover {
  background: rgba(255, 255, 255, 0.08);
}

.date-picker-nav {
  border: 0;
  background: transparent;
  color: #a8888d;
  cursor: pointer;
  font-size: 1.1rem;
  line-height: 1;
  padding: 4px 8px;
  border-radius: 6px;
}

.date-picker-nav:hover {
  color: #f7f1ef;
  background: rgba(255, 255, 255, 0.06);
}

.date-picker-weekdays {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2px;
  margin-bottom: 4px;
  color: #a8888d;
  font-size: 0.72rem;
  text-align: center;
}

.date-picker-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2px;
}

.date-picker-day {
  border: 0;
  background: transparent;
  color: #f7f1ef;
  cursor: pointer;
  padding: 6px 0;
  border-radius: 8px;
  font-size: 0.85rem;
  text-align: center;
}

.date-picker-day:hover:not([disabled]) {
  background: rgba(255, 255, 255, 0.08);
}

.date-picker-day.today {
  color: #fbbf24;
}

.date-picker-day.selected {
  background: linear-gradient(135deg, #be123c, #d97706);
  color: white;
}

.date-picker-day[disabled] {
  color: #5c4448;
  cursor: not-allowed;
}

.date-picker-day-empty {
  cursor: default;
}

.date-picker-cell-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
}

.date-picker-cell {
  border: 0;
  background: transparent;
  color: #f7f1ef;
  cursor: pointer;
  padding: 10px 0;
  border-radius: 8px;
  font-size: 0.85rem;
  text-align: center;
}

.date-picker-cell:hover {
  background: rgba(255, 255, 255, 0.08);
}

.date-picker-cell.selected {
  background: linear-gradient(135deg, #be123c, #d97706);
  color: white;
}

.date-picker-clear {
  width: 100%;
  margin-top: 8px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: transparent;
  color: #c2a3a8;
  cursor: pointer;
  padding: 6px;
  border-radius: 8px;
  font-size: 0.82rem;
}

.date-picker-clear:hover {
  border-color: rgba(251, 113, 133, 0.4);
  color: #fb7185;
}

.link-btn {
  border: 0;
  background: transparent;
  color: #fbbf24;
  cursor: pointer;
  font: inherit;
  padding: 0;
  text-decoration: underline;
}

.position-row-details {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 20px;
  margin-top: 10px;
}

.detail-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 88px;
}

.detail-item-full {
  flex: 1 1 100%;
}

.detail-label {
  font-size: 0.72rem;
  color: #a8888d;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.asset-name {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  color: #f7f1ef !important;
}

/* ── Coin / asset icons ────────────────────────────────────────── */

.asset-icon {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  flex-shrink: 0;
  border-radius: 50%;
  overflow: hidden;
  background: var(--asset-icon-color, #a8888d);
}

.asset-icon-fallback {
  font-size: 0.68rem;
  font-weight: 700;
  color: white;
  line-height: 1;
}

.asset-icon img {
  /* Most CoinCap icon PNGs carry their own ~20% transparent margin around the
     mark itself, so sizing the image to exactly fill the circle still leaves
     that built-in padding visible inside it. Oversizing the image and
     letting the circle's overflow:hidden crop the excess pushes the actual
     logo edge-to-edge instead. */
  position: absolute;
  top: 50%;
  left: 50%;
  width: 145%;
  height: 145%;
  transform: translate(-50%, -50%);
  object-fit: cover;
}

.account-card-title-main {
  display: flex;
  /* flex-start rather than center: once the name wraps to 2-3 lines (see
     .account-card-title h3), centering would float the icon down toward
     the middle of the wrapped block instead of sitting beside its first
     line. */
  align-items: flex-start;
  gap: 8px;
  min-width: 0;
}

.account-card-title-main h3 {
  min-width: 0;
}

.account-type-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  flex-shrink: 0;
  border-radius: 50%;
  background: color-mix(in srgb, var(--asset-icon-color, #a8888d) 20%, transparent);
  color: var(--asset-icon-color, #a8888d);
}

.manual-badge {
  display: inline-block;
  margin-left: 8px;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: none;
  background: rgba(96, 165, 250, 0.16);
  color: #60a5fa;
  vertical-align: middle;
}

/* ── Avanza account sub-sections (inside the single combined Avanza card) ── */

.avanza-account-section-header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 14px;
}

.avanza-account-section-header h4 {
  margin: 0 0 2px;
}

/* Same shrink-to-fit-then-truncate treatment as .account-card-title: this
   sits in a flex row next to .position-value (nowrap, see below), so
   without it a long account name/type at a squeezed accounts-panel width
   would wrap instead of eliding and collide with the pinned value. */
.avanza-account-title {
  min-width: 0;
}

.avanza-account-title h4,
.avanza-account-title .meta {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.realized-pnl-section {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px dashed rgba(255, 255, 255, 0.12);
}

.realized-pnl-section h5 {
  margin: 0 0 10px;
  font-size: 0.95rem;
}

/* ── Auth gate ──────────────────────────────────────────────────── */

/* The gate itself is a plain block container now — .auth-hero below is what
   actually centers the login/signup card full-screen, same as .auth-gate
   used to do on its own before the About/Compare sections were added below
   it. Splitting the two lets the card keep its exact original first-screen
   look while still allowing normal page flow (and scrolling) underneath. */
.auth-gate {
  min-height: 100vh;
}

.auth-hero {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 20px;
  position: relative;
  overflow: hidden;
}

/* Hidden entirely below the min-width:800px query further down — not
   just shrunk down — a phone really has no spare room next to a 380px
   login card (see the math in that query's comment); that's the
   "absolutely no space" case. Above 800px both sides scale continuously
   with viewport width (see the clamp()s below) rather than jumping
   between a couple of fixed sizes, which looked like a glitch at the
   point they jumped. On a wide screen the mockup is pinned to the real
   viewport edge (absolute against .auth-hero, not inset within a
   centered row) so it actually reaches toward the left border instead of
   floating with a wide gap around it. */
.auth-hero-side-left {
  display: none;
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  align-items: center;
  justify-content: flex-start;
}

/* Floor (160px) is the largest size that's still verified-safe at the
   800px reveal point below — see that query's comment — not an
   arbitrary round number. Scales up continuously to the 380px cap from
   there, reaching it around an 1900px-wide viewport. */
.auth-hero-mockup {
  display: block;
  width: clamp(160px, 20vw, 380px);
  height: auto;
  filter: drop-shadow(0 24px 60px rgba(0, 0, 0, 0.55));
}

/* Unlike the mockup, this stays visible at every width — stacked below
   the login card in normal document flow on phone/tablet, then pinned to
   the right edge the same way the mockup pins to the left once there's
   room for a 3-column hero (see the min-width:800px query below). */
.auth-hero-side-right {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  width: 100%;
  margin-top: 28px;
}

/* Same floor-matches-the-800px-safe-maximum logic as the mockup above,
   reaching its own (smaller) 290px cap around a 1450px-wide viewport. */
.auth-hero-tagline {
  width: clamp(160px, 20vw, 290px);
  max-width: 100%;
  text-align: center;
}

.auth-hero-tagline strong {
  display: block;
  font-size: 1.15rem;
  line-height: 1.35;
  margin-bottom: 6px;
}

.auth-hero-tagline span {
  display: block;
  color: #a8888d;
  font-size: 0.85rem;
  line-height: 1.5;
}

/* .auth-box (max-width:380px, centered via .auth-hero's own flex
   centering) is unaffected by either side at any width here. Verified
   numerically before shipping, not just eyeballed: at 800px — the
   tightest width any of this applies to, where the clamp()s above sit at
   their 160px floor and this query's own right:max(20px,3vw) is 24px —
   the box's own edges still sit 26px+ clear of both the image and the
   tagline, and that margin only grows from there (180px+ by 1300px,
   370px+ by 1920px) as the viewport widens and the box's relative share
   of it shrinks. */
@media (min-width: 800px) {
  .auth-hero-side-left {
    display: flex;
  }

  .auth-hero-side-right {
    position: absolute;
    top: 0;
    bottom: 0;
    right: max(20px, 3vw);
    justify-content: center;
    width: auto;
    margin-top: 0;
  }

  /* Shown from here up alongside the mockup it invites scrolling past —
     see the hidden-below-800px comment on .auth-scroll-cue itself. */
  .auth-scroll-cue {
    display: flex;
  }
}

.auth-box {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 380px;
  padding: 28px;
  border-radius: 22px;
  background: rgba(24, 12, 14, 0.92);
  border: 1px solid rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(16px);
}

.auth-box h1 {
  font-size: 1.5rem;
  margin-bottom: 6px;
}

.auth-sub {
  color: #a8888d;
  font-size: 0.9rem;
  margin-bottom: 20px;
}

.auth-error {
  color: #fb7185;
  font-size: 0.9rem;
  min-height: 1.2em;
  margin: 12px 0 0;
}

#auth-toggle-btn {
  display: block;
  margin-top: 14px;
}

/* ── Auth gate: scroll cue + marketing sections below the fold ──── */

/* Hidden below 800px entirely, same as the mockup image (see
   .auth-hero-side-left) — it was pinned absolute+bottom against
   .auth-hero regardless of how tall the stacked content above it was,
   which visibly overlapped the tagline once that became always-visible.
   Rather than reflowing it into the stack, it's simplest to just drop it
   alongside the image it was always meant to invite scrolling past. */
.auth-scroll-cue {
  display: none;
  position: absolute;
  bottom: 28px;
  left: 50%;
  transform: translateX(-50%);
  flex-direction: column;
  align-items: center;
  gap: 4px;
  color: #a8888d;
  font-size: 0.8rem;
  text-decoration: none;
  animation: auth-scroll-cue-bob 2.2s ease-in-out infinite;
}

.auth-scroll-cue:hover {
  color: #f7f1ef;
}

@keyframes auth-scroll-cue-bob {
  0%, 100% { transform: translateX(-50%) translateY(0); }
  50% { transform: translateX(-50%) translateY(6px); }
}

.auth-section {
  padding: 60px 20px;
}

.auth-section-inner {
  max-width: 880px;
  margin: 0 auto;
}

.auth-section-alt {
  background: rgba(0, 0, 0, 0.18);
}

.auth-section h2 {
  font-size: 1.7rem;
  margin: 0 0 14px;
  text-align: center;
}

.auth-section-lead {
  max-width: 620px;
  margin: 0 auto 36px;
  color: #d9bcc0;
  font-size: 1rem;
  line-height: 1.6;
  text-align: center;
}

.auth-feature-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 18px;
}

.auth-feature {
  display: flex;
  gap: 14px;
  padding: 18px;
  border-radius: 16px;
  background: rgba(23, 11, 13, 0.6);
  border: 1px solid rgba(255, 255, 255, 0.08);
}

.auth-feature svg {
  flex-shrink: 0;
  margin-top: 2px;
}

.auth-feature div {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.auth-feature strong {
  font-size: 0.95rem;
}

.auth-feature span {
  color: #a8888d;
  font-size: 0.85rem;
  line-height: 1.5;
}

.auth-compare-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
  align-items: start;
}

.auth-compare-card {
  padding: 24px;
  border-radius: 18px;
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.auth-compare-other {
  background: rgba(23, 11, 13, 0.6);
}

/* The accent card — same gradient-bordered "this one's the pick" treatment
   .expense-category-add-option/.app-nav-btn.active use elsewhere, just as a
   border+tint here instead of a filled background so five lines of text
   stay readable against it. */
.auth-compare-tradone {
  background: rgba(52, 211, 153, 0.07);
  border-color: rgba(52, 211, 153, 0.35);
}

.auth-compare-card h3 {
  margin: 0 0 16px;
  font-size: 1.05rem;
}

.auth-compare-tradone h3 {
  color: #34d399;
}

.auth-compare-card ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 12px;
}

.auth-compare-card li {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-size: 0.9rem;
  line-height: 1.5;
  color: #d9bcc0;
}

.auth-compare-icon {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  font-size: 0.75rem;
  line-height: 1;
  margin-top: 1px;
}

.auth-compare-icon-no {
  background: rgba(251, 113, 133, 0.14);
  color: #fb7185;
}

.auth-compare-icon-yes {
  background: rgba(52, 211, 153, 0.16);
  color: #34d399;
}

/* ── Pop-in reveal ─────────────────────────────────────────────── */
/* Applied by playPopInAnimation() in app.js — --pop-delay is set per
   element so the reveal sweeps from the page's upper-left toward its
   lower-right. */

@keyframes pop-in {
  0% {
    opacity: 0;
    transform: translate3d(-32px, -32px, 0) scale(0.86);
  }
  100% {
    opacity: 1;
    transform: translate3d(0, 0, 0) scale(1);
  }
}

.pop-in {
  animation: pop-in 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) both;
  animation-delay: var(--pop-delay, 0ms);
}

@media (prefers-reduced-motion: reduce) {
  .pop-in {
    animation: none;
  }

  .auth-scroll-cue {
    animation: none;
  }
}

.settings-panel {
  width: 100%;
}

.settings-panel .account-form {
  max-width: 420px;
}

/* ── Top navigation ────────────────────────────────────────────── */

.app-nav {
  display: flex;
  gap: 8px;
  margin-bottom: 24px;
}

.app-nav-btn {
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(23, 11, 13, 0.6);
  color: #c2a3a8;
  padding: 10px 20px;
  border-radius: 999px;
  cursor: pointer;
  font-weight: 600;
}

.app-nav-btn:hover:not(.active) {
  background: rgba(255, 255, 255, 0.06);
  color: #f7f1ef;
}

.app-nav-btn.active {
  background: linear-gradient(135deg, #be123c, #d97706);
  border-color: transparent;
  color: white;
}

/* ── Settings gear button ──────────────────────────────────────── */
/* Pinned to the page's top-right corner (viewport-relative, not just the
   nav row) so Settings stays reachable regardless of scroll position. */

.settings-gear-btn {
  position: fixed;
  top: 20px;
  right: 20px;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(23, 11, 13, 0.78);
  backdrop-filter: blur(16px);
  color: #c2a3a8;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease, transform 0.4s ease;
}

.settings-gear-btn:hover {
  color: #f7f1ef;
  border-color: rgba(255, 255, 255, 0.25);
}

.settings-gear-btn.active {
  background: linear-gradient(135deg, #be123c, #d97706);
  border-color: transparent;
  color: white;
  transform: rotate(90deg);
}

@media (max-width: 700px) {
  .settings-gear-btn {
    top: 12px;
    right: 12px;
    width: 36px;
    height: 36px;
  }

  .auth-feature-grid,
  .auth-compare-grid {
    grid-template-columns: 1fr;
  }

  .auth-section {
    padding: 44px 20px;
  }
}

/* ── Expenses ──────────────────────────────────────────────────── */

/* Grid, not flex, for the two buttons below — flex:1's flex-basis:0%
   distributes the row's width by proportion, which can round to a
   different pixel than the sibling inputs' own (grid-stretched, see
   .account-form label) width one column over. Grid's 1fr tracks are laid
   out by the same algorithm as those sibling grid cells, so this row's
   right edge lines up with theirs exactly instead of drifting by a
   stray pixel. */
.expense-type-toggle {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}

.expense-type-btn {
  min-width: 0;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: #241318;
  color: #c2a3a8;
  padding: 8px 10px;
  border-radius: 8px;
  font-weight: 600;
  font-size: 0.85rem;
  cursor: pointer;
}

/* These sit flush against the toggle row's edges with no spare margin, so
   the global button:hover/:active { transform: scale(...) } (see the * rule
   near the top of this file) pushes them visibly past the panel's rounded
   border on hover/tap instead of just growing in place — the active/color
   state already gives all the feedback this toggle needs. */
.expense-type-btn:hover:not(:disabled),
.expense-type-btn:active:not(:disabled) {
  transform: none;
}

/* Same .account-form button {...} specificity fight as .edit-field-date-
   trigger above — the generic rule outranks .expense-type-btn alone on
   every property they share, so the inactive button would otherwise render
   as an orange pill instead of the plain dark toggle it's meant to be. */
.account-form .expense-type-btn {
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: #241318;
  color: #c2a3a8;
  padding: 8px 10px;
  border-radius: 8px;
  font-weight: 600;
}

.expense-io-section {
  margin-top: 22px;
  padding-top: 22px;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.expense-io-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

/* .avanza-btn-secondary inherits .avanza-btn's display:block/width:100% (see
   above), which would stack these two full-width instead of side by side. */
.expense-io-actions .avanza-btn {
  width: auto;
  flex: 1;
  min-width: 140px;
  text-align: center;
}

.expense-import-review {
  margin-top: 16px;
  display: grid;
  gap: 10px;
}

.expense-import-review label {
  display: grid;
  gap: 6px;
  color: #e8d5d8;
  font-size: 0.95rem;
}

.expense-import-review-actions {
  display: flex;
  align-items: center;
  gap: 16px;
}

.expense-import-review-actions .avanza-btn {
  width: auto;
  flex: 1;
}

/* Category field's own dropdown popup (see setupExpenseCategorySelect in
   app.js) — a normal .custom-select-menu row plus a swatch and a remove (×)
   button per option, and a trailing "+ Add" row that swaps itself for a
   name input in place when clicked. */
.expense-category-option {
  display: flex;
  align-items: center;
  gap: 8px;
}

.expense-category-option-label {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.expense-category-remove-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  border: none;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.08);
  color: #c2a3a8;
  font-size: 0.85rem;
  line-height: 1;
  cursor: pointer;
}

.expense-category-remove-btn:hover {
  background: rgba(251, 113, 133, 0.25);
  color: #fb7185;
}

.expense-category-add-option {
  color: #fbbf24;
  font-weight: 600;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  margin-top: 4px;
  padding-top: 10px !important;
}

.expense-category-add-row-inline {
  display: flex;
  align-items: center;
  gap: 6px;
  cursor: default;
}

.expense-category-add-row-inline:hover {
  background: none !important;
}

.expense-category-add-row-inline .expense-category-name-input {
  flex: 1;
  min-width: 0;
  background: #241318;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 7px;
  padding: 6px 8px;
  color: #f7f1ef;
  font-size: 0.88rem;
}

/* Scoped under .expense-category-menu — see the identical note on
   .expense-category-confirm-edit-btn below — so this beats
   .account-form button's padding/background/color instead of losing to
   them on specificity, which was squeezing the checkmark icon's space down
   to nothing and leaving what looked like a plain, iconless circle. */
.expense-category-menu .expense-category-confirm-add-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: rgba(52, 211, 153, 0.16);
  color: #34d399;
  cursor: pointer;
}

.expense-category-menu .expense-category-confirm-add-btn:hover {
  background: rgba(52, 211, 153, 0.3);
}

/* Custom category rows expand into this in place of their normal row when
   clicked (see showEditCategoryRow in app.js) — a name input on top, mirroring
   the "+ Add" row above, plus a grid of icon choices below it. */
.expense-category-edit-row-inline {
  display: flex;
  flex-direction: column;
  gap: 8px;
  cursor: default;
  padding: 8px !important;
}

.expense-category-edit-row-inline:hover {
  background: none !important;
}

.expense-category-edit-top {
  display: flex;
  align-items: center;
  gap: 6px;
}

.expense-category-edit-top .expense-category-name-input {
  flex: 1;
  min-width: 0;
  background: #241318;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 7px;
  padding: 6px 8px;
  color: #f7f1ef;
  font-size: 0.88rem;
}

/* Scoped under .expense-category-menu (rather than the bare class alone)
   so this beats .account-form button's background/color/padding — every
   button here is a descendant of the "Add expense" form's .account-form,
   which would otherwise win on specificity and paint these as the form's
   default red-orange gradient submit-button style instead of the small
   tinted circle/swatch each is meant to be. */
.expense-category-menu .expense-category-confirm-edit-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: rgba(52, 211, 153, 0.16);
  color: #34d399;
  cursor: pointer;
}

.expense-category-menu .expense-category-confirm-edit-btn:hover {
  background: rgba(52, 211, 153, 0.3);
}

.expense-category-icon-grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 5px;
}

.expense-category-menu .expense-category-icon-option {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 7px;
  background: rgba(255, 255, 255, 0.04);
  color: #c2a3a8;
  cursor: pointer;
}

.expense-category-menu .expense-category-icon-option:hover {
  border-color: rgba(251, 191, 36, 0.4);
  color: #f7f1ef;
}

.expense-category-menu .expense-category-icon-option.selected {
  border-color: #fbbf24;
  background: rgba(251, 191, 36, 0.16);
  color: #fbbf24;
}

.expense-type-btn.active[data-type="expense"] {
  border-color: rgba(251, 113, 133, 0.5);
  background: rgba(251, 113, 133, 0.12);
  color: #fb7185;
}

.expense-type-btn.active[data-type="earning"] {
  border-color: rgba(52, 211, 153, 0.5);
  background: rgba(52, 211, 153, 0.12);
  color: #34d399;
}

.expense-overview-controls {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}

/* Wraps the "Entries" section's subtitle + sort control as one flex child
   of .section-heading, alongside its <h2> — same reasoning as
   .expense-overview-controls above it. */
.expense-entries-controls {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}

.expense-entries-controls .avanza-note,
.expense-entries-controls p {
  margin: 0;
}

/* Same compact "Sort" control as .news-sort-select — duplicated rather
   than reused since that class is scoped by name to the news panel. */
.expense-entries-sort {
  display: flex;
  align-items: center;
  gap: 6px;
  color: #a8888d;
  font-size: 0.82rem;
  flex-shrink: 0;
  white-space: nowrap;
}

.expense-entries-sort .custom-select-btn {
  padding: 6px 10px;
  font-size: 0.82rem;
  min-width: 130px;
}

/* One collapsible-free section per category when Sort is set to
   "Category" (see renderExpenseEntriesByCategory in app.js) — a heading
   row (swatch, name, entry count, running total) followed by that
   category's own entries, visually separated from the next category by
   the heading's top border rather than blending into one flat list. */
.expense-entries-group + .expense-entries-group {
  margin-top: 22px;
  padding-top: 18px;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.expense-entries-group-heading {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 10px;
}

.expense-entries-group-label {
  font-weight: 700;
  color: #f7f1ef;
}

.expense-entries-group-count {
  color: #a8888d;
  font-size: 0.85rem;
}

.expense-entries-group-total {
  margin-left: auto;
  font-weight: 700;
}

/* .accounts-list's own display:grid/gap only reaches its direct children
   — now .expense-entries-group wrappers, not the cards — so each group's
   own entries need the same grid/gap repeated one level down. */
.expense-entries-group-list {
  display: grid;
  gap: 14px;
}

.expense-view-toggle {
  display: inline-flex;
  gap: 4px;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 999px;
  padding: 3px;
}

.expense-view-btn,
.expense-filter-btn {
  border: 0;
  background: transparent;
  color: #c2a3a8;
  font-size: 0.78rem;
  font-weight: 600;
  padding: 6px 12px;
  border-radius: 999px;
  cursor: pointer;
}

.expense-view-btn.active {
  background: linear-gradient(135deg, #be123c, #d97706);
  color: white;
}

/* Expenses/Earnings breakdown filter — tinted per type (rose for expenses,
   green for earnings, same pairing as the Add-expense Type toggle's active
   colors) rather than the neutral List/Wheel/Calendar pill above it, so
   which side is selected reads at a glance instead of needing the label. */
.expense-filter-btn[data-filter="expense"] {
  color: rgba(251, 113, 133, 0.6);
}

.expense-filter-btn[data-filter="expense"].active {
  background: rgba(251, 113, 133, 0.16);
  color: #fb7185;
}

.expense-filter-btn[data-filter="earning"] {
  color: rgba(52, 211, 153, 0.6);
}

.expense-filter-btn[data-filter="earning"].active {
  background: rgba(52, 211, 153, 0.16);
  color: #34d399;
}

/* Sits between the Expenses/Earnings and List/Wheel/Calendar pills, so it's
   restyled to match their capsule look (see .expense-view-toggle) instead of
   the boxy, block-stacked <label>+<select> every other form field uses. */
.expense-period-select {
  display: inline-flex;
  align-items: center;
}

.expense-period-select .custom-select {
  min-width: 0;
}

.expense-period-select .custom-select-btn {
  width: auto;
  border: 0;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 999px;
  padding: 6px 14px;
  gap: 6px;
  color: #c2a3a8;
  font-size: 0.78rem;
  font-weight: 600;
}

.expense-period-select .custom-select-btn:hover {
  border-color: transparent;
  background: rgba(255, 255, 255, 0.09);
}

.expense-period-select .custom-select-menu {
  left: auto;
  right: 0;
  min-width: 150px;
}

/* The default selected-option highlight (see .custom-select-menu li.selected)
   is the same green now used for the Earnings filter button — fine when a
   select has nothing to do with expense/earning type, but confusing right
   next to that toggle, so this one gets the neutral amber accent used
   elsewhere (e.g. the hover state right below) instead. */
.expense-period-select .custom-select-menu li.selected {
  background: rgba(251, 191, 36, 0.16);
  color: #fbbf24;
}

.expense-custom-range {
  display: flex;
  gap: 16px;
  margin-bottom: 18px;
}

.expense-custom-range label {
  display: grid;
  gap: 6px;
  color: #e8d5d8;
  font-size: 0.95rem;
}

.expense-custom-range input {
  border: 1px solid rgba(255, 255, 255, 0.12);
  padding: 8px 12px;
  border-radius: 12px;
  background: #241318;
  color: #f7f1ef;
}

.expense-breakdown {
  display: grid;
  gap: 10px;
  margin-bottom: 22px;
}

/* Shared by the list rows and the wheel's legend rows below — both fade
   and slide up into place, staggered per-row via an inline animation-delay
   set at render time, instead of popping in already fully visible. */
@keyframes expenseRowFadeIn {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes expenseFadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

.expense-bar-row {
  display: grid;
  grid-template-columns: 140px 1fr auto;
  align-items: center;
  gap: 14px;
  animation: expenseRowFadeIn 0.4s ease both;
}

.expense-bar-label {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.9rem;
  color: #e8d5d8;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.expense-bar-swatch {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}

/* A custom category with a chosen icon renders this instead of the plain
   dot above — same footprint as its siblings so it drops into every layout
   (dropdown, expense rows, bars, legend) that already expects a swatch. */
.expense-bar-swatch-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: color-mix(in srgb, currentColor 18%, transparent);
}

.expense-bar-track {
  height: 10px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.06);
  overflow: hidden;
}

.expense-bar-fill {
  height: 100%;
  border-radius: 999px;
  transition: width 0.7s cubic-bezier(0.22, 0.9, 0.32, 1);
}

.expense-bar-amount {
  font-size: 0.9rem;
  font-weight: 600;
  white-space: nowrap;
  text-align: right;
}

.expense-bar-pct {
  color: #a8888d;
  font-weight: 400;
  margin-left: 4px;
}

.expense-wheel-wrap {
  display: flex;
  align-items: center;
  gap: 28px;
  flex-wrap: wrap;
}

.expense-wheel-svg-wrap {
  position: relative;
  width: 160px;
  height: 160px;
  flex-shrink: 0;
}

.expense-wheel {
  width: 100%;
  height: 100%;
}

/* Each circle's stroke-dasharray is set to a zero-length arc at render time
   and flipped to its real value a frame later (see animateExpenseWheel) —
   this transition is what turns that jump into the ring sweeping itself
   full. transition-delay is set per-circle inline, staggering the segments. */
.expense-wheel circle {
  transition: stroke-dasharray 0.8s cubic-bezier(0.22, 0.9, 0.32, 1);
}

.expense-wheel-center {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  pointer-events: none;
  animation: expenseFadeIn 0.5s ease both;
  animation-delay: 0.35s;
}

.expense-wheel-center-amount {
  font-size: 1.05rem;
  font-weight: 700;
  color: #f7f1ef;
}

.expense-wheel-center-label {
  font-size: 0.65rem;
  color: #a8888d;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-top: 2px;
}

.expense-wheel-legend {
  flex: 1;
  min-width: 180px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.expense-wheel-legend-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.85rem;
  animation: expenseRowFadeIn 0.4s ease both;
}

.expense-wheel-legend-label {
  flex: 1;
  color: #e8d5d8;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.expense-wheel-legend-amount {
  color: #c2a3a8;
  font-weight: 600;
  white-space: nowrap;
}

.expense-calendar {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.expense-calendar-header {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
}

.expense-calendar-title-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 160px;
}

.expense-calendar-title {
  font-weight: 700;
  font-size: 1.05rem;
  text-align: center;
}

.expense-calendar-month-total {
  font-size: 0.82rem;
  font-weight: 700;
}

.expense-calendar-nav {
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: #241318;
  color: #e8d5d8;
  width: 32px;
  height: 32px;
  border-radius: 10px;
  cursor: pointer;
  font-size: 1.1rem;
  line-height: 1;
}

.expense-calendar-nav:hover {
  border-color: rgba(251, 191, 36, 0.4);
  color: #fbbf24;
}

/* 8 columns, not 7 — the trailing column is each week's net total (see
   .expense-calendar-week-total below), which both the weekday header row
   and the day grid share the same column template with so they line up.
   Day columns are capped at 96px (not 1fr) — each day cell is a square
   (see .expense-calendar-day's aspect-ratio), so on a wide panel letting
   columns stretch to fill the width made every row taller too, and a
   6-row month could end up needing to scroll to see the bottom weeks.
   justify-content centers the now-narrower grid instead of leaving it
   flush left with empty space to the right. */
.expense-calendar-weekdays,
.expense-calendar-grid {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 96px)) 96px;
  justify-content: center;
  gap: 6px;
}

.expense-calendar-weekdays span {
  text-align: center;
  font-size: 0.72rem;
  color: #a8888d;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding-bottom: 4px;
}

.expense-calendar-day {
  aspect-ratio: 1 / 1;
  /* Without this, unwrappable content (the amount badge below, at
     white-space:nowrap) forces the grid track wider than its 1fr share the
     moment it doesn't fit — which then blows up every cell's aspect-ratio
     size in lockstep, making the whole calendar visibly bigger than
     intended instead of just that one cell overflowing. */
  min-width: 0;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 10px;
  padding: 6px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  background: #1c0f12;
  animation: expenseFadeIn 0.3s ease both;
}

.expense-calendar-day-empty {
  border-color: transparent;
  background: transparent;
  animation: none;
}

.expense-calendar-day.today {
  border-color: rgba(251, 191, 36, 0.5);
}

.expense-calendar-day.has-activity {
  background: #241318;
}

.expense-calendar-day-number {
  font-size: 0.78rem;
  color: #c2a3a8;
}

.expense-calendar-day.today .expense-calendar-day-number {
  color: #fbbf24;
  font-weight: 700;
}

.expense-calendar-day-amount {
  font-size: 0.76rem;
  font-weight: 700;
  align-self: flex-end;
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Each week's net total, in the grid's trailing 8th column — plain flex
   centering rather than aspect-ratio like a day cell, since it just needs
   to stretch to match whatever height the row's day cells already set. */
.expense-calendar-week-total {
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  text-align: center;
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.03);
  font-size: 0.8rem;
  font-weight: 700;
  padding: 4px 2px;
}

.expense-calendar-week-total-empty {
  color: #7a6266;
}

.expense-entry-row {
  display: flex;
  align-items: center;
  gap: 12px;
}

.expense-entry-main {
  flex: 1;
  min-width: 0;
}

.expense-entry-main h3 {
  margin: 0 0 4px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── Portfolio news ────────────────────────────────────────────── */

.news-panel {
  display: flex;
  flex-direction: column;
  min-width: 0;
  /* Anchors the news-side .panel-resize-handle, which sits just outside
     this panel's left edge, straddling the gap to the accounts panel
     next to it. */
  position: relative;
}

/* ── Panel-width resize handles ────────────────────────────────────
   Two drag handles straddle the gaps on either side of the accounts
   panel: one against the "Add account" form, one against the news
   panel. Each hangs off the left edge of the panel to its right (see
   #accounts-panel's and .news-panel's `position: relative`) and, when
   dragged, changes --form-panel-width or --news-panel-width — the CSS
   vars .content-grid's outer columns read above. The accounts panel
   itself is always the grid's 1fr column, so it absorbs whichever side
   gets dragged automatically, without needing its own width var. Widths
   are clamped in app.js so neither panel can be dragged down to an
   unreadable size. */
.panel-resize-handle {
  position: absolute;
  top: 0;
  bottom: 0;
  left: -21px;
  width: 18px;
  cursor: col-resize;
  display: flex;
  align-items: center;
  justify-content: center;
  touch-action: none;
  z-index: 5;
}

.panel-resize-handle::before {
  content: '';
  width: 3px;
  height: 48px;
  border-radius: 3px;
  background: rgba(255, 255, 255, 0.12);
  transition: background 0.15s ease, height 0.15s ease;
}

.panel-resize-handle:hover::before,
.panel-resize-handle.panel-resize-handle-active::before {
  background: rgba(251, 191, 36, 0.55);
  height: 64px;
}

.news-panel .section-heading {
  margin-bottom: 4px;
}

.news-panel .section-heading h2 {
  font-size: 1.15rem;
}

.news-controls {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
}

.news-controls .avanza-note {
  margin-bottom: 0;
}

.news-sort-select {
  display: flex;
  align-items: center;
  gap: 6px;
  color: #a8888d;
  font-size: 0.82rem;
  flex-shrink: 0;
  white-space: nowrap;
}

.news-sort-select .custom-select-btn {
  padding: 6px 10px;
  font-size: 0.82rem;
  min-width: 130px;
}

/* The button above stays nowrap/compact, but that white-space:nowrap
   inherits down into the flyout menu too — with long labels like "Novo
   Nordisk ADR" that forced the menu to overflow horizontally and, because
   overflow-y:auto implicitly makes overflow-x auto as well, produced a
   sideways scrollbar. Reset wrapping and let the menu grow to fit its
   longest item (capped) instead of scrolling sideways. */
.news-sort-select .custom-select-menu {
  left: auto;
  right: 0;
  width: max-content;
  min-width: 100%;
  max-width: 260px;
  white-space: normal;
  overflow-x: hidden;
}

/* The "By stock/crypto" row inside the Sort menu — expands its own
   per-asset sub-list in place (see .news-sort-submenu below) instead of
   that list living in a second, separate dropdown next to this one. */
.news-sort-expandable-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.news-sort-expandable-chevron {
  flex-shrink: 0;
  color: #a8888d;
  transition: transform 0.15s ease;
}

.news-sort-expandable.expanded .news-sort-expandable-chevron {
  transform: rotate(180deg);
}

.news-sort-submenu {
  list-style: none;
  margin: 4px 0 0;
  padding: 2px 0 2px 10px;
  border-left: 1px solid rgba(255, 255, 255, 0.08);
  display: none;
}

.news-sort-expandable.expanded .news-sort-submenu {
  display: block;
}

.news-sort-submenu li {
  font-size: 0.85rem;
}

.news-sort-submenu-empty {
  color: #7a6266;
  cursor: default !important;
}

.news-sort-submenu-empty:hover {
  background: none !important;
  color: #7a6266 !important;
}

.news-list {
  display: grid;
  gap: 12px;
  max-height: 700px;
  overflow-y: auto;
  overflow-x: hidden;
  padding-right: 4px;
  margin-right: -4px;
}

.news-list::-webkit-scrollbar {
  width: 6px;
}

.news-list::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.14);
  border-radius: 999px;
}

.news-item {
  min-width: 0;
  border: 1px solid rgba(255, 255, 255, 0.09);
  border-radius: 16px;
  padding: 14px;
  background: #1c0f12;
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}

.news-item:hover {
  border-color: rgba(251, 191, 36, 0.3);
  background: #221317;
}

.news-item.expanded {
  cursor: default;
  border-color: rgba(251, 191, 36, 0.35);
}

.news-item-header {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 8px;
}

.news-item-thumb {
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  border-radius: 10px;
  object-fit: cover;
  background: #241318;
}

.news-item-thumb-fallback {
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 0.85rem;
  color: #fbbf24;
  background: rgba(217, 119, 6, 0.16);
}

.news-item-meta {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}

.news-item-badge {
  display: inline-block;
  width: fit-content;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 600;
  background: rgba(217, 119, 6, 0.16);
  color: #fbbf24;
}

.news-item-source {
  color: #a8888d;
  font-size: 0.8rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.news-item-title {
  margin: 0 0 6px;
  font-size: 0.98rem;
  line-height: 1.35;
  white-space: normal;
  overflow-wrap: anywhere;
}

.news-item-snippet {
  margin: 0;
  color: #c2a3a8;
  font-size: 0.88rem;
  line-height: 1.4;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.news-item-summary {
  margin: 0 0 10px;
  color: #d9bcc0;
  font-size: 0.9rem;
  line-height: 1.5;
}

.news-item-link {
  color: #fbbf24;
  font-size: 0.88rem;
  font-weight: 600;
  text-decoration: underline;
}

/* ── No-hover devices ──────────────────────────────────────────── */
/* A touch device never fires :hover in any persistent sense, so anything
   whose only way to appear is ".position-row:hover .position-*-btn"
   (opacity:0 by default — see those rules above) is invisible and
   untappable there: no way to hide, edit, or delete a position at all.
   `hover: none` targets touch capability directly rather than proxying it
   through screen width, so this also covers a touch laptop or tablet in a
   wide window, not just a narrow phone viewport. */
@media (hover: none), (pointer: coarse) {
  .position-hide-btn,
  .position-delete-btn,
  .position-edit-btn {
    opacity: 1;
  }
}

/* ── Budget page ──────────────────────────────────────────────────── */
/* Same two-button toggle look as .expense-type-toggle/.expense-type-btn, but
   under its own class name since Budget's toggles (solve-for, data source)
   aren't the expense/earning pair those were built for. */
.budget-toggle {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}

.account-form .budget-toggle-btn {
  min-width: 0;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: #241318;
  color: #c2a3a8;
  padding: 8px 10px;
  border-radius: 8px;
  font-weight: 600;
  font-size: 0.85rem;
  cursor: pointer;
}

.budget-toggle-btn:hover:not(:disabled),
.budget-toggle-btn:active:not(:disabled) {
  transform: none;
}

.budget-toggle-btn.active {
  border-color: rgba(251, 191, 36, 0.5);
  background: rgba(251, 191, 36, 0.12);
  color: #fbbf24;
}

.budget-contribution-field,
.budget-manual-fields {
  display: grid;
  gap: 14px;
}

.budget-category-inputs {
  display: grid;
  gap: 10px;
}

.budget-category-input-row {
  display: grid;
  grid-template-columns: 1fr 120px;
  align-items: center;
  gap: 10px;
}

.budget-category-input-row label {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.9rem;
  color: #c2a3a8;
}

/* The budget tab's two headline stat values ("$X / week ($Y / month)") run
   noticeably longer than every other .stat-value in the app (plain numbers)
   — .stat-value's app-wide single-line ellipsis (see styles.css above)
   would clip them mid-word, so these two are let wrap onto a second line
   instead rather than losing the monthly figure to truncation. */
#budget-primary-value,
#budget-available-value {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
  font-size: 0.95rem;
  line-height: 1.3;
}

.budget-status-ok {
  color: #34d399;
}

.budget-status-warn {
  color: #fb7185;
}

.budget-suggestions-body {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.budget-suggestions-line {
  font-size: 1.05rem;
  line-height: 1.5;
  color: #f7f1ef;
}

.budget-suggestions-goal-line {
  font-size: 0.95rem;
  line-height: 1.5;
  color: #c2a3a8;
}

/* One pill per goal, same visual language as .app-nav-btn — the active one
   picks up the same gradient so "which goal am I editing" reads the same
   way "which tab am I on" does at the top of the app. */
.budget-goal-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 14px 0;
}

.budget-goal-tab {
  display: flex;
  align-items: center;
  gap: 6px;
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(23, 11, 13, 0.6);
  color: #c2a3a8;
  padding: 8px 14px;
  border-radius: 999px;
  cursor: pointer;
  font-weight: 600;
  font-size: 0.85rem;
}

.budget-goal-tab:hover:not(.active) {
  background: rgba(255, 255, 255, 0.06);
  color: #f7f1ef;
}

.budget-goal-tab.active {
  background: linear-gradient(135deg, #be123c, #d97706);
  border-color: transparent;
  color: white;
}

.budget-goal-tab-remove {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  color: inherit;
  opacity: 0.75;
}

.budget-goal-tab-remove:hover {
  opacity: 1;
}

.budget-goal-tab-new {
  border-style: dashed;
}

/* ── Category importance (Settings) ──────────────────────────────── */
.importance-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.importance-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 10px 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}

.importance-row:last-child {
  border-bottom: none;
}

.importance-row-label {
  display: flex;
  align-items: center;
  gap: 10px;
  color: #f7f1ef;
  font-size: 0.95rem;
}

/* The 5 dots sit on a thin connecting line (the row's own ::before, since a
   single flat bar behind inline buttons needs a positioning context) so the
   whole control reads as one scale being filled in, not 5 separate buttons. */
.importance-bubbles {
  position: relative;
  display: flex;
  align-items: center;
  gap: 18px;
}

.importance-bubbles::before {
  content: '';
  position: absolute;
  left: 7px;
  right: 7px;
  top: 50%;
  height: 2px;
  background: rgba(255, 255, 255, 0.12);
  transform: translateY(-50%);
}

.importance-bubble {
  position: relative;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.25);
  background: #1c0f12;
  padding: 0;
  cursor: pointer;
}

.importance-bubble.filled {
  border-color: transparent;
  background: linear-gradient(135deg, #be123c, #d97706);
}

/* ── Budget chart ─────────────────────────────────────────────────── */
.budget-chart-wrap {
  position: relative;
  margin-top: 24px;
  padding-top: 20px;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.budget-chart-legend {
  display: flex;
  gap: 20px;
  margin-bottom: 10px;
}

.budget-chart-legend-item {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.85rem;
  color: #c2a3a8;
}

.budget-chart-legend-swatch {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
}

.budget-chart-legend-needed {
  background: #d97706;
}

.budget-chart-legend-pace {
  background: #fbbf24;
}

/* A dark-red card of its own, same family as .panel/.stat-card
   (rgba(24,12,14,...)/#1c0f12) rather than just bleeding edge-to-edge into
   the results panel behind it — gives the chart a contained canvas. */
.budget-chart-svg-wrap {
  position: relative;
  width: 100%;
  background: rgba(28, 13, 15, 0.6);
  border-radius: 16px;
}

.budget-chart-svg {
  display: block;
  width: 100%;
  height: auto;
  cursor: crosshair;
}

.budget-chart-line {
  fill: none;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Needed is a definite, fixed-rate plan — solid. Current pace is an
   extrapolation from recent averages, not a certainty — dashed, so the two
   read as "the target" vs "a projection" at a glance, not just two colors. */
.budget-chart-line-needed {
  stroke: #d97706;
}

.budget-chart-line-pace {
  stroke: #fbbf24;
  stroke-dasharray: 7 5;
}

.budget-chart-target-guide {
  stroke: rgba(217, 119, 6, 0.3);
  stroke-width: 1;
  stroke-dasharray: 4 4;
}

.budget-chart-axis-line {
  stroke: rgba(217, 119, 6, 0.8);
  stroke-width: 3;
}

.budget-chart-tick {
  stroke: rgba(217, 119, 6, 0.8);
  stroke-width: 2;
}

.budget-chart-axis-label {
  font-size: 11px;
  fill: #d9a066;
}

.budget-chart-target-label {
  font-weight: 700;
}

.budget-chart-hover-guide {
  stroke: rgba(251, 191, 36, 0.45);
  stroke-width: 1;
}

.budget-chart-dot {
  stroke: #170b0d;
  stroke-width: 2;
}

.budget-chart-dot-needed {
  fill: #d97706;
}

.budget-chart-dot-pace {
  fill: #fbbf24;
}

.budget-chart-tooltip {
  position: absolute;
  pointer-events: none;
  background: rgba(23, 11, 13, 0.95);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 10px;
  padding: 10px 12px;
  min-width: 170px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4);
  z-index: 5;
}

.budget-chart-tooltip-date {
  font-size: 0.8rem;
  font-weight: 700;
  color: #f7f1ef;
  margin-bottom: 6px;
}

.budget-chart-tooltip-row {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 0.8rem;
  color: #c2a3a8;
}

/* ── Responsive ────────────────────────────────────────────────── */

@media (max-width: 900px) {
  .content-grid {
    grid-template-columns: 1fr;
  }

  .stats-cards {
    grid-auto-flow: row;
    grid-template-columns: repeat(2, 1fr);
    overflow-x: visible;
  }

  /* Panels stack into one column here, so there's no side-by-side gap
     left for the drag handle to sit in. */
  .panel-resize-handle {
    display: none;
  }
}

@media (max-width: 700px) {
  .hero {
    flex-direction: column;
    align-items: flex-start;
  }

  .hero-card {
    width: 100%;
  }

  .stats-cards {
    grid-auto-flow: row;
    grid-template-columns: 1fr 1fr;
    overflow-x: visible;
  }

  .expense-bar-row {
    grid-template-columns: 90px 1fr auto;
  }

  .expense-custom-range {
    flex-direction: column;
    gap: 10px;
  }

  .expense-calendar-day-number {
    font-size: 0.7rem;
  }

  .expense-calendar-day-amount {
    font-size: 0.66rem;
  }

  .expense-calendar-weekdays,
  .expense-calendar-grid {
    grid-template-columns: repeat(7, 1fr) 42px;
  }

  .expense-calendar-week-total {
    font-size: 0.7rem;
    padding: 2px 1px;
  }

  /* ── Touch targets ─────────────────────────────────────────────
     These sizes are fine with a mouse pointer but well under the
     ~40-44px a thumb needs to hit reliably — bumped here rather than
     globally so desktop's tighter, precise layout is untouched. */

  .privacy-toggle-btn {
    width: 38px;
    height: 38px;
  }

  .currency-dropdown-btn {
    padding: 8px 12px;
    font-size: 0.85rem;
  }

  .expense-category-remove-btn {
    width: 24px;
    height: 24px;
  }

  .expense-category-menu .expense-category-icon-option {
    width: 34px;
    height: 34px;
  }

  /* Widened enough that the day grid below actually gets bigger cells
     out of it — JS clamps the popup back on-screen dynamically (see
     positionDatePicker in app.js), so this is safe at any viewport width
     this breakpoint applies to. */
  .date-picker-popup {
    width: 300px;
  }

  .date-picker-day {
    padding: 10px 0;
    font-size: 0.9rem;
  }

  .date-picker-nav {
    padding: 8px 12px;
    font-size: 1.3rem;
  }
}
