/* ============================================
   GENERATED FILE — DO NOT HAND-EDIT.
   Built by build-css.py from css/index.css and its @import graph.
   Every change here is lost on the next build. Edit the source
   file under css/ or tokens/, then re-run:

       python3 build-css.py
   ============================================ */

/* ---- css/index.css ---- */
/* ============================================
   Settlr Design System — All CSS
   Import this single file to load everything.
   ============================================ */

/* Tokens */

/* ---- tokens/index.css ---- */
/* ============================================
   Settlr Design System — All Tokens
   Import this single file to load everything.
   ============================================ */


/* ---- tokens/colors.css ---- */
/* ============================================
   Settlr Design System — Color Tokens
   ============================================ */

:root {
  /* ---- Neutral (warm beige) ---- */
  --color-neutral-50:  #FEF9EE;
  --color-neutral-100: #F9F1DA;
  --color-neutral-200: #EFE4C4;
  --color-neutral-300: #E0D0B0;
  --color-neutral-400: #BEB48A;
  --color-neutral-500: #787057; /* darkened from #9A9070 for WCAG AA — 4.70:1 on neutral-50, 4.94:1 on white (UX-25) */
  --color-neutral-600: #756C55;
  --color-neutral-700: #524C3B;
  --color-neutral-800: #332F25;
  --color-neutral-900: #1A1810;

  /* ---- Gray (pure neutral) ---- */
  --color-gray-0:    #FFFFFF;
  --color-gray-50:   #F7F8F9;
  --color-gray-100:  #ECEFF1;
  --color-gray-200:  #D8DCE3;
  --color-gray-300:  #C4C7CC;
  --color-gray-400:  #A0A4AB;
  --color-gray-500:  #7C8089;
  --color-gray-600:  #5B5F68;
  --color-gray-700:  #3E4149;
  --color-gray-800:  #25272D;
  --color-gray-900:  #111315;
  --color-gray-1000: #000000;

  /* ---- Olive (brand) ---- */
  --color-olive-50:  #F2F4EB;
  --color-olive-100: #DDE3C8;
  --color-olive-200: #BFCB9A;
  --color-olive-300: #96A96A;
  --color-olive-400: #6E8742;
  --color-olive-500: #4E6629;
  --color-olive-600: #31401A;
  --color-olive-700: #243012;
  --color-olive-800: #16200A;
  --color-olive-900: #0A1005;

  /* ---- Green (success / lent) ---- */
  --color-green-50:  #E8FAF0;
  --color-green-100: #C2EECF;
  --color-green-200: #A8D5B0;
  --color-green-300: #72B87E;
  --color-green-400: #4A9A58;
  --color-green-500: #357A42;
  --color-green-600: #285E32;
  --color-green-700: #1D4624;
  --color-green-800: #122E17;
  --color-green-900: #091A0D;

  /* ---- Coral (error / owe) ---- */
  --color-coral-50:  #FBF0EE;
  --color-coral-100: #F5D8D2;
  --color-coral-200: #E8B0A4;
  --color-coral-300: #D4876F;
  --color-coral-400: #BF6550;
  --color-coral-500: #9E4C39;
  --color-coral-600: #7D3829;
  --color-coral-700: #5C271B;
  --color-coral-800: #3B180F;
  --color-coral-900: #1C0B07;

  /* ---- Gold (warning / favourite) ---- */
  --color-gold-50:  #FBF6E9;
  --color-gold-100: #F7EBC8;
  --color-gold-200: #ECD491;
  --color-gold-300: #E0BC5E;
  --color-gold-400: #CFA02E;
  --color-gold-500: #B8860B;
  --color-gold-600: #976E09;
  --color-gold-700: #6F5107;

  /* ---- Overlay ---- */
  --overlay-20: rgba(0, 0, 0, 0.20);
  --overlay-35: rgba(0, 0, 0, 0.35);
  --overlay-50: rgba(0, 0, 0, 0.50);
  --overlay-65: rgba(0, 0, 0, 0.65);
  --overlay-80: rgba(0, 0, 0, 0.80);
}

/* ---- tokens/semantic.css ---- */
/* ============================================
   Settlr Design System — Semantic / Component Tokens

   LAYER 2 — General Semantics
     Maps primitives (colors.css) to role-based aliases.
     Used only by L3 component tokens below.

   LAYER 3 — Component Tokens
     Maps L2 roles to specific component slots.
     Used by css/*.css component files.
   ============================================ */

:root {

  /* ============================================================
     L2 — GENERAL SEMANTICS
     All values alias directly to primitives in colors.css
     ============================================================ */

  /* ---- Brand / Action (Olive) ---- */
  --action-surface:   var(--color-olive-50);   /* selected rows, tinted card bg */
  --action-muted:     var(--color-olive-100);  /* chip/badge/toast light tint */
  --action-secondary: var(--color-olive-200);  /* secondary btn bg, avatar bg */
  --action-accent:    var(--color-olive-300);  /* fab bg, secondary pressed, illus accent, light borders */
  --action-mid:       var(--color-olive-500);  /* mid-weight icon fill */
  --action-primary:   var(--color-olive-600);  /* CTAs, active states, focus rings */
  --action-dark:      var(--color-olive-700);  /* primary pressed, text/icon on light olive surfaces */
  --action-strong:    var(--color-olive-800);  /* high-contrast olive text */

  /* ---- Error / Destructive / Owe (Coral) ---- */
  --error-action:         var(--color-coral-400);  /* destructive btn bg, error input border */
  --error-action-pressed: var(--color-coral-500);  /* destructive pressed state, owe icon */
  --error-strong:         var(--color-coral-600);  /* error helper/validation text */
  --error-fg:             var(--color-coral-700);  /* label/toast error text */
  --error-subtle:         var(--color-coral-100);  /* error/owe label bg, list-remove bg */
  --error-surface:        var(--color-coral-50);   /* error input bg, owe card bg */
  --error-border:         var(--color-coral-300);  /* toast error border */

  /* ---- Warning / Favourite (Gold) ---- */
  --warning-fg:      var(--color-gold-500);  /* favourite star, warning text (#B8860B) */
  --warning-strong:  var(--color-gold-600);  /* stronger warning text */
  --warning-subtle:  var(--color-gold-100);  /* warning label bg */
  --warning-border:  var(--color-gold-300);  /* warning border */
  /* warning-fg/gold-500 is 2.74:1 on warning-subtle/gold-100 and warning-strong/
     gold-600 is 3.88:1 — both fail WCAG AA 4.5:1 for label-sized text. gold-700
     clears it at 6.19:1 (matches the success/error label pattern: 6.0:1 / 8.9:1). */
  --warning-fg-strong: var(--color-gold-700);

  /* ---- Success / Lent (Green) ---- */
  --success-fg:      var(--color-green-600);  /* label/lent text */
  --success-strong:  var(--color-green-700);  /* toast success text */
  --success-mid:     var(--color-green-500);  /* expense lent icon */
  --success-subtle:  var(--color-green-100);  /* label bg, card lent border */
  --success-surface: var(--color-green-50);   /* expense lent bg, lent card bg */
  --success-border:  var(--color-green-300);  /* toast success border */

  /* ---- Surface (Neutral / Gray) ---- */
  --surface-bg:       var(--color-neutral-50);   /* page bg, sheet bg, top-app-bar */
  --surface-primary:  var(--color-neutral-50);   /* alias — same as surface-bg */
  --surface-card:     var(--color-gray-0);        /* elevated cards, modals, nav bar */
  --surface-input:    var(--color-neutral-100);   /* input bg, chip-off bg, icon-btn bg */
  --surface-track:    var(--color-neutral-200);   /* tab track, slot bg, illustration placeholders */

  /* ---- Content / Text (Neutral) ---- */
  --text-primary:     var(--color-neutral-900);  /* headings, active labels, primary body */
  --text-secondary:   var(--color-neutral-600);  /* subtext, helper, tab default */
  --text-tertiary:    var(--color-neutral-500);  /* captions, empty-state body */
  --text-placeholder: var(--color-neutral-500);  /* input placeholder, settled text — was neutral-400 (1.85:1, fails AA); neutral-500 → 4.38:1 on input bg (UX-25) */
  --text-strong:      var(--color-neutral-800);  /* chip/control labels, faq text */
  --text-label:       var(--color-neutral-700);  /* form labels, contact icons */
  --text-faint:       var(--color-neutral-300);  /* very dim text, disabled tab labels */
  --text-brand:       var(--color-olive-600);    /* brand-colored text */
  --text-inverse:     var(--color-gray-0);        /* text on filled/dark surfaces */

  /* ---- Border (Neutral) ---- */
  --border-default: var(--color-neutral-300);  /* standard borders, dividers, sheet */
  --border-subtle:  var(--color-neutral-200);  /* footer, nav, soft separators */
  --border-strong:  var(--color-neutral-400);  /* amount input, prominent borders */
  /* neutral-300/400 only reach ~1.4:1 / ~2.0:1 against surface-bg — too weak to
     read as a UI boundary. neutral-500 clears WCAG 1.4.11 (≥3:1 non-text contrast)
     with room to spare: 4.70:1 on surface-bg (#FEF9EE), 4.94:1 on surface-card
     (#FFFFFF). Use where a boundary must actually be perceived, not just implied
     by a background tint (icon-btn neutral variant). */
  --border-emphasis: var(--color-neutral-500);

  /* ---- Neutral / Gray Status ---- */
  --neutral-surface:      var(--color-gray-100);  /* neutral label bg */
  --neutral-fg:           var(--color-gray-700);  /* neutral label text */
  --neutral-border:       var(--color-gray-300);  /* neutral toast border */
  --neutral-mid:          var(--color-gray-200);  /* illustration bg (no longer the nav tab active bg) */
  --disabled-fg:          var(--color-gray-400);  /* disabled control label */
  --disabled-border:      var(--color-gray-200);  /* disabled control border */
  --disabled-selected-bg: var(--color-gray-300);  /* disabled + selected control fill */


  /* ============================================================
     L3 — COMPONENT TOKENS
     All values alias to L2 general semantics above.
     Referenced by css/*.css component files.
     ============================================================ */

  /* ---- Button: Primary ---- */
  --btn-primary-bg:         var(--action-primary);
  --btn-primary-bg-pressed: var(--action-dark);
  --btn-primary-fg:         var(--text-inverse);

  /* ---- Button: Secondary ---- */
  --btn-secondary-bg:         var(--action-secondary);
  --btn-secondary-bg-pressed: var(--action-accent);
  --btn-secondary-fg:         var(--action-dark);

  /* ---- Button: Ghost ---- */
  --btn-ghost-fg: var(--action-primary);

  /* ---- Button: Destructive ---- */
  --btn-destructive-bg:         var(--error-action);
  --btn-destructive-bg-pressed: var(--error-action-pressed);
  --btn-destructive-fg:         var(--text-inverse);

  /* ---- Button: Icon ---- */
  /* Default / neutral */
  --btn-icon-bg:         var(--surface-input);
  --btn-icon-bg-pressed: var(--surface-track);
  --btn-icon-fg:         var(--text-primary);
  /* Variant: primary (olive filled) */
  --btn-icon-primary-bg:         var(--btn-primary-bg);
  --btn-icon-primary-bg-pressed: var(--btn-primary-bg-pressed);
  --btn-icon-primary-fg:         var(--btn-primary-fg);
  /* Variant: destructive (coral tint; pressed darkens for visible feedback) */
  --btn-icon-destructive-bg:         var(--list-remove-bg);
  --btn-icon-destructive-bg-pressed: var(--error-border);
  --btn-icon-destructive-fg:         var(--list-remove-fg);
  /* Variant: ghost (transparent; subtle pressed fill) */
  --btn-icon-ghost-fg:         var(--text-primary);
  --btn-icon-ghost-bg-pressed: var(--surface-input);
  /* Variant: surface (white + hairline border) */
  --btn-icon-surface-bg:         var(--surface-card);
  --btn-icon-surface-bg-pressed: var(--surface-input);
  --btn-icon-surface-fg:         var(--text-primary);
  --btn-icon-surface-border:     var(--border-default);
  /* Variant: default/neutral boundary — surface-input (#F9F1DA) on surface-bg
     (#FEF9EE) is ~1.07:1, effectively invisible as a button shape. A hairline
     border at --border-emphasis restores a perceivable boundary (see F5). */
  --btn-icon-border: var(--border-emphasis);
  /* Fixed-footprint sizes (xs/sm reuse spacing tokens; md/lg are off-scale) */
  --icon-btn-size-xs: var(--spacing-32);
  --icon-btn-size-sm: var(--spacing-40);
  --icon-btn-size-md: 44px;
  --icon-btn-size-lg: 52px;

  /* ---- Action Button Row ---- */
  --action-btn-row-bg:     var(--surface-input);
  --action-btn-row-border: var(--border-subtle);

  /* ---- Screen Footer ---- */
  --screen-footer-bg:     var(--surface-bg);
  /* Border is transparent at rest and revealed by .is-scrolled once content
     scrolls underneath the footer (see components/screen-footer.md). */
  --screen-footer-border-default: transparent;
  --screen-footer-border: var(--border-subtle);

  /* ---- Type Chip ---- */
  --type-chip-bg-off:     var(--surface-bg);
  --type-chip-border-off: var(--border-strong);
  --type-chip-fg-off:     var(--text-strong);
  --type-chip-bg-on:      var(--action-muted);
  --type-chip-border-on:  var(--action-dark);
  --type-chip-fg-on:      var(--text-primary);

  /* ---- Chip ---- */
  --chip-bg-off:     var(--surface-input);
  --chip-bg-on:      var(--action-primary);
  --chip-border-off: var(--border-default);
  --chip-border-on:  var(--action-primary);
  --chip-fg-off:     var(--text-strong);
  --chip-fg-on:      var(--text-inverse);

  /* ---- Label / Status Badge ---- */
  --label-success-bg: var(--success-subtle);
  --label-success-fg: var(--success-fg);
  --label-error-bg:   var(--error-subtle);
  --label-error-fg:   var(--error-fg);
  --label-neutral-bg: var(--neutral-surface);
  --label-neutral-fg: var(--neutral-fg);
  --label-lent-bg:    var(--success-subtle);
  --label-lent-fg:    var(--success-fg);
  --label-owe-bg:     var(--error-subtle);
  --label-owe-fg:     var(--error-fg);
  --label-settled-bg: var(--neutral-surface);
  --label-settled-fg: var(--neutral-fg);
  --label-warning-bg: var(--warning-subtle);
  --label-warning-fg: var(--warning-fg-strong);   /* AA-safe warning badge text (see --warning-fg-strong) */

  /* ---- Input ---- */
  --input-bg:             var(--surface-input);
  --input-bg-focused:     var(--surface-card);
  --input-bg-error:       var(--error-surface);
  --input-fg-default:     var(--text-placeholder);
  --input-fg-active:      var(--text-primary);
  --input-border-default: var(--border-default);
  --input-border-focused: var(--action-primary);
  --input-border-error:   var(--error-action);
  --input-label:          var(--text-label);
  --input-helper:         var(--text-tertiary);
  --input-helper-error:   var(--error-strong);

  /* ---- OTP Input ---- */
  --otp-caret: var(--action-primary);

  /* ---- Radio / Checkbox Control ---- */
  --control-bg-default:           transparent;
  --control-bg-selected:          var(--action-primary);
  --control-bg-disabled:          var(--neutral-surface);
  --control-bg-disabled-selected: var(--disabled-selected-bg);
  --control-border-default:       var(--border-default);
  --control-border-selected:      var(--action-primary);
  --control-border-disabled:      var(--disabled-border);
  --control-dot:                  var(--text-inverse);
  --control-label:                var(--text-strong);
  --control-description:          var(--text-tertiary);
  --control-label-disabled:       var(--disabled-fg);

  /* ---- Radio Container (Boxed) ---- */
  --container-bg-default:      var(--surface-card);
  --container-bg-selected:     var(--action-surface);
  --container-border-default:  var(--border-default);
  --container-border-selected: var(--action-primary);
  --container-border-disabled: var(--disabled-border);

  /* ---- Radio Item Boxed — Illustration ---- */
  --radio-illus-placeholder-bg: var(--surface-track);

  /* ---- Type Chip — Illustration placeholder ---- */
  --type-chip-illus-placeholder-bg: var(--surface-track);

  /* ---- Tab / Segment ---- */
  --tab-bg-track:    var(--surface-track);
  --tab-bg-active:   var(--surface-card);
  --tab-border-active: var(--border-default);
  --tab-fg-active:   var(--text-primary);
  --tab-fg-default:  var(--text-secondary);
  --tab-fg-disabled: var(--text-faint);

  /* ---- Sheet / Modal ---- */
  --sheet-bg:      var(--surface-bg);
  --sheet-border:  var(--action-primary);
  --sheet-header:  var(--text-primary);
  --sheet-icon:    var(--text-primary);
  --sheet-slot-bg: var(--surface-track);
  --sheet-divider: var(--border-default);

  /* ---- Avatar (standalone) ---- */
  --avatar-bg:   var(--action-secondary);
  --avatar-fg:   var(--action-primary);
  --avatar-ring: var(--surface-card);

  /* ---- Member Pill / Avatar Chip ---- */
  --member-pill-bg: var(--surface-input);
  --member-pill-fg: var(--text-strong);

  /* ---- Avatar Stack ---- */
  --avatar-stack-overflow-bg: var(--neutral-surface);
  --avatar-stack-overflow-fg: var(--text-secondary);
  --avatar-stack-label-fg:    var(--text-tertiary);
  /* Overlap (negative margin) per size — component-specific, no spacing primitive.
     Previously ~29-31% of each item's diameter at every size (xs -6/20, sm -8/28,
     md -12/40, lg -16/52). Real initials are 2 characters (js/hydrate.js
     initialsFrom takes the first letter of the first two words), and at that
     overlap ratio the second letter sits under the next avatar — "AJ" renders as
     "A" (F2). Reduced one spacing step per size (~14-23% of diameter) so 2-char
     initials stay fully visible while avatars still visibly stack. */
  /* XS (20px circle, ~16px-wide 2-char text at --font-size-12) only has ~2px
     of blank margin per side before hitting the glyphs themselves — measured
     in-browser, even -4px still clipped 2px into the text. 0 (flush, no
     overlap) is the only value that stays clipping-safe for arbitrary 2-char
     initials at this size; the visible ring (box-shadow) still reads as a
     stack. SM/MD/LG keep visible overlap — measured with ~2px+ of spare
     margin around the text at each of these three sizes. */
  --avatar-stack-overlap-xs:  0;
  --avatar-stack-overlap-sm:  calc(-1 * var(--spacing-4));
  --avatar-stack-overlap-md:  calc(-1 * var(--spacing-8));
  --avatar-stack-overlap-lg:  calc(-1 * var(--spacing-12));

  /* ---- Contact / Person Item ---- */
  --contact-bg-default:  transparent;
  --contact-bg-selected: var(--action-surface);
  --contact-avatar-bg:   var(--action-secondary);
  --contact-avatar-fg:   var(--action-primary);
  --contact-name:        var(--text-primary);
  --contact-subtext:     var(--text-secondary);
  --contact-icon:        var(--text-label);
  --contact-divider:     var(--border-default);
  --contact-settled-fg:  var(--text-placeholder);

  /* ---- Navigation Bar ---- */
  --nav-bar-bg:         var(--surface-card);
  --nav-bar-border:     var(--border-subtle);
  /* The active tab pill used to be --neutral-mid (gray/200, a cool blue-grey),
     which fought the warm beige palette on the app's most persistent element.
     Now a light olive surface with the olive text/icon tone made for it. */
  --nav-tab-bg-active:  var(--action-secondary);
  --nav-tab-fg-active:  var(--action-dark);
  --nav-tab-fg-default: var(--text-primary);

  /* ---- Icon Holder ---- */
  --icon-holder-bg-brand: var(--action-muted);   /* brand tint behind icon (olive/100) */
  --icon-holder-fg-brand: var(--text-brand);      /* icon color on brand bg (olive/600) */

  /* ---- List ---- */
  --list-remove-bg: var(--error-subtle);
  --list-remove-fg: var(--error-action-pressed);

  /* ---- Expense ---- */
  --expense-lent-fg:       var(--success-mid);
  --expense-lent-bg:       var(--success-surface);
  --expense-owe-fg:        var(--error-action-pressed);
  --expense-owe-bg:        var(--error-surface);
  --expense-settled-fg:    var(--text-tertiary);
  --expense-item-illus-bg: var(--surface-input);

  /* ---- Card / Group ---- */
  --card-group-owe-border:  var(--error-subtle);
  --card-group-lent-border: var(--success-subtle);
  --card-group-image-bg:    var(--surface-track);
  --card-group-lent-bg:     var(--success-surface);
  --card-group-owe-bg:      var(--error-surface);
  --card-create-bg:         var(--action-surface);
  --card-create-icon-bg:    var(--action-muted);
  --card-create-fg:         var(--action-mid);
  --card-create-border:     var(--action-secondary);

  /* ---- Heading ---- */
  --heading-fg: var(--text-primary);

  /* ---- Top App Bar ---- */
  --top-app-bar-bg:    var(--surface-bg);
  --top-app-bar-title: var(--action-strong);

  /* ---- Toast ---- */
  --toast-neutral-bg:     var(--neutral-surface);
  --toast-neutral-fg:     var(--neutral-fg);
  --toast-neutral-border: var(--neutral-border);
  --toast-brand-bg:       var(--action-muted);
  --toast-brand-fg:       var(--action-strong);
  --toast-brand-border:   var(--action-accent);
  --toast-success-bg:     var(--success-subtle);
  --toast-success-fg:     var(--success-strong);
  --toast-success-border: var(--success-border);
  --toast-error-bg:       var(--error-subtle);
  --toast-error-fg:       var(--error-fg);
  --toast-error-border:   var(--error-border);

  /* ---- Empty State ---- */
  --empty-state-illus-bg:  var(--action-surface);
  --empty-state-illus-fg:  var(--action-accent);
  --empty-state-title-fg:  var(--text-strong);
  --empty-state-body-fg:   var(--text-tertiary);

  /* ---- FAQ / Accordion ---- */
  --faq-border:      var(--border-default);
  --faq-question-fg: var(--text-strong);
  --faq-answer-fg:   var(--text-secondary);
  --faq-icon-fg:     var(--text-strong);

  /* ---- Amount Input ---- */
  --amount-input-bg:             var(--surface-input);
  --amount-input-bg-focused:     var(--surface-card);
  --amount-input-border:         var(--border-strong);
  --amount-input-border-focused: var(--action-primary);
  --amount-input-fg:             var(--text-primary);
  --amount-input-fg-disabled:    var(--text-secondary);
  --amount-input-icon-fg:        var(--text-secondary);

  /* ---- Avatar — XL (hero/profile feature) ---- */
  --avatar-xl-font-size:       30px;       /* component-specific spec value */
  --avatar-xl-letter-spacing:  -0.90px;    /* component-specific spec value */

  /* ---- Hero Section ----
     --surface-* / --avatar-* prefixes below are legacy: these three were
     defined in the L2 block until 2026-08-12, which made component-scoped
     values look like general semantics and inflated the L2 count. Relocated
     here (consumers: css/hero-section.css, css/avatar.css); names kept so no
     consumer had to change. The gradient stops and the avatar border now go
     through L2 instead of reaching for primitives directly. ---- */
  --surface-hero-gradient:        linear-gradient(160deg, var(--action-muted), var(--surface-input));
  --surface-hero-texture-overlay: rgba(255, 255, 255, 0.06);  /* component-specific spec value — no palette equivalent */
  --avatar-border-on-hero:        var(--surface-bg);

  --hero-section-texture-tile:     40px;
  --hero-section-emoji-size:       var(--font-size-40);
  --hero-section-badge-size:       26px;
  --hero-section-badge-bg:         var(--surface-card);
  --hero-section-badge-fg:         var(--text-secondary);

  /* ---- Hero Section — E8 fix (2026-08-06): band shortened + actions-top
     inset matched to the horizontal inset (now var(--spacing-16) directly
     in css/hero-section.css, no dedicated token). The old
     --hero-section-height / -tall / -short / -actions-top tokens this
     replaced were orphaned by the fix and have since been deleted
     (zero consumers reverified 2026-08-06 — see changelog). ---- */
  --hero-section-height-compact:        180px;  /* individual-detail */
  --hero-section-height-tall-compact:   220px;  /* group-detail */
  --hero-section-height-short-compact:  150px;  /* edit-group */

  /* ---- Button: Icon — Overlay variant (over hero-section) ---- */
  --icon-btn-overlay-size:         44px;
  --icon-btn-overlay-bg:           var(--surface-card);
  --icon-btn-overlay-fg:           var(--text-primary);
  --icon-btn-overlay-bg-pressed:   var(--surface-input);

  /* ---- Toggle Switch ----
     Disabled state uses --surface-track / --text-faint directly in
     css/toggle.css (warm-neutral generic semantics), not dedicated
     disabled tokens here — see css/toggle.css for the reasoning. The old
     --toggle-track-bg-disabled / --toggle-thumb-bg-disabled tokens that
     state used to reference had zero consumers and were deleted
     2026-08-06 (see changelog). ---- */
  --toggle-track-bg-off:        var(--border-default);
  --toggle-track-bg-on:         var(--action-primary);
  --toggle-thumb-bg:            var(--surface-card);
  --toggle-thumb-shadow:        var(--shadow-xs);

  /* ---- Settings: Section / Card / Row ---- */
  --settings-section-label-fg:           var(--text-tertiary);
  --settings-card-bg:                    var(--surface-card);
  --settings-card-border:                var(--border-subtle);
  --settings-row-divider:                var(--border-subtle);
  --settings-row-press-bg:               var(--surface-primary);
  --settings-row-icon-bg:                var(--surface-primary);
  --settings-row-icon-fg:                var(--text-brand);
  --settings-row-label-fg:               var(--text-primary);
  --settings-row-value-fg:               var(--text-tertiary);
  --settings-row-chevron-fg:             var(--text-faint);
  --settings-row-destructive-label-fg:   var(--error-fg);
  --settings-row-logout-label-fg:        var(--text-primary);

  /* ---- Detail Row ---- */
  --detail-row-bg:                    transparent;
  --detail-row-bg-pressed:            var(--surface-input);
  --detail-row-icon-bg:               var(--surface-input);
  --detail-row-icon-bg-selected:      var(--action-muted);
  --detail-row-icon-fg:               var(--text-primary);
  --detail-row-label-fg:              var(--text-tertiary);
  --detail-row-value-fg:              var(--text-primary);
  --detail-row-chevron-fg:            var(--text-placeholder);
  --detail-row-border:                var(--border-default);
  --detail-row-selected-bg:           var(--action-surface);
  --detail-row-selected-border:       var(--action-primary);
  --detail-row-radio-border:          var(--control-border-default);
  --detail-row-radio-border-selected: var(--control-border-selected);
  --detail-row-radio-bg-selected:     var(--control-bg-selected);
  --detail-row-radio-dot:             var(--control-dot);

  /* ---- Notes Card ---- */
  --notes-card-bg:                    var(--surface-input);
  --notes-card-bg-editable:           var(--input-bg);
  --notes-card-bg-editable-focused:   var(--input-bg-focused);
  --notes-card-border:                var(--input-border-default);
  --notes-card-border-focused:        var(--input-border-focused);
  --notes-card-label-fg:              var(--text-tertiary);
  --notes-card-text-fg:               var(--text-label);
  --notes-card-textarea-fg:           var(--input-fg-active);
  --notes-card-textarea-placeholder:  var(--input-fg-default);
  --notes-card-counter-fg:            var(--text-tertiary);
  --notes-card-counter-fg-warning:    var(--error-strong);

  /* ---- Summary Card ---- */
  --summary-card-bg:         var(--surface-card);
  --summary-card-border:     var(--border-subtle);
  --summary-card-avatar-bg:  var(--contact-avatar-bg);
  --summary-card-avatar-fg:  var(--contact-avatar-fg);
  --summary-card-name-fg:    var(--text-primary);
  --summary-card-amount-fg:  var(--text-primary);
  --summary-card-meta-fg:    var(--text-tertiary);

  /* ---- Success State ---- */
  --success-state-icon-bg:                 var(--type-chip-bg-on);
  --success-state-icon-fg:                 var(--text-primary);
  --success-state-icon-bg-confirmation:    var(--label-success-bg);
  --success-state-icon-fg-confirmation:    var(--expense-lent-fg);
  --success-state-heading-fg:              var(--top-app-bar-title);
  --success-state-heading-fg-confirmation: var(--expense-lent-fg);
  --success-state-body-fg:                 var(--input-label);
  --success-state-info-bg:                 var(--surface-card);
  --success-state-info-border:             var(--border-subtle);
  --success-state-meta-fg:                 var(--text-secondary);
  --success-state-timestamp-fg:            var(--contact-settled-fg);

  /* ---- Invite Banner ---- */
  --invite-banner-bg:           var(--container-bg-selected);
  --invite-banner-bg-pressed:   var(--type-chip-bg-on);
  --invite-banner-border:       var(--toast-brand-border);
  --invite-banner-icon-bg:      var(--type-chip-bg-on);
  --invite-banner-icon-fg:      var(--text-brand);
  --invite-banner-title-fg:     var(--btn-secondary-fg);
  --invite-banner-subtitle-fg:  var(--text-tertiary);
}

/* ---- tokens/spacing.css ---- */
/* ============================================
   Settlr Design System — Spacing Tokens
   ============================================ */

:root {
  --spacing-2:  2px;
  --spacing-4:  4px;
  --spacing-8:  8px;
  --spacing-12: 12px;
  --spacing-16: 16px;
  --spacing-20: 20px;
  --spacing-24: 24px;
  --spacing-32: 32px;
  --spacing-40: 40px;
  --spacing-48: 48px;
  --spacing-50: 50px;
  --spacing-64: 64px;
  --spacing-96: 96px;
}

/* ---- tokens/radius.css ---- */
/* ============================================
   Settlr Design System — Radius Tokens
   ============================================ */

:root {
  --radius-2:    2px;
  --radius-4:    4px;
  --radius-8:    8px;
  --radius-12:   12px;
  --radius-16:   16px;
  --radius-20:   20px;
  --radius-24:   24px;
  --radius-32:   32px;
  --radius-48:   48px;
  --radius-64:   64px;
  --radius-full: 9999px;
}

/* ---- tokens/typography.css ---- */
/* ============================================
   Settlr Design System — Typography Tokens

   Font FACES are not loaded here — every page brings its own:
   app screens link fonts.googleapis.com in their <head>; the
   playground links the self-hosted assets/fonts/fonts.css.
   (The old @import here double-loaded the CDN on every page.)
   ============================================ */

:root {
  /* ---- Font Families ---- */
  --font-display: 'Unbounded', sans-serif;
  --font-body:    'Plus Jakarta Sans', sans-serif;

  /* ---- Font Weights ---- */
  --weight-regular:  400;
  --weight-medium:   500;
  --weight-semibold: 600;
  --weight-bold:     700;
  --weight-black:    900;

  /* ---- Font Sizes ---- */
  /* 10px & 11px retired — smallest text size is now 12px (--font-size-12) */
  --font-size-12: 12px;
  --font-size-13: 13px;
  --font-size-14: 14px;
  --font-size-15: 15px;
  --font-size-16: 16px;
  --font-size-18: 18px;
  --font-size-20: 20px;
  --font-size-24: 24px;
  --font-size-28: 28px;
  --font-size-32: 32px;
  --font-size-36: 36px;
  --font-size-40: 40px;
  --font-size-48: 48px;

  /* ---- Line Heights ---- */
  --line-height-14: 14px;
  --line-height-16: 16px;
  --line-height-17: 17px;
  --line-height-18: 18px;
  --line-height-19: 19px;
  --line-height-20: 20px;
  --line-height-21: 21px;
  --line-height-22: 22px;
  --line-height-23: 23px;
  --line-height-24: 24px;
  --line-height-26: 26px;
  --line-height-27: 27px;
  --line-height-28: 28px;
  --line-height-30: 30px;
  --line-height-32: 32px;
  --line-height-34: 34px;
  --line-height-40: 40px;
  --line-height-44: 44px;
  --line-height-52: 52px;
}

/* ---- Display ---- */

/* used by: .top-app-bar__title (main screens) */
.text-display-sm {
  font-family: var(--font-display);
  font-size: var(--font-size-24);
  font-weight: var(--weight-bold);
  line-height: var(--line-height-28);
  letter-spacing: -0.96px;
}

/* used by: .amount-prefix, .amount-field (add-amount.html) */
.text-display-lg {
  font-family: var(--font-display);
  font-size: var(--font-size-40);
  font-weight: var(--weight-black);
  line-height: var(--line-height-44);
  letter-spacing: -1.60px;
}

/* ---- Heading ---- */

/* used by: .heading__title, .top-app-bar--bordered .top-app-bar__title */
.text-heading-md {
  font-family: var(--font-display);
  font-size: var(--font-size-20);
  font-weight: var(--weight-bold);
  line-height: var(--line-height-26);
  letter-spacing: -0.40px;
}

/* used by: .empty-state__title */
.text-heading-sm {
  font-family: var(--font-display);
  font-size: var(--font-size-18);
  font-weight: var(--weight-bold);
  line-height: var(--line-height-24);
  letter-spacing: -0.36px;
}

/* ---- Title ---- */

/* used by: .sheet__title */
.text-title-lg {
  font-family: var(--font-body);
  font-size: var(--font-size-18);
  font-weight: var(--weight-bold);
  line-height: var(--line-height-26);
  letter-spacing: -0.18px;
}

/* used by: .btn--lg, .chip--lg, .avatar--md */
.text-title-md {
  font-family: var(--font-body);
  font-size: var(--font-size-16);
  font-weight: var(--weight-bold);
  line-height: var(--line-height-24);
  letter-spacing: -0.16px;
}

/* used by: .btn--md, .chip--md, .segment-item, .toast__title, .person-item__name, .expense-item__name, .card-group__name, .settlement-item__name */
.text-title-sm {
  font-family: var(--font-body);
  font-size: var(--font-size-14);
  font-weight: var(--weight-semibold);
  line-height: var(--line-height-20);
  letter-spacing: 0;
}

/* used by: .btn--sm, .chip--sm, .currency-chip, .top-app-bar__text-btn */
.text-title-xs {
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-semibold);
  line-height: var(--line-height-18);
  letter-spacing: 0;
}

/* ---- Body ---- */

/* used by: .input-field__box input, .otp-digit, .checkbox-item__label, .radio-item__label, .radio-item-boxed__label */
.text-body-md {
  font-family: var(--font-body);
  font-size: var(--font-size-14);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-23);
  letter-spacing: 0;
}

/* used by: .toast__body, .radio-item__sub */
.text-body-sm {
  font-family: var(--font-body);
  font-size: var(--font-size-13);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-21);
  letter-spacing: 0;
}

/* used by: .person-item__sub, .expense-item__sub, .member-pill__name */
.text-body-xs {
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-19);
  letter-spacing: 0;
}

/* ---- Label ---- */

/* used by: .settlement-item__name */
.text-label-md {
  font-family: var(--font-body);
  font-size: var(--font-size-14);
  font-weight: var(--weight-semibold);
  line-height: normal;
  letter-spacing: 0;
}

/* used by: .input-field__label, .input-field__helper, .otp-group__label, .otp-group__helper, .avatar--xs, .avatar--sm, .expense-item__tag */
.text-label-xs {
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-medium);
  line-height: normal;
  letter-spacing: 0;
}

/* ---- Caption ---- */

/* used by: .bottom-nav__tab-label, .card-group__count, .expense-item__date */
.text-caption-sm {
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-17);
  letter-spacing: 0;
}

/* ---- Overline ---- */

/* used by: .section-date (layout.css) */
.text-overline-md {
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-medium);
  line-height: var(--line-height-14);
  letter-spacing: 1.76px;
  text-transform: uppercase;
}

/* ---- Amount ---- */

/* Large balance/amount displays (hero + entry screens). letter-spacing stays
   raw px per the type-system convention. */

/* used by: settle-amount .amount-display, edit-expense .amount-input-wrap (symbol + input) */
.text-amount-xl {
  font-family: var(--font-display);
  font-size: var(--font-size-48);
  font-weight: var(--weight-black);
  line-height: var(--line-height-52);
  letter-spacing: -1.92px;
}

/* used by: add-review .expense-hero__amount */
.text-amount-lg {
  font-family: var(--font-display);
  font-size: var(--font-size-36);
  font-weight: var(--weight-bold);
  line-height: var(--line-height-40);
  letter-spacing: -1.44px;
}

/* used by: group-detail / individual-detail .info-section__amount */
.text-amount-md {
  font-family: var(--font-display);
  font-size: var(--font-size-32);
  font-weight: var(--weight-black);
  line-height: var(--line-height-40);
  letter-spacing: -1.28px;
}

.text-amount-sm {
  font-family: var(--font-display);
  font-size: var(--font-size-16);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-20);
  letter-spacing: -0.32px;
}

/* used by: .card-group__amount, .settlement-item__amount */
.text-amount-xs {
  font-family: var(--font-display);
  font-size: var(--font-size-13);
  font-weight: var(--weight-semibold);
  line-height: var(--line-height-18);
  letter-spacing: 0;
}

/* ---- tokens/shadows.css ---- */
/* ============================================
   Settlr Design System — Shadow & Effect Tokens
   ============================================ */

:root {
  /* ---- Shadows ---- */
  --shadow-xs: 0 1px 2px rgba(14, 6, 24, 0.06);
  --shadow-sm: 0 2px 4px rgba(14, 6, 24, 0.08),
               0 1px 2px rgba(33, 0, 112, 0.04);
  --shadow-md: 0 4px 12px rgba(14, 6, 24, 0.10),
               0 2px 4px rgba(33, 0, 112, 0.06);
  --shadow-lg: 0 8px 24px rgba(14, 6, 24, 0.14),
               0 4px 8px rgba(33, 0, 112, 0.08);
  --shadow-xl: 0 16px 48px rgba(14, 6, 24, 0.20),
               0 8px 16px rgba(33, 0, 112, 0.12);

  /* ---- Border Widths ---- */
  --border-small:  1px;
  --border-medium: 1.5px;
  --border-large:  2px;

  /* ---- Icon Sizes ---- */
  --icon-xs: 12px;
  --icon-sm: 16px;
  --icon-md: 20px;
  --icon-lg: 24px;
  --icon-xl: 32px;

  /* ---- Opacity ---- */
  --opacity-subtle:   0.10;
  --opacity-medium:   0.25;
  --opacity-strong:   0.50;
  --opacity-disabled: 0.75;
  --opacity-backdrop: 0.90;
}

/* ---- tokens/motion.css ---- */
/* ============================================
   Settlr Motion Tokens
   Durations + easing curves for transitions and animations.
   Always pair with `prefers-reduced-motion: no-preference`
   guards in component CSS.
   ============================================ */

:root {
  /* ── Durations ──────────────────────────────────────────── */
  --duration-fast:     150ms;  /* tap feedback, chip toggle       */
  --duration-base:     250ms;  /* default UI transitions          */
  --duration-slow:     400ms;  /* sheet open, page transitions    */

  /* ── Easing curves ──────────────────────────────────────── */
  /* Standard "iOS-like" decelerating curve — most UI motion    */
  --ease-out:        cubic-bezier(0.16, 1, 0.3, 1);
  /* Accelerating — content leaving the screen                  */
  --ease-in:         cubic-bezier(0.7, 0, 0.84, 0);
  /* Subtle overshoot — playful press / FAB                     */
  --ease-spring:     cubic-bezier(0.34, 1.56, 0.64, 1);

  /* ── Common transition shortcuts ────────────────────────── */
  --transition-tap:   transform var(--duration-fast) var(--ease-out),
                      opacity   var(--duration-fast) var(--ease-out);

  /* ── Press scale (tap feedback) ─────────────────────────── */
  --press-scale:      0.97;
  --press-scale-sm:   0.94;   /* small targets like icon-btn, chip */
}

/* 5 tokens once lived here — --duration-instant, --duration-slower,
   --ease-in-out, --ease-linear, --transition-base — with zero verified
   references anywhere in css/, js/, or tokens/semantic.css. Parked
   (not deleted) in tokens/_archive-motion.css; that file is NOT
   imported by tokens/index.css. See its header for why and how to
   bring one back. */

/* ---- css/index.css ---- */


/* Layout & Utilities */

/* ---- css/layout.css ---- */
/* ============================================
   Settlr — Screen Layout & Utilities
   Standard mobile screen frame (393px iPhone 15 Pro)
   ============================================ */

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

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

/* ---- Base ---- */
html {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body {
  font-family: var(--font-body);
  background-color: var(--surface-card);
  color: var(--text-primary);
}

/* ---- Screen Frame ---- */
.screen {
  display: flex;
  flex-direction: column;
  width: 393px;
  min-height: 100vh;
  background-color: var(--surface-card);
  position: relative;
  margin: 0 auto;
}

/* ---- Content Area ---- */
.screen__content {
  flex: 1;
  display: flex;
  flex-direction: column;
  padding: 0 var(--spacing-16);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding-bottom: 80px; /* space for bottom nav */
}

/* ---- Section Spacing ---- */
.section {
  display: flex;
  flex-direction: column;
}

.section + .section {
  margin-top: var(--spacing-24);
}

.section--tight + .section--tight {
  margin-top: var(--spacing-16);
}

/* ---- Divider ---- */
.divider {
  height: var(--border-small);
  background-color: var(--contact-divider);
  width: 100%;
}

.divider--inset {
  margin-left: var(--spacing-16);
}

/* ---- Horizontal Scroll ---- */
.h-scroll {
  display: flex;
  gap: var(--spacing-12);
  overflow-x: auto;
  padding: 0 var(--spacing-16);
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}

.h-scroll::-webkit-scrollbar {
  display: none;
}

.h-scroll > * {
  scroll-snap-align: start;
  flex-shrink: 0;
}

/* ---- Grid (for cards) ---- */
.card-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--spacing-12);
  padding: 0 var(--spacing-16);
}

/* ---- Utilities ---- */
.text-center { text-align: center; }
.text-right  { text-align: right; }
.flex-1      { flex: 1; }
.w-full      { width: 100%; }
.truncate    { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.gap-2  { gap: var(--spacing-2); }
.gap-4  { gap: var(--spacing-4); }
.gap-8  { gap: var(--spacing-8); }
.gap-12 { gap: var(--spacing-12); }
.gap-16 { gap: var(--spacing-16); }
.gap-24 { gap: var(--spacing-24); }
.gap-32 { gap: var(--spacing-32); }

.p-4  { padding: var(--spacing-4); }
.p-8  { padding: var(--spacing-8); }
.p-12 { padding: var(--spacing-12); }
.p-16 { padding: var(--spacing-16); }
.px-16 { padding-left: var(--spacing-16); padding-right: var(--spacing-16); }
.py-12 { padding-top: var(--spacing-12); padding-bottom: var(--spacing-12); }

.mt-8  { margin-top: var(--spacing-8); }
.mt-16 { margin-top: var(--spacing-16); }
.mt-24 { margin-top: var(--spacing-24); }
.mt-32 { margin-top: var(--spacing-32); }
.mb-8  { margin-bottom: var(--spacing-8); }
.mb-16 { margin-bottom: var(--spacing-16); }

/* ── Date Heading ── */
.date-heading {
  padding: var(--spacing-8) var(--spacing-16) 0;
  width: 100%;
}

.date-heading__label {
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-17);
  color: var(--text-secondary);
}

/* ── Section Label — uppercase overline above a list group ── */
.section-label {
  padding: var(--spacing-12) var(--spacing-16) var(--spacing-8);
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-semibold);
  letter-spacing: 1.76px;
  text-transform: uppercase;
  color: var(--text-tertiary);
}

/* ---- css/index.css ---- */


/* App shell (compiled single-document app — scoped under .app-shell) */

/* ---- css/app-shell.css ---- */
/* ============================================
   Settlr — App Shell
   Layout primitives for the COMPILED single-document app (index.html):
   persistent chrome (status-bar + bottom-nav) + a stack of swappable views.

   Everything is scoped under `.app-shell` (carried by the shell <body>) so
   the 30+ standalone screens that still load css/index.css during migration
   are completely unaffected. The `.view*` classes are new, so they are safe
   to define unscoped.

   Replaces the per-screen inline shell rules (html/body flex column,
   `.content` scroll container) that were duplicated across screens.
   ============================================ */

/* ---- Shell frame ---- */
.app-shell {
  /* Self-contained height — no dependency on html/body sizing, and dvh
     accounts for mobile browser chrome. */
  height: 100dvh;
  display: flex;
  flex-direction: column;
  /* Full-bleed on a real phone (fills the device width). The 393px phone
     frame is only applied on larger screens (tablet/desktop) below. */
  width: 100%;
  max-width: 100%;
  margin: 0 auto;
  overflow: hidden;
  background: var(--surface-primary);
  /* Anchor absolutely-positioned descendants (e.g. an overlay status bar)
     to the shell column, not the viewport. */
  position: relative;
}

/* Centre the shell as a 393px phone frame only on wide viewports. */
@media (min-width: 480px) {
  .app-shell {
    max-width: 393px;
  }
}

/* The mock status bar is gone — the app relies on the OS status bar. Clear the
   notch / home indicator with safe-area insets so content isn't occluded.
   (Requires `viewport-fit=cover` on the viewport meta.) */
.app-shell {
  padding-top: env(safe-area-inset-top);
  padding-bottom: env(safe-area-inset-bottom);
}

/* ---- View host ---- */
/* Holds every inlined screen as a stacked `.view`; only one is shown. */
.app-shell__view-host {
  flex: 1;
  position: relative;
  overflow: hidden;
}

/* ---- Boot placeholder ---- */
/* Shown between first paint and SettlrRouterSPA.start(), which on a slow
   connection is a real interval — the view host renders an empty body until
   then. This is APP-SHELL CHROME, not a design-system component: it lives only
   in build-shell.py's generated <head>-to-boot window, the boot script removes
   it from the DOM the moment start() runs, and nothing else can ever reuse it.
   That is why it is deliberately NOT registered in .claude/indexes/code-index.json,
   .claude/indexes/screen-manifest.json or playground/registry.js. */
.app-shell__boot {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-16);
  padding: var(--spacing-24);
  background: var(--surface-primary);
  /* Start invisible and only appear after a beat, so a fast boot removes this
     before it was ever painted — no flash of placeholder. `forwards` holds the
     end state; opacity 0 holds through the delay. There is no fade here, only
     the delay, so this base rule is already reduced-motion-safe. */
  opacity: 0;
  animation: appShellBootIn 0s linear var(--duration-base) forwards;
}

@media (prefers-reduced-motion: no-preference) {
  .app-shell__boot {
    animation-duration: var(--duration-base);
    animation-timing-function: var(--ease-out);
  }
}

@keyframes appShellBootIn {
  to { opacity: 1; }
}

/* Neutral skeleton rows — route-agnostic, so this reads as "content loading"
   whichever view the shell is about to enter. --surface-track is the token the
   system already uses for illustration/slot placeholders. */
.app-shell__boot-bar {
  height: var(--spacing-16);
  border-radius: var(--radius-full);
  background: var(--surface-track);
}

.app-shell__boot-bar--sm { width: 40%; }
.app-shell__boot-bar--md { width: 65%; }

/* ---- View ---- */
/* Each former screen becomes a view: a flex column filling the host, with
   its own scrollable content region. Hidden views are display:none so they
   cost no layout and their `js-*` IDs never collide with the active view. */
.view {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.view[hidden] {
  display: none;
}

/* Canonical scrollable content region inside a view — replaces the
   per-screen inline `.content` block. The default bottom padding clears the
   floating bottom-nav dock (two 48px rows + 16px gap, composed from spacing
   tokens); views without the dock can override `--app-shell-content-pad`. */
.view__content {
  flex: 1;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding-bottom: var(--app-shell-content-pad, calc(var(--spacing-48) + var(--spacing-48) + var(--spacing-16)));
  background: var(--surface-primary);
}

/* ---- css/index.css ---- */


/* Components */

/* ---- css/icon-holder.css ---- */
/* ============================================
   Settlr — Icon Holder
   The standard wrapper for every Phosphor icon.
   Sizes: XS(12) SM(16) MD(20) LG(24) — match --icon-* tokens.
   Background: none (default) / brand (olive tint + pad + radius).
   ============================================ */

.icon-holder {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  color: currentColor;
  /* Default (no size modifier): track the surrounding font-size, so an
     upgraded icon matches whatever sizing its parent already applied. */
  width: 1em;
  height: 1em;
  vertical-align: middle;
}

/* Inner glyph fills the holder — Phosphor <i> is sized by font-size,
   inline <svg> stretches to the holder box. */
.icon-holder > i {
  font-size: inherit;
  line-height: 1;
}
.icon-holder > svg {
  width: 100%;
  height: 100%;
  display: block;
}

/* ---- Sizes ---- */
.icon-holder--xs { width: var(--icon-xs); height: var(--icon-xs); font-size: var(--icon-xs); }
.icon-holder--sm { width: var(--icon-sm); height: var(--icon-sm); font-size: var(--icon-sm); }
.icon-holder--md { width: var(--icon-md); height: var(--icon-md); font-size: var(--icon-md); }
.icon-holder--lg { width: var(--icon-lg); height: var(--icon-lg); font-size: var(--icon-lg); }

/* ---- Brand background — olive tint, 8px padding, 8px radius ---- */
.icon-holder--bg-brand {
  background-color: var(--icon-holder-bg-brand);
  color: var(--icon-holder-fg-brand);
  padding: var(--spacing-8);
  border-radius: var(--radius-8);
  box-sizing: content-box;
}

/* ---- Boolean toggles (instance-level) ----
   Components declare their icon-holder at source ALWAYS; a consuming instance
   adds `--hidden` to suppress the icon (e.g. a chevron-less detail row, an
   action-less top app bar) without removing the markup. `--disabled` keeps
   the icon visible but dims it and blocks interaction. */
.icon-holder--hidden {
  display: none;
}

.icon-holder--disabled {
  opacity: var(--opacity-disabled);
  pointer-events: none;
}

/* ---- css/button.css ---- */
/* ============================================
   Settlr — Button Component
   Variants: Primary, Secondary, Ghost, Destructive
   Sizes: SM, MD, LG
   States: Default, Pressed, Disabled
   ============================================ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: var(--radius-full);
  cursor: pointer;
  font-family: var(--font-body);
  transition: background-color 0.15s ease, opacity 0.15s ease;
  -webkit-tap-highlight-color: transparent;
  white-space: nowrap;
  text-decoration: none;
}

.btn:disabled,
.btn.is-disabled {
  opacity: var(--opacity-disabled);
  pointer-events: none;
}

/* ---- Sizes ---- */
.btn--sm {
  padding: var(--spacing-8) var(--spacing-12);
  font-size: var(--font-size-12);
  font-weight: var(--weight-semibold);
  line-height: var(--line-height-18);
}
.btn--sm .btn__icon { font-size: var(--icon-sm); }

.btn--md {
  padding: var(--spacing-12) var(--spacing-16);
  font-size: var(--font-size-14);
  font-weight: var(--weight-semibold);
  line-height: var(--line-height-20);
}
.btn--md .btn__icon { font-size: var(--icon-md); }

.btn--lg {
  padding: var(--spacing-12) var(--spacing-20);
  font-size: var(--font-size-16);
  font-weight: var(--weight-bold);
  line-height: var(--line-height-24);
  letter-spacing: -0.16px;
}
.btn--lg .btn__icon { font-size: var(--icon-lg); }

/* ---- Full width ---- */
.btn--full {
  width: 100%;
}

/* ---- Primary ---- */
.btn--primary {
  background-color: var(--btn-primary-bg);
  color: var(--btn-primary-fg);
}
.btn--primary:active,
.btn--primary.is-pressed {
  background-color: var(--btn-primary-bg-pressed);
}

/* ---- Secondary ---- */
.btn--secondary {
  background-color: var(--btn-secondary-bg);
  color: var(--btn-secondary-fg);
}
.btn--secondary:active,
.btn--secondary.is-pressed {
  background-color: var(--btn-secondary-bg-pressed);
}

/* ---- Ghost ---- */
.btn--ghost {
  background-color: transparent;
  color: var(--btn-ghost-fg);
  padding: 0;
}

/* ---- Destructive ---- */
.btn--destructive {
  background-color: var(--btn-destructive-bg);
  color: var(--btn-destructive-fg);
}
.btn--destructive:active,
.btn--destructive.is-pressed {
  background-color: var(--btn-destructive-bg-pressed);
}

/* ---- Inner layout ---- */
.btn__content {
  display: inline-flex;
  align-items: center;
}

.btn--sm .btn__content { gap: var(--spacing-4); }
.btn--md .btn__content { gap: var(--spacing-8); }
.btn--lg .btn__content { gap: var(--spacing-8); }

.btn__icon {
  flex-shrink: 0;
  color: currentColor;
  line-height: 1;
}

.btn__label {
  flex-shrink: 0;
}

/* ---- css/icon-button.css ---- */
/* ============================================
   Settlr — Icon Button Component
   Circular icon-only button.
   Variants: Default (neutral) · Primary · Destructive · Ghost · Surface · Overlay
   Sizes (fixed footprint): XS 32 · SM 40 · MD 44 · LG 52
   States: Default · Pressed · Disabled
   ============================================ */

.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  /* Default/neutral fill (--btn-icon-bg) sits at ~1.07:1 on --surface-bg /
     ~1.13:1 on --surface-card — the circle is imperceptible without a boundary
     (F5). A hairline border at --btn-icon-border (≥4.7:1) makes the button
     shape readable; color-variant rules below reset this back to none. */
  border: var(--border-small) solid var(--btn-icon-border);
  border-radius: var(--radius-full);
  background-color: var(--btn-icon-bg);
  color: var(--btn-icon-fg);
  cursor: pointer;
  transition: background-color 0.15s ease, opacity 0.15s ease;
  -webkit-tap-highlight-color: transparent;
}

/* ---- Default / neutral pressed ---- */
.icon-btn:active,
.icon-btn.is-pressed {
  background-color: var(--btn-icon-bg-pressed);
}

.icon-btn:disabled,
.icon-btn.is-disabled {
  opacity: var(--opacity-disabled);
  pointer-events: none;
}

/* ---- Icon inherits foreground ---- */
.icon-btn svg,
.icon-btn img {
  flex-shrink: 0;
  color: currentColor;
}

/* ---- Sizes (fixed footprint; padding-free, icon scales per size) ---- */
.icon-btn--xs,
.icon-btn--sm,
.icon-btn--md,
.icon-btn--lg { padding: 0; }

.icon-btn--xs { width: var(--icon-btn-size-xs); height: var(--icon-btn-size-xs); }
.icon-btn--sm { width: var(--icon-btn-size-sm); height: var(--icon-btn-size-sm); }
.icon-btn--md { width: var(--icon-btn-size-md); height: var(--icon-btn-size-md); }
.icon-btn--lg { width: var(--icon-btn-size-lg); height: var(--icon-btn-size-lg); }

.icon-btn--xs .icon-btn__icon,
.icon-btn--xs .icon-holder { width: var(--icon-sm); height: var(--icon-sm); }
.icon-btn--xs i { font-size: var(--icon-sm); }

.icon-btn--sm .icon-btn__icon,
.icon-btn--sm .icon-holder { width: var(--icon-md); height: var(--icon-md); }
.icon-btn--sm i { font-size: var(--icon-md); }

.icon-btn--md .icon-btn__icon,
.icon-btn--md .icon-holder { width: var(--icon-md); height: var(--icon-md); }
.icon-btn--md i { font-size: var(--icon-md); }

.icon-btn--lg .icon-btn__icon,
.icon-btn--lg .icon-holder { width: var(--icon-lg); height: var(--icon-lg); }
.icon-btn--lg i { font-size: var(--icon-lg); }

/* ---- Variant: Primary (olive filled) ---- */
.icon-btn--primary {
  background-color: var(--btn-icon-primary-bg);
  color: var(--btn-icon-primary-fg);
  border: none; /* filled bg already gives ample contrast; neutral-only boundary fix */
}
.icon-btn--primary:active,
.icon-btn--primary.is-pressed {
  background-color: var(--btn-icon-primary-bg-pressed);
}

/* ---- Variant: Destructive (coral) ---- */
.icon-btn--destructive {
  background-color: var(--btn-icon-destructive-bg);
  color: var(--btn-icon-destructive-fg);
  border: none; /* tinted bg already gives ample contrast; neutral-only boundary fix */
}
.icon-btn--destructive:active,
.icon-btn--destructive.is-pressed {
  background-color: var(--btn-icon-destructive-bg-pressed);
}

/* ---- Variant: Ghost (transparent; subtle pressed fill) ---- */
.icon-btn--ghost {
  background-color: transparent;
  color: var(--btn-icon-ghost-fg);
  border: none; /* deliberately boundary-less; neutral-only boundary fix */
}
.icon-btn--ghost:active,
.icon-btn--ghost.is-pressed {
  background-color: var(--btn-icon-ghost-bg-pressed);
}

/* ---- Variant: Surface (white + hairline border) ---- */
.icon-btn--surface {
  background-color: var(--btn-icon-surface-bg);
  color: var(--btn-icon-surface-fg);
  border: var(--border-small) solid var(--btn-icon-surface-border);
}
.icon-btn--surface:active,
.icon-btn--surface.is-pressed {
  background-color: var(--btn-icon-surface-bg-pressed);
}

/* ---- Variant: Overlay ----
   Used over .hero-section gradients (back, settings, edit).
   Fixed 44x44 footprint, semi-transparent surface, subtle shadow. */
.icon-btn--overlay {
  width: var(--icon-btn-overlay-size);
  height: var(--icon-btn-overlay-size);
  padding: 0;
  background-color: var(--icon-btn-overlay-bg);
  color: var(--icon-btn-overlay-fg);
  box-shadow: var(--shadow-sm);
  border: none; /* shadow + solid surface-card fill already separate it from the hero; neutral-only boundary fix */
}
.icon-btn--overlay .icon-btn__icon { width: var(--icon-md); height: var(--icon-md); }
.icon-btn--overlay i { font-size: var(--icon-md); }
.icon-btn--overlay:active,
.icon-btn--overlay.is-pressed { background-color: var(--icon-btn-overlay-bg-pressed); }

/* ---- css/chip.css ---- */
/* ============================================
   Settlr — Chip Component
   Sizes: SM, MD, LG
   States: On, Off
   ============================================ */

.chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-full);
  border-style: solid;
  border-width: var(--border-small);
  cursor: pointer;
  font-family: var(--font-body);
  transition: all 0.15s ease;
  -webkit-tap-highlight-color: transparent;
  white-space: nowrap;
}

/* ---- Off (default) ---- */
.chip {
  background-color: var(--chip-bg-off);
  border-color: var(--chip-border-off);
  color: var(--chip-fg-off);
}

/* ---- On (selected) ---- */
/* Canonical selected modifier is .chip--on (the legacy .is-active alias was
   dropped so People + Activity share one class; selected chips also set
   aria-pressed in JS for a color-independent cue). */
.chip--on {
  background-color: var(--chip-bg-on);
  border-color: var(--chip-border-on);
  color: var(--chip-fg-on);
}

/* ---- Icon inherits foreground ---- */
.chip svg,
.chip img {
  flex-shrink: 0;
  color: currentColor;
}

/* ---- Icon slot: wraps an .icon-holder, sized per chip size ----
   Markup: <span class="chip__icon"><span class="icon-holder">…</span></span>
   Sizing lives here (not on a size modifier in markup) so the holder always
   matches its chip's scale, mirroring the Icon Button pattern
   (css/icon-button.css .icon-btn--{size} .icon-holder). */
.chip__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.chip--sm .chip__icon .icon-holder { width: var(--icon-xs); height: var(--icon-xs); }
.chip--md .chip__icon .icon-holder { width: var(--icon-sm); height: var(--icon-sm); }
.chip--lg .chip__icon .icon-holder { width: var(--icon-md); height: var(--icon-md); }

/* ---- Sizes ---- */
.chip--sm {
  padding: var(--spacing-8) var(--spacing-12);
  gap: var(--spacing-4);
  font-size: var(--font-size-12);
  font-weight: var(--weight-semibold);
  line-height: var(--line-height-18);
}

.chip--md {
  padding: var(--spacing-8) var(--spacing-16);
  gap: var(--spacing-4);
  font-size: var(--font-size-14);
  font-weight: var(--weight-semibold);
  line-height: var(--line-height-20);
}

.chip--lg {
  padding: var(--spacing-12) var(--spacing-20);
  gap: var(--spacing-8);
  font-size: var(--font-size-16);
  font-weight: var(--weight-bold);
  line-height: var(--line-height-24);
  letter-spacing: -0.16px;
}

/* ---- css/type-chip.css ---- */
/* ============================================
   Settlr — Type Chip Component
   Group/expense type selection tile
   States: default (off), is-selected (on)
   ============================================ */

.type-chip {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--spacing-4);
  /* Fixed square footprint — was hug-content (width varied with the label,
     height varied between the illus/emoji slots), which read as an
     unbalanced, non-square tile in a 4-up grid. Width/height are pinned
     equal via the same spacing token so every tile is a true square
     regardless of label length or illustration slot used. Padding trimmed
     from --spacing-12 to --spacing-8 so the emoji/illus + 2-line label still
     fit inside the fixed box without overflowing it. */
  width: var(--spacing-64);
  height: var(--spacing-64);
  padding: var(--spacing-8);
  border-radius: var(--radius-12);
  border-style: solid;
  border-width: var(--border-small);
  background-color: var(--type-chip-bg-off);
  border-color: var(--type-chip-border-off);
  cursor: pointer;
  transition: all 0.15s ease;
  -webkit-tap-highlight-color: transparent;
  overflow: hidden;
  /* Self-align inside any grid/flex row (e.g. [data-view="create-group-name"]
     .type-grid's repeat(4, 1fr) columns, ~80px wide on a 393px screen) so the
     fixed 64px square centers in its track instead of stretching or
     left-packing against it. */
  justify-self: center;
}

/* ---- Selected ---- */
.type-chip.is-selected {
  background-color: var(--type-chip-bg-on);
  border-color: var(--type-chip-border-on);
  border-width: var(--border-large);
}

/* ---- Illustration placeholder ----
   Sized to --icon-lg (24px), matching .type-chip__emoji's glyph size, so
   both illustration slots occupy the same visual footprint inside the fixed
   square (previously --icon-xl/32px, which no longer fits the tightened
   padding of the fixed-square tile below --icon-xl + text). */
.type-chip__illus {
  width: var(--icon-lg);
  height: var(--icon-lg);
  border-radius: var(--radius-8);
  background-color: var(--type-chip-illus-placeholder-bg);
  flex-shrink: 0;
}

/* ---- Emoji illustration (fills the illustration slot in place of the box) ---- */
/* 24px glyph size is a documented emoji exception (no icon token drives emoji). */
.type-chip__emoji {
  /* duotone SVGs are fill=currentColor, so this slot must state its own
     foreground; an emoji ignored color. Safe to set here: .is-selected
     recolors only .type-chip__name, never the illustration slot.
     font-size stays load-bearing — a bare .icon-holder sizes itself off
     the inherited font-size. */
  color: var(--text-primary);
  font-size: 24px;
  line-height: 1;
  flex-shrink: 0;
}

/* ---- Label ---- */
.type-chip__name {
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-semibold);
  color: var(--type-chip-fg-off);
  text-align: center;
  line-height: var(--line-height-14);
  /* Fixed-square tile has no vertical room for a 2-line label once the
     illustration/emoji + gap + padding already fill the square (icon-lg 24
     + gap-4 + padding-8×2 leaves one line's worth of height) — long single-
     word labels like "Roommates" get a single-line ellipsis truncation
     instead, the standard pattern for a fixed-footprint icon tile (2-line
     wrap was tried first but a column-flex item shrinks/clips before
     wrapping in this engine rather than growing the tile). */
  width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.type-chip.is-selected .type-chip__name {
  color: var(--type-chip-fg-on);
}

/* ---- css/input-field.css ---- */
/* ============================================
   Settlr — Input Field Component
   States: Empty, Active, Filled, Error, Disabled
   ============================================ */

.input-field {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-4);
  width: 100%;
  font-family: var(--font-body);
}

/* ---- Label ---- */
.input-field__label {
  color: var(--input-label);
  font-size: var(--font-size-12);
  font-weight: var(--weight-medium);
}

/* ---- Input Container ---- */
.input-field__box {
  display: flex;
  align-items: center;
  gap: var(--spacing-4);
  padding: var(--spacing-12) var(--spacing-16);
  border-radius: var(--radius-12);
  border: var(--border-small) solid var(--input-border-default);
  background-color: var(--input-bg);
  transition: all 0.15s ease;
}

/* ---- Rectangular variant: light radius (instead of fully-rounded pill) ---- */
.input-field--rect .input-field__box,
.input-field--multiline .input-field__box {
  border-radius: var(--radius-12);
}

/* ---- Multiline (textarea) extends rect: top-aligned content ---- */
.input-field--multiline .input-field__box {
  align-items: flex-start;
}

.input-field__box input {
  flex: 1;
  border: none;
  outline: none;
  background: transparent;
  font-family: var(--font-body);
  color: var(--input-fg-active);
  font-size: var(--font-size-14);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-23);
}

/* ---- Multiline textarea control (typography supplied by a text-* class
   in markup; only the structural reset lives here) ---- */
.input-field__box textarea {
  flex: 1;
  border: none;
  outline: none;
  background: transparent;
  color: var(--input-fg-active);
  resize: none;
}

/* ---- Suffix icon (right-aligned action affordance, e.g. pencil) ---- */
.input-field__suffix-icon {
  flex-shrink: 0;
  font-size: var(--icon-md);
  color: var(--text-brand);
}

.input-field__box input::placeholder,
.input-field__box textarea::placeholder {
  color: var(--input-fg-default);
}

/* ---- Icons ---- */
.input-field__icon {
  flex-shrink: 0;
  width: var(--icon-md);
  height: var(--icon-md);
  color: var(--input-fg-default);
}

/* ---- Helper text ---- */
.input-field__helper {
  color: var(--input-helper);
  font-size: var(--font-size-12);
  font-weight: var(--weight-medium);
}

/* ---- States ---- */

/* Active / Focused */
.input-field--active .input-field__box,
.input-field__box:focus-within {
  background-color: var(--input-bg-focused);
  border-color: var(--input-border-focused);
}

/* Filled */
.input-field--filled .input-field__box {
  background-color: var(--input-bg);
  border-color: var(--input-border-default);
}
.input-field--filled .input-field__box input {
  color: var(--input-fg-active);
}

/* Error */
.input-field--error .input-field__box {
  background-color: var(--input-bg-error);
  border-color: var(--input-border-error);
}
.input-field--error .input-field__helper {
  color: var(--input-helper-error);
}

/* Disabled */
.input-field--disabled .input-field__box {
  background-color: var(--input-bg);
  border-color: transparent;
  opacity: var(--opacity-disabled);
  pointer-events: none;
}
.input-field--disabled .input-field__box input {
  color: var(--input-fg-default);
}

/* ---- css/labels.css ---- */
/* ============================================
   Settlr — Labels / Status Badge Component
   Status: Success, Warning, Error, Info, Default
   Sizes: SM, MD, LG
   Typography: all sizes are semibold (Label/Label-XS/MD/LG)
   ============================================ */

.label {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-full);
  font-family: var(--font-body);
  font-weight: var(--weight-semibold);
  line-height: normal;
  white-space: nowrap;
}

/* ---- Sizes ---- */
/* SM — Label/Label-XS: 10px semibold */
.label--sm {
  padding: var(--spacing-2) var(--spacing-8);
  gap: var(--spacing-2);
  font-size: var(--font-size-12);
}
.label--sm .label__icon { width: var(--icon-xs); height: var(--icon-xs); }

/* MD — Label/Label-MD: 14px semibold */
.label--md {
  padding: var(--spacing-4) var(--spacing-12);
  gap: var(--spacing-8);
  font-size: var(--font-size-14);
}
.label--md .label__icon { width: var(--icon-sm); height: var(--icon-sm); }

/* LG — Label/Label-LG: 16px semibold */
.label--lg {
  padding: var(--spacing-8) var(--spacing-16);
  gap: var(--spacing-8);
  font-size: var(--font-size-16);
}
.label--lg .label__icon { width: var(--icon-md); height: var(--icon-md); }

/* ---- Status: Success ---- */
.label--success {
  background-color: var(--label-success-bg);
  color: var(--label-success-fg);
}

/* ---- Status: Error ---- */
.label--error {
  background-color: var(--label-error-bg);
  color: var(--label-error-fg);
}

/* ---- Status: Warning ---- */
.label--warning {
  background-color: var(--label-warning-bg);
  color: var(--label-warning-fg);
}

/* ---- Status: Default ---- */
.label--default {
  background-color: var(--label-neutral-bg);
  color: var(--label-neutral-fg);
}

/* ---- Expense Status (text-only, no background) ---- */
/* Used inline in expense list items and contact list items */
/* Typography: Label/Label-XS — 10px semibold */
.label--expense {
  background: transparent;
  padding: 0;
  height: auto;
  font-size: var(--font-size-12);
  font-weight: var(--weight-semibold);
  line-height: normal;
  border-radius: 0;
}

.label--owe     { color: var(--expense-owe-fg); }
.label--lent    { color: var(--expense-lent-fg); }
.label--settled { color: var(--expense-settled-fg); }

/* ---- Balance Pill (standalone pill with bg + fg, not text-only) ---- */
.balance-pill--lent {
  background: var(--label-lent-bg);
  color: var(--label-lent-fg);
}
.balance-pill--owe {
  background: var(--label-owe-bg);
  color: var(--label-owe-fg);
}
.balance-pill--settled {
  background: var(--label-settled-bg);
  color: var(--label-settled-fg);
}

/* ---- css/avatar.css ---- */
/* ============================================
   Settlr — Avatar Component
   Figma: 84:5841
   Sizes: XS(20) SM(28) MD(40) LG(52) XL(96)
   Types: Initials / Photo
   ============================================ */

.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  overflow: hidden;
  font-family: var(--font-body);
  border-radius: var(--radius-full);
  text-decoration: none;
}

/* ---- Group avatar: rounded square (people = circle, groups = square) ---- */
.avatar--group {
  border-radius: var(--radius-16);
}
.avatar--group.avatar--xs,
.avatar--group.avatar--sm {
  border-radius: var(--radius-8);
}
.avatar--group.avatar--md,
.avatar--group.avatar--lg {
  border-radius: var(--radius-12);
}

/* ---- Types ---- */
.avatar--initials {
  background-color: var(--avatar-bg);
  color: var(--avatar-fg);
}

.avatar--photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ---- Outline: icon / placeholder avatar (surface bg + hairline border) ---- */
.avatar--outline {
  background: var(--surface-primary);
  border: var(--border-small) solid var(--border-default);
  color: var(--text-tertiary);
}

/* ---- Sizes ---- */
/* XS — 20px — text-label-xs: 10px medium */
.avatar--xs {
  width: 20px;
  height: 20px;
  font-size: var(--font-size-12);
  font-weight: var(--weight-medium);
}

/* SM — 28px — text-label-xs: 10px medium */
.avatar--sm {
  width: 28px;
  height: 28px;
  font-size: var(--font-size-12);
  font-weight: var(--weight-medium);
}

/* MD — 40px — Title/Title-MD: 16px bold */
.avatar--md {
  width: 40px;
  height: 40px;
  font-size: var(--font-size-16);
  font-weight: var(--weight-bold);
  letter-spacing: -0.16px;
}

/* LG — 52px — Title/Title-LG: 18px bold */
.avatar--lg {
  width: 52px;
  height: 52px;
  font-size: var(--font-size-18);
  font-weight: var(--weight-bold);
  letter-spacing: -0.18px;
}

/* XL — 96px — Hero/Profile feature avatar */
/* Uses display font (Unbounded) at 30px bold, ring border + shadow-md.
   Used as hero/profile centerpiece overlapping a hero-section. */
.avatar--xl {
  width: var(--spacing-96);
  height: var(--spacing-96);
  font-family: var(--font-display);
  font-size: var(--avatar-xl-font-size);
  font-weight: var(--weight-bold);
  letter-spacing: var(--avatar-xl-letter-spacing);
  border: var(--border-large) solid var(--avatar-border-on-hero);
  box-shadow: var(--shadow-md);
  background-clip: padding-box;
}

/* ============================================
   Member Pill / Avatar Chip
   Figma: 241:19122
   [Avatar SM] [Name] [optional ×]
   ============================================ */

.member-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-2);
  padding: var(--spacing-4) var(--spacing-8) var(--spacing-4) var(--spacing-4);
  border-radius: var(--radius-full);
  background-color: var(--member-pill-bg);
  border: var(--border-small) solid var(--border-default);
  white-space: nowrap;
}

/* Avatar inside pill uses contact-avatar tokens (olive/200 bg, olive/600 fg) */
.member-pill .avatar--initials {
  background-color: var(--contact-avatar-bg);
  color: var(--contact-avatar-fg);
}

.member-pill__name {
  color: var(--member-pill-fg);
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-19);
}

/* ---- Removable variant (with × icon) ---- */
.member-pill__remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--icon-xs);
  height: var(--icon-xs);
  color: var(--contact-subtext);
  flex-shrink: 0;
  cursor: pointer;
}

/* ---- css/avatar-stack.css ---- */
/* ============================================
   Settlr — Avatar Stack Component
   Figma: 260:6858 (Subtract boolean stacking)
   Sizes: XS, SM, MD, LG
   ============================================ */

/* ---- Stack container ---- */
.avatar-stack {
  display: flex;
  align-items: center;
}

/* ---- Stack item base ---- */
.avatar-stack__item,
.avatar-stack__overflow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  border-radius: var(--radius-full);
  font-family: var(--font-body);
  font-weight: var(--weight-semibold);
  /* Subtract boolean effect: ring matches container bg, overridable per context */
  box-shadow: 0 0 0 var(--border-large) var(--avatar-ring);
  position: relative;
}

.avatar-stack__item {
  background-color: var(--contact-avatar-bg);
  color: var(--contact-avatar-fg);
}

.avatar-stack__overflow {
  background-color: var(--avatar-stack-overflow-bg);
  color: var(--avatar-stack-overflow-fg);
}

/* ---- Sizes ---- */

/* XS — 20px */
.avatar-stack--xs .avatar-stack__item,
.avatar-stack--xs .avatar-stack__overflow {
  width: 20px;
  height: 20px;
  font-size: var(--font-size-12);
}
.avatar-stack--xs .avatar-stack__item + .avatar-stack__item,
.avatar-stack--xs .avatar-stack__overflow { margin-left: var(--avatar-stack-overlap-xs); }

/* SM — 28px */
.avatar-stack--sm .avatar-stack__item,
.avatar-stack--sm .avatar-stack__overflow {
  width: 28px;
  height: 28px;
  font-size: var(--font-size-12);
}
.avatar-stack--sm .avatar-stack__item + .avatar-stack__item,
.avatar-stack--sm .avatar-stack__overflow { margin-left: var(--avatar-stack-overlap-sm); }

/* MD — 40px */
.avatar-stack--md .avatar-stack__item,
.avatar-stack--md .avatar-stack__overflow {
  width: 40px;
  height: 40px;
  font-size: var(--font-size-14);
}
.avatar-stack--md .avatar-stack__item + .avatar-stack__item,
.avatar-stack--md .avatar-stack__overflow { margin-left: var(--avatar-stack-overlap-md); }

/* LG — 52px */
.avatar-stack--lg .avatar-stack__item,
.avatar-stack--lg .avatar-stack__overflow {
  width: 52px;
  height: 52px;
  font-size: var(--font-size-18);
}
.avatar-stack--lg .avatar-stack__item + .avatar-stack__item,
.avatar-stack--lg .avatar-stack__overflow { margin-left: var(--avatar-stack-overlap-lg); }

/* ---- With label ---- */
.avatar-stack-group {
  display: flex;
  align-items: center;
  gap: var(--spacing-8);
}

.avatar-stack-group__label {
  font-family: var(--font-body);
  font-size: var(--font-size-13);
  font-weight: var(--weight-medium);
  color: var(--avatar-stack-label-fg);
}

/* ---- css/radio.css ---- */
/* ============================================
   Settlr — Radio / Checkbox Controls
   States: Default, Selected, Disabled, Disabled-Selected
   ============================================ */

/* ---- Radio Control ---- */
.radio-control {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border-radius: var(--radius-full);
  border: var(--border-small) solid var(--control-border-default);
  background-color: var(--control-bg-default);
  cursor: pointer;
  transition: all 0.15s ease;
  flex-shrink: 0;
}

.radio-control__dot {
  width: var(--spacing-4);
  height: var(--spacing-4);
  border-radius: var(--radius-full);
  background-color: var(--control-dot);
  opacity: 0;
  transform: scale(0.4);
}

@media (prefers-reduced-motion: no-preference) {
  .radio-control__dot {
    transition: opacity var(--duration-fast) var(--ease-out),
                transform var(--duration-fast) var(--ease-spring);
  }
}

/* Selected */
.radio-control.is-selected,
.radio-control--selected {
  background-color: var(--control-bg-selected);
  border-color: var(--control-border-selected);
}
.radio-control.is-selected .radio-control__dot,
.radio-control--selected .radio-control__dot {
  opacity: 1;
  transform: scale(1);
}

/* Disabled */
.radio-control--disabled {
  background-color: var(--control-bg-disabled);
  border-color: var(--control-border-disabled);
  pointer-events: none;
}

/* Disabled Selected */
.radio-control--disabled-selected {
  background-color: var(--control-bg-disabled-selected);
  border-color: var(--control-border-disabled);
  pointer-events: none;
}
.radio-control--disabled-selected .radio-control__dot {
  opacity: 1;
}

/* ---- Radio Item ---- */
.radio-item {
  display: flex;
  align-items: center;
  gap: var(--spacing-8);
  padding: var(--spacing-4) 0;
  cursor: pointer;
}

.radio-item__label {
  color: var(--control-label);
  font-family: var(--font-body);
  font-size: var(--font-size-14);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-23);
}

.radio-item--disabled .radio-item__label {
  color: var(--control-label-disabled);
}

/* ---- Radio Item Boxed ---- */
.radio-item-boxed {
  display: flex;
  align-items: center;
  gap: var(--spacing-12);
  padding: var(--spacing-12) var(--spacing-16);
  border-radius: var(--radius-8);
  border: var(--border-small) solid var(--container-border-default);
  background-color: var(--container-bg-default);
  cursor: pointer;
  transition: all 0.15s ease;
}

.radio-item-boxed.is-selected,
.radio-item-boxed--selected {
  background-color: var(--container-bg-selected);
  border-color: var(--container-border-selected);
  border-width: var(--border-large);
}

.radio-item-boxed--disabled {
  border-color: var(--container-border-disabled);
  pointer-events: none;
}

.radio-item-boxed__text {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-2);
  flex: 1;
}

.radio-item-boxed__label {
  color: var(--control-label);
  font-family: var(--font-body);
  font-size: var(--font-size-14);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-23);
}

.radio-item-boxed__description {
  color: var(--control-description);
  font-family: var(--font-body);
  font-size: var(--font-size-13);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-21);
}

/* ---- Radio Item Boxed — Illustration Variant ---- */
/* Layout: [Illustration] [Text] [Radio Control] */
.radio-item-boxed--illus .radio-item-boxed__illus {
  width: var(--icon-xl);
  height: var(--icon-xl);
  border-radius: var(--radius-8);
  background-color: var(--radio-illus-placeholder-bg);
  flex-shrink: 0;
}

/* ---- css/checkbox.css ---- */
/* ============================================
   Settlr — Checkbox Control Component
   Figma: Forms / Checkbox / Control (268:8508)
   States: Default, Selected, Disabled, Disabled Selected
   Reuses --control-* tokens (shared with radio).
   ============================================ */

.checkbox-control {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border-radius: var(--radius-4);
  border: var(--border-small) solid var(--control-border-default);
  background-color: var(--control-bg-default);
  flex-shrink: 0;
  position: relative;
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease;
  -webkit-tap-highlight-color: transparent;
}

/* ---- Checkmark icon (hidden by default) ---- */
.checkbox-control__check {
  font-size: var(--font-size-12);
  line-height: 1;
  color: var(--control-dot);
  /* Always rendered but invisible until selected — enables animation */
  opacity: 0;
  transform: scale(0.6);
}

/* ---- Selected ---- */
.checkbox-control.is-selected {
  background-color: var(--control-bg-selected);
  border-color: var(--control-border-selected);
}

.checkbox-control.is-selected .checkbox-control__check {
  opacity: 1;
  transform: scale(1);
}

@media (prefers-reduced-motion: no-preference) {
  .checkbox-control__check {
    transition: transform var(--duration-fast) var(--ease-spring),
                opacity var(--duration-fast) var(--ease-out);
  }
}

/* ---- Disabled ---- */
.checkbox-control.is-disabled {
  background-color: var(--control-bg-disabled);
  border-color: var(--control-border-disabled);
  cursor: not-allowed;
  pointer-events: none;
}

/* ---- Disabled Selected ---- */
.checkbox-control.is-disabled.is-selected {
  background-color: var(--control-bg-disabled-selected);
  border-color: var(--control-border-disabled);
}

/* ============================================
   Checkbox Item (271:8528)
   Checkbox Control + label text, horizontal row
   ============================================ */

.checkbox-item {
  display: flex;
  align-items: center;
  gap: var(--spacing-8);
  padding: var(--spacing-4) 0;
  cursor: pointer;
}

.checkbox-item__label {
  color: var(--control-label);
  font-family: var(--font-body);
  font-size: var(--font-size-14);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-23);
}

.checkbox-item.is-disabled {
  cursor: not-allowed;
  pointer-events: none;
}

.checkbox-item.is-disabled .checkbox-item__label {
  color: var(--control-label-disabled);
}

/* ---- css/otp.css ---- */
/* ============================================
   Settlr — OTP Input Component
   States: Empty, Focus, Filled, Error, Disabled
   ============================================ */

/* ---- Single Digit ---- */
.otp-digit {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: var(--spacing-12);
  border-radius: var(--radius-8);
  border: var(--border-small) solid var(--input-border-default);
  background-color: var(--input-bg);
  font-family: var(--font-body);
  color: var(--input-fg-default);
  text-align: center;
  caret-color: var(--otp-caret);
  transition: all 0.15s ease;
  font-size: var(--font-size-14);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-23);
}

.otp-digit::placeholder {
  color: var(--input-fg-default);
}

/* Focus — mirrors Input Field's active treatment (css/input-field.css
   .input-field--active .input-field__box): background + border COLOR change
   only. Border-width previously jumped --border-small → --border-large on
   focus; since box-sizing is border-box (css/layout.css reset) that shrank
   the content box on a fixed 44×44 digit, nudging the centered glyph by a
   pixel and reading as a "messed up" jitter on focus. Keeping border-width
   constant across all states removes that shift. */
.otp-digit:focus,
.otp-digit--focus {
  background-color: var(--input-bg-focused);
  border-color: var(--input-border-focused);
  outline: none;
}

/* Filled */
.otp-digit--filled {
  background-color: var(--input-bg);
  border-color: var(--input-border-default);
  color: var(--input-fg-active);
}

/* Error */
.otp-digit--error {
  background-color: var(--input-bg-error);
  border-color: var(--input-border-error);
}

/* Disabled */
.otp-digit--disabled {
  opacity: var(--opacity-disabled);
  pointer-events: none;
}

/* ---- 6-Digit Group ---- */
.otp-group {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-4);
  width: 100%;
}

.otp-group__label {
  color: var(--input-label);
  font-size: var(--font-size-12);
  font-weight: var(--weight-medium);
}

.otp-group__digits {
  display: flex;
  gap: var(--spacing-8);
  justify-content: space-between;
}

.otp-group__helper {
  color: var(--input-helper);
  font-size: var(--font-size-12);
  font-weight: var(--weight-medium);
}

.otp-group--error .otp-group__helper {
  color: var(--input-helper-error);
}

/* ---- css/list-items.css ---- */
/* ============================================
   Settlr — List Item Components
   Person Item: Action variants
   Expense Item: State × Balance variants
   ============================================ */

/* ---- Person Item ---- */
.person-item {
  display: flex;
  align-items: center;
  gap: var(--spacing-12);
  padding: var(--spacing-12) var(--spacing-16);
  background-color: var(--contact-bg-default);
  border-bottom: var(--border-small) solid var(--contact-divider);
  cursor: pointer;
  transition: background-color 0.15s ease;
  -webkit-tap-highlight-color: transparent;
  text-decoration: none;
}

.person-item.is-selected {
  background-color: var(--contact-bg-selected);
}

.person-item__avatar {
  flex-shrink: 0;
}

.person-item__text {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-width: 0;
}

.person-item__name {
  color: var(--contact-name);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: var(--font-body);
  font-size: var(--font-size-14);
  font-weight: var(--weight-semibold);
  line-height: var(--line-height-20);
}

.person-item__subtext {
  color: var(--contact-subtext);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-19);
}

/* Group emoji tile — reuses same pattern as expense-item__illustration */
.person-item__group-icon {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-8);
  background-color: var(--expense-item-illus-bg);
  /* see .expense-item__illustration — duotone SVG needs an explicit fg */
  color: var(--text-primary);
  font-size: var(--font-size-20);
  overflow: hidden;
}

.person-item__group-icon img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.person-item__action {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  color: var(--contact-icon);
}

.person-item__action-icon {
  width: var(--icon-lg);
  height: var(--icon-lg);
}

/* ---- Person Item: Balance (Lent / Owe / Settled) ---- */
.person-item__balance {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  flex-shrink: 0;
  gap: var(--spacing-2);
}

.person-item__balance-label {
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-19);
  color: var(--contact-subtext);
}

.person-item__balance-amount {
  font-family: var(--font-display);
  font-size: var(--font-size-13);
  font-weight: var(--weight-semibold);
  line-height: var(--line-height-18);
}

.person-item--lent     .person-item__balance-amount { color: var(--expense-lent-fg); }
.person-item--owe      .person-item__balance-amount { color: var(--expense-owe-fg); }
.person-item--settled  .person-item__balance-amount { color: var(--contact-settled-fg); }

/* ---- Person Item: Amount Input (split row) ---- */
.person-item__input-box {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--spacing-4);
  width: 120px;
  height: 40px;
  flex-shrink: 0;
  padding: var(--spacing-8);
  background-color: var(--input-bg);
  border: var(--border-small) solid var(--input-border-default);
  border-radius: var(--radius-8);
  font-family: var(--font-body);
  font-size: var(--font-size-14);
  font-weight: var(--weight-regular);
  color: var(--input-fg-default);
}

.person-item__input-icon {
  width: var(--icon-md);
  height: var(--icon-md);
  flex-shrink: 0;
  color: var(--contact-icon);
}

/* ---- Expense Item ---- */
.expense-item {
  display: flex;
  align-items: center;
  gap: var(--spacing-12);
  padding: var(--spacing-12) var(--spacing-16);
  background-color: var(--contact-bg-default);
  border-bottom: var(--border-small) solid var(--contact-divider);
  cursor: pointer;
  transition: background-color 0.15s ease;
  -webkit-tap-highlight-color: transparent;
  text-decoration: none;
}

.expense-item.is-pressed {
  background-color: var(--contact-bg-selected);
}

.expense-item__illustration {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-8);
  background-color: var(--expense-item-illus-bg);
  /* duotone SVGs are fill=currentColor (solid path + 0.2-opacity backdrop),
     so the tile must state its own foreground — an emoji ignored color, an
     inline icon would otherwise inherit body text colour. font-size stays:
     a bare .icon-holder sizes itself off the inherited font-size. */
  color: var(--text-primary);
  font-size: var(--font-size-20);
}

.expense-item__text {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-width: 0;
}

.expense-item__title {
  color: var(--contact-name);
  font-family: var(--font-body);
  font-size: var(--font-size-14);
  font-weight: var(--weight-semibold);
  line-height: var(--line-height-20);
}

.expense-item__subtitle {
  color: var(--contact-subtext);
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-19);
}

/* Right-side column: label on top, amount below */
.expense-item__right {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  flex-shrink: 0;
  gap: var(--spacing-2);
}/* Label text above the amount (e.g. "lent", "owe") */
.expense-item__label {
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-medium);
}
.expense-item__label--lent { color: var(--expense-lent-fg); }
.expense-item__label--owe  { color: var(--expense-owe-fg); }

/* Amount/Amount-XS: the monetary value */
.expense-item__amount {
  font-family: var(--font-display);
  font-size: var(--font-size-13);
  font-weight: var(--weight-semibold);
  line-height: var(--line-height-18);
  letter-spacing: -0.32px;
  text-align: right;
  white-space: nowrap;
}

.expense-item__amount--lent { color: var(--expense-lent-fg); }
.expense-item__amount--owe  { color: var(--expense-owe-fg); }

/* Legacy: amount-value + badge (used in other screens) */
.expense-item__amount-value {
  font-family: var(--font-display);
  font-size: var(--font-size-13);
  font-weight: var(--weight-semibold);
  line-height: var(--line-height-18);
}

.expense-item__badge {
  display: inline-flex;
  padding: var(--spacing-2) var(--spacing-8);
  border-radius: var(--radius-full);
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-medium);
}

/* Lent */
.expense-item--lent .expense-item__amount-value { color: var(--expense-lent-fg); }
.expense-item--lent .expense-item__badge {
  background-color: var(--expense-lent-bg);
  color: var(--expense-lent-fg);
}

/* Owe */
.expense-item--owe .expense-item__amount-value { color: var(--expense-owe-fg); }
.expense-item--owe .expense-item__badge {
  background-color: var(--expense-owe-bg);
  color: var(--expense-owe-fg);
}

/* ---- Comment (optional) ---- */
.expense-item__comment {
  color: var(--contact-subtext);
  margin-top: var(--spacing-2);
}

/* ---- css/txn-item.css ---- */
/* ============================================
   Settlr — Transaction Item
   Shared list row produced by Render.txnItem, used by the group-detail and
   individual-detail "Transactions" tabs. Promoted from two identical per-screen
   scoped copies. The illustration radius is standardized to --radius-8 to match
   expense-item (the dominant list-row illustration); individual-detail's former
   --radius-12 was the outlier.
   ============================================ */

.txn-item {
  display: flex;
  align-items: center;
  gap: var(--spacing-12);
  padding: var(--spacing-12) var(--spacing-16);
  background: transparent;
  border-bottom: var(--border-small) solid var(--border-subtle);
  cursor: pointer;
  transition: background-color 0.15s ease;
  -webkit-tap-highlight-color: transparent;
  text-decoration: none;
}
.txn-item:active { background: var(--contact-bg-selected); }

/* Emoji/illustration tile. 48px has no spacing token (flagged), kept exact. */
.txn-item__illus {
  width: 48px;
  height: 48px;
  border-radius: var(--radius-8);
  background: var(--btn-icon-bg);
  /* duotone SVGs are fill=currentColor, so the tile must state its own
     foreground; an emoji ignored color. font-size stays load-bearing —
     a bare .icon-holder sizes itself off the inherited font-size. */
  color: var(--text-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--font-size-20);
  flex-shrink: 0;
}

.txn-item__text {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-width: 0;
}
/* name — text style via .text-title-sm in Render.txnItem markup */
.txn-item__name {
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* subtitle — text style via .text-body-xs in Render.txnItem markup */
.txn-item__subtitle {
  color: var(--text-tertiary);
}

.txn-item__right {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  flex-shrink: 0;
  gap: var(--spacing-2);
}
/* badge — text style via .text-label-xs in markup; color via direction modifier */
/* amount — Render.txnItem markup has no text-* class; type kept here (no token) */
.txn-item__amount {
  font-family: var(--font-display);
  font-size: var(--font-size-16);
  font-weight: var(--weight-bold);
  line-height: var(--line-height-20);
}

.txn-item--lent .txn-item__badge,
.txn-item--lent .txn-item__amount { color: var(--expense-lent-fg); }
.txn-item--owe .txn-item__badge,
.txn-item--owe .txn-item__amount { color: var(--expense-owe-fg); }
.txn-item--settled .txn-item__badge,
.txn-item--settled .txn-item__amount { color: var(--text-tertiary); }

/* ---- css/balance-row.css ---- */
/* ============================================
   Settlr — Balance Row
   Shared list row produced by Render.balanceRow, used by the group-detail
   "Balances" tab. Promoted verbatim from the [data-view="group-detail"]
   scoped block (the [data-view] prefix was dropped — zero visual change).
   Property values are kept identical, including the non-token 44px avatar
   tile and the kept display font props on __amount (these were flagged in
   the original as having no matching text-* token).
   ============================================ */

.balance-row {
  display: flex;
  align-items: center;
  gap: var(--spacing-12);
  padding: var(--spacing-12) var(--spacing-16);
  border-bottom: var(--border-small) solid var(--border-subtle);
}
.balance-row__avatar {
  width: 44px;
  height: 44px;
  border-radius: var(--radius-full);
  background: var(--contact-avatar-bg);
  color: var(--contact-avatar-fg);
  font-family: var(--font-body);
  font-size: var(--font-size-14);
  font-weight: var(--weight-semibold);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
/* text — text style via .text-body-md in Render.balanceRow markup
   (snaps 14/20 → 14/23 line-height; same delta accepted in expense-detail) */
.balance-row__text {
  flex: 1;
  color: var(--text-secondary);
}
.balance-row__text strong { color: var(--text-primary); font-weight: var(--weight-semibold); }
/* amount — Render.balanceRow markup carries .text-amount-xs (13/18 semibold).
   Original inline was display 14px bold; keep the original type here so the
   text-amount-xs class does not change the look. Flagged. */
.balance-row__amount {
  flex-shrink: 0;
  font-family: var(--font-display);
  font-size: var(--font-size-14);
  font-weight: var(--weight-bold);
}
.balance-row__amount--lent { color: var(--expense-lent-fg); }
.balance-row__amount--owe  { color: var(--expense-owe-fg); }

/* ---- css/group-row.css ---- */
/* ============================================
   Settlr — Group Row
   Shared list row produced by Render.groupRow, used by the individual-detail
   "Common Groups" tab. Promoted verbatim from the
   [data-view="individual-detail"] scoped block (the [data-view] prefix was
   dropped — zero visual change). Property values are kept identical, including
   the non-token 44px icon tile and the kept display font props on __meta /
   __amount (these were flagged in the original as having no matching text-*
   token). The :active tap feedback and the .avatar-stack ring override are
   relocated unscoped as well.
   ============================================ */

.group-row {
  display: flex;
  align-items: center;
  gap: var(--spacing-12);
  padding: var(--spacing-12) var(--spacing-16);
  border-bottom: var(--border-small) solid var(--border-subtle);
  cursor: pointer;
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
}
.group-row:active { background: var(--contact-bg-selected); }
.group-row__icon {
  width: 44px;
  height: 44px;
  border-radius: var(--radius-12);
  background: var(--card-create-icon-bg);
  /* duotone SVGs are fill=currentColor, so the tile must state its own
     foreground; an emoji ignored color. font-size stays load-bearing —
     a bare .icon-holder sizes itself off the inherited font-size. */
  color: var(--text-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--font-size-20);
  flex-shrink: 0;
  overflow: hidden;
}
.group-row__icon img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.group-row__text {
  flex: 1;
  min-width: 0;
}
/* name — text style via .text-title-sm in Render.groupRow markup */
.group-row__name {
  color: var(--text-primary);
}
/* meta — no .group-row__meta in current Render.groupRow markup (it renders an
   avatar-stack instead); kept for parity with the original inline rule. */
.group-row__meta {
  font-family: var(--font-body);
  font-size: var(--font-size-13);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-18);
  color: var(--text-tertiary);
}
.group-row .avatar-stack { --avatar-ring: var(--surface-primary); }
/* amount — text style via .text-amount-xs in Render.groupRow markup.
   Original inline was display 14px bold; keep the original type here so the
   text-amount-xs class does not change the look. Flagged. */
.group-row__amount {
  font-family: var(--font-display);
  font-size: var(--font-size-14);
  font-weight: var(--weight-bold);
  flex-shrink: 0;
}
.group-row__amount--lent { color: var(--expense-lent-fg); }
.group-row__amount--owe  { color: var(--expense-owe-fg); }
.group-row__chevron {
  width: var(--icon-sm);
  height: var(--icon-sm);
  color: var(--text-tertiary);
  flex-shrink: 0;
}

/* ---- css/cards.css ---- */
/* ============================================
   Settlr — Card Components
   Group Item: Balance=Lent/Owe
   Create New Group
   ============================================ */

/* ---- Group Item Card ---- */
.card-group {
  display: flex;
  flex-direction: column;
  width: 161px;
  height: 206px;
  border-radius: var(--radius-8);
  overflow: hidden;
  border: var(--border-small) solid var(--border-subtle);
  background-color: var(--surface-card);
  color: var(--text-primary);
  text-decoration: none;
}

.card-group--lent {
  border-color: var(--card-group-lent-border);
}

.card-group--owe {
  border-color: var(--card-group-owe-border);
}

.card-group:focus,
.card-group:focus-visible {
  outline: none;
}

.card-group__image {
  width: 100%;
  height: 96px;
  background-color: var(--card-group-image-bg);
  object-fit: cover;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 40px;
  line-height: 1;
  overflow: hidden;
}

.card-group__image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.card-group__content,
.card-group__info {
  display: flex;
  flex-direction: column;
  padding: var(--spacing-12);
  flex: 1;
}

.card-group__name {
  color: var(--contact-name);
  font-family: var(--font-body);
  font-size: var(--font-size-14);
  font-weight: var(--weight-semibold);
  line-height: var(--line-height-20);
}

.card-group__members,
.card-group__subtitle {
  color: var(--contact-subtext);
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-17);
}

.card-group__amount {
  margin-top: auto;
  font-family: var(--font-display);
  font-size: var(--font-size-13);
  font-weight: var(--weight-semibold);
  line-height: var(--line-height-18);
}

.card-group--lent .card-group__amount { color: var(--expense-lent-fg); }
.card-group--owe .card-group__amount { color: var(--expense-owe-fg); }

/* Colored info/content section backgrounds per Figma */
.card-group--lent .card-group__content,
.card-group--lent .card-group__info {
  background-color: var(--card-group-lent-bg);
}

.card-group--owe .card-group__content,
.card-group--owe .card-group__info {
  background-color: var(--card-group-owe-bg);
}

/* Balance wrapper inside info */
.card-group__balance {
  display: flex;
  flex-direction: column;
  margin-top: auto;
}

.card-group__amount--lent { color: var(--expense-lent-fg); }
.card-group__amount--owe  { color: var(--expense-owe-fg); }

/* ---- Create New Group Card ---- */
.card-create {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 160px;
  height: 200px;
  gap: var(--spacing-12);
  border-radius: var(--radius-8);
  background-color: var(--card-create-bg);
  border: var(--border-medium) dashed var(--card-create-border);
  cursor: pointer;
  transition: opacity 0.15s ease;
}

.card-create__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: var(--radius-full);
  background-color: var(--card-create-icon-bg);
  color: var(--card-create-fg);
}

.card-create__icon svg {
  width: var(--icon-lg);
  height: var(--icon-lg);
}

.card-create__text {
  font-family: var(--font-body);
  font-size: var(--font-size-14);
  font-weight: var(--weight-semibold);
  color: var(--card-create-fg);
  text-align: center;
}

.card-create:focus,
.card-create:focus-visible {
  outline: none;
}

/* ---- css/navigation.css ---- */
/* ============================================
   Settlr — Navigation Components
   Bottom Nav Bar, Segment Control
   ============================================ */

/* ---- Bottom Nav Bar (floating pill wrapper) ---- */
.bottom-nav-bar {
  position: fixed;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  /* Full-bleed on phones; frame to 393px only on desktop — mirrors
     .app-shell / .screen-footer so the nav spans the same width as the
     content above it on >393px phones like Pro Max, and stays aligned
     with the app frame on desktop. */
  width: 100%;
  max-width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--spacing-16) var(--spacing-16) var(--spacing-24);
  z-index: 100;
  pointer-events: none;
}

/* Centre the nav in the 393px phone frame only on wide viewports —
   matching the .app-shell breakpoint so the two stay aligned. */
@media (min-width: 480px) {
  .bottom-nav-bar {
    max-width: 393px;
  }
}

.bottom-nav-bar > * {
  pointer-events: auto;
}

/* ---- Nav Pill ---- */
.bottom-nav {
  position: relative;
  display: flex;
  align-items: center;
  flex: 1;
  gap: var(--spacing-8);
  padding: var(--spacing-4);
  border-radius: var(--radius-full);
  background: var(--nav-bar-bg);
  box-shadow: var(--shadow-sm);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
}

/* ---- Nav Tab ---- */
.bottom-nav__tab {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 1;
  height: var(--spacing-48);
  border-radius: var(--radius-full);
  text-decoration: none;
  color: var(--nav-tab-fg-default);
  transition: background-color 0.15s ease;
  -webkit-tap-highlight-color: transparent;
  border: none;
  background: transparent;
}

.bottom-nav__tab.is-active {
  background: var(--nav-tab-bg-active);
  color: var(--nav-tab-fg-active);
}

/* ---- Sliding active indicator (pill that slides between tabs) ----
   js/bottom-nav-slider.js injects .bottom-nav__indicator and positions it
   over the active tab; it slides on active change. The per-tab .is-active
   background is suppressed once the slider is wired (the pill provides it). */
.bottom-nav__indicator {
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
  border-radius: var(--radius-full);
  background: var(--nav-tab-bg-active);
  pointer-events: none;
  z-index: 0;
  opacity: 0;
}
.bottom-nav[data-slider-init="1"] .bottom-nav__tab.is-active {
  background: transparent;
}

@media (prefers-reduced-motion: no-preference) {
  .bottom-nav__indicator {
    transition: transform var(--duration-base) var(--ease-out),
                width var(--duration-base) var(--ease-out),
                height var(--duration-base) var(--ease-out);
  }
  /* Tap feedback — scale the icon+label cluster, not the full-width tab */
  .bottom-nav__tab-content {
    transition: transform var(--duration-fast) var(--ease-out);
    will-change: transform;
  }
  .bottom-nav__tab:active .bottom-nav__tab-content {
    transform: scale(var(--press-scale-sm));
  }
}

.bottom-nav__tab-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--spacing-4);
}

.bottom-nav__tab-icon {
  width: var(--icon-md);
  height: var(--icon-md);
  display: flex;
  align-items: center;
  justify-content: center;
}

.bottom-nav__tab-icon i {
  font-size: var(--icon-md);
  line-height: 1;
}

.bottom-nav__tab-label {
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-17);
}



/* ---- Segment Control (Container) ---- */
.segment-control {
  position: relative;
  display: flex;
  gap: var(--spacing-4);
  padding: var(--spacing-2);
  border-radius: var(--radius-12);
  background-color: var(--tab-bg-track);
  width: 100%;
}

/* Animated sliding pill — positioned by js/segment-slider.js.
   Items keep their own .is-active styles as fallback. */
.segment-control__pill {
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
  border-radius: var(--radius-8);
  background-color: var(--tab-bg-active);
  box-shadow: 0 0 0 var(--border-small) var(--tab-border-active);
  pointer-events: none;
  z-index: 0;
  opacity: 0;
}

@media (prefers-reduced-motion: no-preference) {
  .segment-control__pill {
    transition: transform var(--duration-base) var(--ease-out),
                width var(--duration-base) var(--ease-out),
                height var(--duration-base) var(--ease-out);
  }
}

/* Items sit above the pill so text stays clickable */
.segment-control > .segment-item {
  position: relative;
  z-index: 1;
}

/* When the JS slider is active, hide each item's individual active bg
   so only the moving pill shows. */
.segment-control[data-slider-init="1"] .segment-item.is-active,
.segment-control[data-slider-init="1"] .segment-item--active {
  background-color: transparent;
  box-shadow: none;
}

/* ---- Segment Item ---- */
.segment-item {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--spacing-8);
  flex: 1;
  padding: var(--spacing-8) var(--spacing-12);
  border-radius: 0;
  background: transparent;
  border: none;
  cursor: pointer;
  color: var(--tab-fg-default);
  transition: all 0.2s ease;
  -webkit-tap-highlight-color: transparent;
  font-family: var(--font-body);
  font-size: var(--font-size-14);
  font-weight: var(--weight-semibold);
  line-height: var(--line-height-20);
}

.segment-item.is-active,
.segment-item--active {
  background-color: var(--tab-bg-active);
  border-radius: var(--radius-8);
  color: var(--tab-fg-active);
  box-shadow: 0 0 0 var(--border-small) var(--tab-border-active);
}

.segment-item--disabled {
  color: var(--tab-fg-disabled);
  pointer-events: none;
}

/* ---- Step Progress ---- */
.step-progress {
  display: flex;
  gap: var(--spacing-4);
  justify-content: center;
  padding: var(--spacing-8) var(--spacing-16);
  flex-shrink: 0;
  background: var(--surface-primary);
}

.step-progress__step {
  width: var(--spacing-24);
  height: var(--spacing-4);
  border-radius: var(--radius-full);
  background: var(--border-default);
}

.step-progress__step--active {
  background: var(--action-primary);
}

/* ---- css/heading.css ---- */
/* ============================================
   Settlr — Heading Component
   ============================================ */

.heading {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--spacing-12) var(--spacing-16);
  width: 100%;
}

.heading__title {
  color: var(--heading-fg);
  font-family: var(--font-display);
  font-size: var(--font-size-20);
  font-weight: var(--weight-bold);
  line-height: var(--line-height-26);
  letter-spacing: -0.40px;
}

.heading__action {
  flex-shrink: 0;
}

/* ---- css/top-app-bar.css ---- */
/* ============================================
   Settlr — Top App Bar Component
   Figma: node 206:15660
   ============================================ */

.top-app-bar {
  display: flex;
  align-items: center;
  gap: var(--spacing-8);
  padding: var(--spacing-8) var(--spacing-16);
  min-height: var(--spacing-50);
  background: var(--top-app-bar-bg);
  width: 100%;
  flex-shrink: 0;
}

/* Title — left-aligned, fills remaining space */
.top-app-bar__title {
  flex: 1;
  color: var(--top-app-bar-title);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-family: var(--font-display);
  font-size: var(--font-size-24);
  font-weight: var(--weight-bold);
  line-height: var(--line-height-28);
  letter-spacing: -0.96px;
}

/* Brand-coloured title (e.g. "Settlr" wordmark on Home) */
.top-app-bar__title--brand {
  color: var(--text-brand);
}

/* "Done" ghost text action (Variant2) */
.top-app-bar__done {
  border: none;
  background: transparent;
  color: var(--btn-ghost-fg);
  cursor: pointer;
  padding: 0;
  flex-shrink: 0;
  white-space: nowrap;
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-semibold);
  line-height: var(--line-height-18);
}

/* Back button — now the shared Icon Button (.icon-btn.icon-btn--sm, neutral
   40px). The .top-app-bar__back class is kept only as a flex hook. */
.top-app-bar__back { flex-shrink: 0; text-decoration: none; }



/* Modifier: adds a bottom border (use when bar sits over flat content) */
.top-app-bar--bordered {
  border-bottom: var(--border-small) solid var(--nav-bar-border);
}

/* Detail screen title override — heading-md size (20px) */
.top-app-bar--bordered .top-app-bar__title,
.top-app-bar--nav .top-app-bar__title {
  font-size: var(--font-size-20);
  line-height: var(--line-height-26);
  letter-spacing: -0.40px;
}

/* ---- css/header-chips.css ---- */
/* ============================================
   Settlr — Header Chips Component
   A horizontally scrollable row of SM Chips
   used as a filter strip below the Top App Bar.
   No new tokens — uses existing chip + border tokens.
   ============================================ */

.header-chips {
  display: flex;
  flex-direction: row;
  align-items: center;
  padding: var(--spacing-12) var(--spacing-16);
  gap: var(--spacing-12);
  border-bottom: var(--border-small) solid var(--border-default);

  /* Horizontal scroll on mobile */
  overflow-x: auto;
  overflow-y: visible;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}

.header-chips::-webkit-scrollbar {
  display: none;
}

/* ---- Compact ----
   Tighter filter strip used directly below a search field (people, activity).
   Promoted from the per-screen `.chips-row` (zero visual change): the base
   already supplies display:flex, overflow-x:auto, hidden scrollbar, and the
   same border-bottom (--border-small solid --border-default); this modifier
   only overrides gap + padding and adds flex-shrink. */
.header-chips--compact {
  gap: var(--spacing-8);
  padding: 0 var(--spacing-16) var(--spacing-12);
  flex-shrink: 0;
}

/* ---- css/action-button-row.css ---- */
/* ============================================
   Settlr — Action Button Row Component
   Figma: node 207:15824
   ============================================ */

.action-btn-row {
  display: flex;
  align-items: center;
  gap: var(--spacing-16);
  padding: var(--spacing-12) var(--spacing-16);
  border-top: var(--border-small) solid var(--action-btn-row-border);
  background-color: var(--action-btn-row-bg);
  width: 100%;
}

/* Buttons grow equally to fill the row */
.action-btn-row .btn {
  flex: 1;
}

/* ---- css/screen-footer.css ---- */
/* ============================================
   Settlr — Screen Footer Component
   Fixed footer bar with 1 or 2 action buttons.
   Figma node: TBD
   ============================================ */

.screen-footer {
  position: fixed;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  /* Mirror the .app-shell width: full-bleed on a real phone (so the footer
     spans the same width as the content above it, even on phones wider than
     393px), capped to the 393px phone frame only on tablet/desktop below.
     A hard 393px cap on a wider phone left the footer narrower than the
     content with empty side gutters. */
  width: 100%;
  max-width: 100%;
  display: flex;
  gap: var(--spacing-12);
  padding: var(--spacing-12) var(--spacing-16) var(--spacing-32);
  background: var(--screen-footer-bg);
  /* Transparent at rest — the border is a scroll affordance, not a permanent
     divider. The reserved 1px keeps the footer from shifting when it appears. */
  border-top: var(--border-small) solid var(--screen-footer-border-default);
  z-index: 20;
}

/* Revealed once content scrolls underneath. Toggled by each screen's view JS
   (add-amount, add-review, add-split, edit-group, group-detail,
   individual-detail) — see the snippet in components/screen-footer.md. */
.screen-footer.is-scrolled {
  border-top-color: var(--screen-footer-border);
}

/* Centre the footer in the 393px phone frame only on wide viewports — matching
   the .app-shell breakpoint so the two stay aligned. */
@media (min-width: 480px) {
  .screen-footer {
    max-width: 393px;
  }
}

/* All direct .btn children grow equally */
.screen-footer .btn {
  flex: 1;
}

/* ---- css/settlement-item.css ---- */
/* ============================================
   Settlr — Settlement Item Component
   Figma: node 208:15867
   ============================================ */

.settlement-item {
  display: flex;
  align-items: center;
  gap: var(--spacing-12);
  padding: var(--spacing-12) var(--spacing-16);
  background: transparent;
  border-bottom: var(--border-small) solid var(--contact-divider);
  width: 100%;
}

.settlement-item__info {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-2);
  flex: 1;
  min-width: 0;
  overflow: hidden;
}

.settlement-item__name {
  color: var(--contact-name);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-family: var(--font-body);
  font-size: var(--font-size-14);
  font-weight: var(--weight-semibold);
  line-height: var(--line-height-20);
}.settlement-item__amount {
  font-family: var(--font-display);
  font-size: var(--font-size-13);
  font-weight: var(--weight-semibold);
  line-height: var(--line-height-18);
  flex-shrink: 0;
  white-space: nowrap;
}
.settlement-item__amount--lent {
  color: var(--expense-lent-fg);
}

.settlement-item__amount--owe {
  color: var(--expense-owe-fg);
}

/* ---- css/paid-by.css ---- */
/* ============================================
   Settlr — Paid By
   Row showing who paid an expense: a leading avatar (single) or an avatar
   stack (multiple payers), a "Paid by" label + payer name, and a trailing
   Change action. Shared by the expense edit + split screens.

   Surface is context-driven via a modifier:
     --card     inset card on a warm background (edit-expense)
     --divider  full-bleed row with a bottom hairline (add-split sheet)

   Typography comes from text-* classes in markup (.text-body-xs label,
   .text-title-sm name); only colour lives here.
   ============================================ */

.paid-by {
  display: flex;
  align-items: center;
  gap: var(--spacing-12);
  padding: var(--spacing-12) var(--spacing-16);
}

/* Leading avatar stack (multiple payers); a single .avatar also works. */
.paid-by__avatars {
  display: flex;
}
.paid-by__avatars .avatar:not(:first-child) {
  margin-left: calc(-1 * var(--spacing-8));
  border: var(--border-large) solid var(--surface-card);
}

.paid-by__text {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-2);
}
.paid-by__label { color: var(--text-secondary); }
.paid-by__name  { color: var(--text-primary); }

/* ---- Surface variants ---- */
.paid-by--card {
  background: var(--surface-card);
  border: var(--border-small) solid var(--border-subtle);
  border-radius: var(--radius-12);
}
.paid-by--divider {
  background: var(--surface-primary);
  border-bottom: var(--border-medium) solid var(--border-subtle);
}

/* ---- css/payer-sheet.css ---- */
/* ============================================
   Settlr — Payer Sheet rows (shared)
   Styling for the multi-payer "Paid by" bottom-sheet rendered by
   js/payer-sheet.js (SettlrPayerSheet). Shared by add-split + edit-expense.
   Row = checkbox + avatar + name + a 120px amount-input; a running sum hint
   sits under the list (coral when the amounts don't add up).
   ============================================ */

.payer-row {
  display: flex;
  align-items: center;
  gap: var(--spacing-12);
  padding: var(--spacing-12) var(--spacing-16);
  border-bottom: var(--border-small) solid var(--contact-divider);
}
.payer-row:last-child { border-bottom: none; }

.payer-row__text {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-2);
  min-width: 0;
}
.payer-row__name { color: var(--text-primary); }
.payer-row__sub  { color: var(--text-tertiary); }

/* Per-payer amount input (reuses the .amount-input component, fixed 120px col). */
.payer-row .amount-input {
  width: 120px;
  flex-shrink: 0;
}

/* Running payer-sum hint under the list; coral when amounts don't add up. */
.payer-hint {
  padding: var(--spacing-8) var(--spacing-16);
  text-align: center;
  color: var(--text-secondary);
}
.payer-hint--err { color: var(--expense-owe-fg); }

/* ---- css/bottom-sheet.css ---- */
/* ============================================
   Settlr — Bottom Sheet Component
   ============================================ */

/* ---- Overlay ---- */
.sheet-overlay {
  position: fixed;
  inset: 0;
  background-color: var(--overlay-50);
  z-index: 200;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  animation: fadeIn 0.2s ease;
}

/* ---- Sheet ---- */
.sheet {
  display: flex;
  flex-direction: column;
  width: 100%;
  /* Full-bleed on phones; only frame to 393px on desktop — mirrors the
     .app-shell width rule so the sheet never sits narrower than the app it
     covers (which left side gaps on >393px phones like Pro Max). */
  max-width: 100%;
  max-height: 75vh;
  background-color: var(--sheet-bg);
  border-top: var(--border-large) solid var(--sheet-border);
  border-radius: var(--radius-16) var(--radius-16) 0 0;
  overflow: hidden;
  animation: slideUp 0.3s ease;
}

@media (min-width: 480px) {
  .sheet { max-width: 393px; }
}

/* ---- Handle ---- */
.sheet__handle {
  display: flex;
  justify-content: center;
  padding: var(--spacing-8) 0;
}

.sheet__handle-bar {
  width: 36px;
  height: 4px;
  border-radius: var(--radius-full);
  background-color: var(--sheet-slot-bg);
}

/* ---- Header ---- */
.sheet__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--spacing-12) var(--spacing-16);
  border-bottom: var(--border-small) solid var(--sheet-divider);
}

.sheet__title {
  color: var(--sheet-header);
  font-family: var(--font-body);
  font-size: var(--font-size-18);
  font-weight: var(--weight-bold);
  line-height: var(--line-height-26);
  letter-spacing: -0.18px;
}

/* Sheet close action uses the shared Icon Button component
   (.icon-btn.icon-btn--sm) — see css/icon-button.css. */

/* ---- Content ----
   Deliberately carries NO horizontal padding: consumers that inject bare rows
   (.detail-row / .settings-row) supply their own inset, and several already set
   an explicit `padding` inline (js/confirm-sheet.js, js/views/individual-detail.js)
   or via a scoped rule (css/screens/settings.css) — adding it here would
   double-pad them.
   The bottom safe-area inset IS set here: the sheet is anchored to the bottom of
   the viewport, so on gesture-nav devices the last row used to sit underneath the
   home indicator. The three consumers above already declare their own
   padding-bottom (>= --spacing-24) so they keep that value unchanged; every
   other sheet — the People quick-actions list, the payer/group pickers — now
   clears the indicator. */
.sheet__content {
  flex: 1;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding-bottom: env(safe-area-inset-bottom, 0px);
}

/* ---- Animations ---- */
@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes slideUp {
  from { transform: translateY(100%); }
  to { transform: translateY(0); }
}

/* ---- css/empty-state.css ---- */
/* ============================================
   Settlr — Empty State Component
   Centered placeholder for screens with no content.
   Uses: --empty-state-* tokens + btn component.
   ============================================ */

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: var(--spacing-48) var(--spacing-32);
  gap: var(--spacing-24);
  width: 100%;
}

/* ---- Illustration ---- */
.empty-state__illustration {
  width: 96px;
  height: 96px;
  border-radius: var(--radius-16);
  background-color: var(--empty-state-illus-bg);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  color: var(--empty-state-illus-fg);
}

.empty-state__illustration svg {
  width: 48px;
  height: 48px;
}

/* ---- Text ---- */
.empty-state__text {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-8);
  align-items: center;
}

.empty-state__title {
  color: var(--empty-state-title-fg);
  font-family: var(--font-display);
  font-size: var(--font-size-18);
  font-weight: var(--weight-bold);
  line-height: var(--line-height-24);
  letter-spacing: -0.36px;
}

.empty-state__body {
  color: var(--empty-state-body-fg);
  max-width: 240px;
  font-family: var(--font-body);
  font-size: var(--font-size-13);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-21);
}

/* ---- css/toast.css ---- */
/* ============================================
   Settlr — Toast Component
   Figma: 292:8850
   Colors: Neutral, Brand, Success, Warning, Error, Info
   Booleans: Show Icon, Show Illustration, Show Title, Show Body
   ============================================ */

.toast {
  display: flex;
  align-items: center;
  gap: var(--spacing-8);
  width: 100%;
  max-width: 361px; /* 393px screen − 16px margin each side */
  padding: var(--spacing-12) var(--spacing-16);
  border-radius: var(--radius-12);
  border: var(--border-small) solid transparent;
  box-shadow: var(--shadow-lg);
  font-family: var(--font-body);
  -webkit-tap-highlight-color: transparent;
}

/* ---- Color variants ---- */
.toast--neutral {
  background-color: var(--toast-neutral-bg);
  color:            var(--toast-neutral-fg);
  border-color:     var(--toast-neutral-border);
}

.toast--brand {
  background-color: var(--toast-brand-bg);
  color:            var(--toast-brand-fg);
  border-color:     var(--toast-brand-border);
}

.toast--success {
  background-color: var(--toast-success-bg);
  color:            var(--toast-success-fg);
  border-color:     var(--toast-success-border);
}

.toast--error {
  background-color: var(--toast-error-bg);
  color:            var(--toast-error-fg);
  border-color:     var(--toast-error-border);
}

/* ---- Icon (16×16) — omit element to hide ---- */
.toast__icon {
  flex-shrink: 0;
  width: var(--icon-sm);
  height: var(--icon-sm);
  color: currentColor;
}

/* ---- Illustration (40×40) — omit element to hide ---- */
.toast__illustration {
  flex-shrink: 0;
  border-radius: var(--radius-8);
  overflow: hidden;
  background-color: var(--expense-item-illus-bg);
}

/* ---- Text column ---- */
.toast__text {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-4);
  flex: 1;
  min-width: 0;
}

/* ---- Title — Title/Title-SM (14px semibold) — omit element to hide ---- */
.toast__title {
  color: currentColor;
  font-size: var(--font-size-14);
  font-weight: var(--weight-semibold);
  line-height: var(--line-height-20);
}

/* ---- Body — Body/Body-SM (13px regular) ---- */
.toast__body {
  color: currentColor;
  font-size: var(--font-size-13);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-21);
}

/* ---- css/faq.css ---- */
/* ============================================
   Settlr Design System — FAQ / Accordion
   ============================================ */

.faq-item {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-8);
  padding: var(--spacing-12);
  border-bottom: var(--border-small) solid var(--faq-border);
}

.faq-item__trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  cursor: pointer;
}

.faq-item__question {
  font-family: var(--font-body);
  font-size: var(--font-size-13);
  font-weight: var(--weight-semibold);
  line-height: normal;
  color: var(--faq-question-fg);
  flex: 1;
}

.faq-item__icon {
  width: var(--icon-sm);
  height: var(--icon-sm);
  color: var(--faq-icon-fg);
  flex-shrink: 0;
}

.faq-item__answer {
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-16);
  color: var(--faq-answer-fg);
}

/* ---- css/currency-chip.css ---- */
/* ============================================
   Settlr Design System — Currency Chip
   ============================================ */

.currency-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-4);
  padding: var(--spacing-8) var(--spacing-12);
  border-radius: var(--radius-full);
  border: var(--border-small) solid var(--chip-border-off);
  background-color: var(--chip-bg-off);
  color: var(--chip-fg-off);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  white-space: nowrap;
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-semibold);
  line-height: var(--line-height-18);
}

.currency-chip__caret {
  width: var(--icon-xs);
  height: var(--icon-xs);
  flex-shrink: 0;
  color: currentColor;
}

/* ---- css/amount-input.css ---- */
/* ============================================
   Amount Input
   Figma: node 314:9120 — "Amount input" section
   ============================================

   Usage:
     <div class="amount-input amount-input--currency">
       <span class="amount-input__icon">₹</span>
       <input class="amount-input__field" type="number">
     </div>

   Variants:
     .amount-input--currency  — ₹ icon on the left, value right-aligned
     .amount-input--percent   — % icon on the right, value right-aligned
     .amount-input--shares    — unit label on the right, value right-aligned
     .amount-input--stepper   — ± controls on both sides (equal split display)

   States: default, :focus-within (border + background change)
   ============================================ */

/* ── Container ── */
.amount-input {
  display: flex;
  align-items: center;
  gap: var(--spacing-4);
  width: 120px;
  height: 40px;
  padding: var(--spacing-8);
  background: var(--amount-input-bg);
  border: var(--border-small) solid var(--amount-input-border);
  border-radius: var(--radius-8);
  overflow: hidden;
  transition: border-color 0.15s ease, background 0.15s ease;
}

.amount-input:focus-within {
  background: var(--amount-input-bg-focused);
  border-color: var(--amount-input-border-focused);
}

/* ── Editable field ── */
.amount-input__field {
  flex: 1;
  min-width: 0;
  background: transparent;
  border: none;
  outline: none;
  font-family: var(--font-display);
  font-size: var(--font-size-16);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-20);
  letter-spacing: -0.32px;
  color: var(--amount-input-fg);
  text-align: right;
  /* Reset native <input type="number"> chrome on all engines. Previously
     only -moz-appearance was reset; WebKit/Blink can still paint their own
     default text-field appearance (incl. an inset border/ring) on top of
     this custom-styled wrapper, which read as a stray "border inside the
     input section" — most visible once the field gained focus. Resetting
     -webkit-appearance/appearance too guarantees the wrapper's own
     border/background (below) is the only chrome ever drawn. */
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: textfield;
}
.amount-input__field::-webkit-inner-spin-button,
.amount-input__field::-webkit-outer-spin-button { -webkit-appearance: none; }
.amount-input__field::placeholder { color: var(--input-fg-default); }

/* ── Icon / unit slot (20 × 20px) ── */
.amount-input__icon {
  width: var(--icon-md);
  height: var(--icon-md);
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--amount-input-icon-fg);
  font-family: var(--font-body);
  font-size: var(--icon-md);
  font-weight: var(--weight-regular);
  line-height: 1;
}
.amount-input__icon svg {
  width: var(--icon-md);
  height: var(--icon-md);
  display: block;
}

/* ── Variant: shares — icon slot wider for the unit text ── */
.amount-input--shares .amount-input__icon {
  width: auto;
  font-size: var(--font-size-12);
  color: var(--amount-input-icon-fg);
}

/* ── Variant: stepper — two 20px tap-target icon slots leave only ~54px for
   the field within the base 120px width; a realistic 6-digit amount
   ("125000", this is a money app) needs ~74px and the last digit hid under
   the "+" button (F7). Fixed width (matching the base component's own
   non-token 120px precedent — see amount-input.md) with headroom for 6
   digits; min-width as a floor if a host ever squeezes it via flex-shrink. */
.amount-input--stepper {
  width: 160px;
  min-width: 160px;
}

/* ── Variant: stepper — icon slots are tap targets ── */
.amount-input--stepper .amount-input__icon {
  cursor: pointer;
  border-radius: var(--radius-4);
  font-size: var(--font-size-16);
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}
.amount-input--stepper .amount-input__icon:active {
  background: var(--amount-input-border);
}
.amount-input--stepper .amount-input__field {
  text-align: center;
}

/* ---- Inactive state ----
   Participant unchecked (add-split rows, payer sheet): dimmed, field not
   editable; tapping the row re-activates it. Promoted from a
   [data-view="add-split"]-scoped rule — the payer sheet is shared with
   edit-expense, where this state previously had no styling. */
.amount-input--inactive {
  opacity: var(--opacity-strong);
  cursor: pointer;
}
.amount-input--inactive .amount-input__field {
  pointer-events: none;
}

/* ---- css/status-bar.css ---- */
/* ── Status Bar ──────────────────────────────────────────── */
/* Simulated iOS status bar for mobile mockup screens        */

.status-bar {
  height: var(--spacing-48); /* 48px — closest token to 44px native iOS bar */
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 var(--spacing-24);
  background: var(--surface-primary);
}

.status-bar__time {
  font-family: var(--font-body);
  font-size: var(--font-size-14);
  font-weight: var(--weight-semibold);
  line-height: var(--line-height-20);
  letter-spacing: -0.5px; /* no token equivalent — design-specific */
  color: var(--text-primary);
}

.status-bar__icons {
  display: flex;
  align-items: center;
  gap: var(--spacing-4);
  color: var(--text-primary);
}

/* ---- Overlay variant ----
   Transparent bar pinned over a full-bleed hero so the hero extends to the
   very top (hero detail screens: group-detail, individual-detail, edit-group).
   The shell router toggles this on the persistent status bar per view. */
.status-bar--overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 10;
  background: transparent;
}

/* ---- css/search-input.css ---- */
/* ============================================
   Settlr — Search Input Component
   ============================================ */

.search-wrap {
  padding: var(--spacing-12) var(--spacing-16);
  background: var(--surface-primary);
  flex-shrink: 0;
}

.search-input {
  display: flex;
  align-items: center;
  gap: var(--spacing-8);
  height: 44px;
  padding: 0 var(--spacing-16);
  background: var(--input-bg);
  border: var(--border-small) solid var(--input-border-default);
  border-radius: var(--radius-full);
  width: 100%;
  cursor: text;
}

.search-input__icon {
  flex-shrink: 0;
  color: var(--input-fg-default);
  display: flex;
  align-items: center;
}

.search-input__icon i {
  font-size: var(--icon-sm);
}

.search-input input {
  flex: 1;
  border: none;
  background: transparent;
  font-family: var(--font-body);
  font-size: var(--font-size-14);
  font-weight: var(--weight-regular);
  color: var(--text-primary);
  outline: none;
}

.search-input input::placeholder {
  color: var(--input-fg-default);
}

/* ---- Filled (input has value) ---- */
.search-input:has(input:not(:placeholder-shown)) input {
  color: var(--input-fg-active);
  font-weight: var(--weight-medium);
}

/* ---- Focused (overrides above) ---- */
.search-input:focus-within {
  background-color: var(--input-bg-focused);
  border-color: var(--input-border-focused);
}

/* ---- css/update-item.css ---- */
/* =========================================================
   UPDATE ITEM — Activity feed notification rows
   Variants: --expense | --settlement | --group | --reminder | --system
   Modifier: --unread (shows dot indicator)
   ========================================================= */

.update-item {
  display: flex;
  align-items: flex-start;
  gap: var(--spacing-12);
  padding: var(--spacing-12) var(--spacing-16);
  background: transparent;
  position: relative;
}

/* Icon circle */
.update-item__icon {
  width: var(--spacing-40);
  height: var(--spacing-40);
  border-radius: var(--radius-full);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  font-size: var(--spacing-20);
}

.update-item__icon--expense {
  background: var(--label-owe-bg);
  color: var(--label-owe-fg);
}

.update-item__icon--settlement {
  background: var(--label-lent-bg);
  color: var(--label-lent-fg);
}

.update-item__icon--group {
  background: var(--chip-bg-on);
  color: var(--chip-fg-on);
}

.update-item__icon--reminder {
  background: var(--label-settled-bg);
  color: var(--label-settled-fg);
}

.update-item__icon--system {
  background: var(--surface-card);
  color: var(--text-secondary);
  border: 1px solid var(--border-default);
}

/* Body */
.update-item__body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-4);
}

.update-item__text {
  color: var(--text-primary);
  font-family: var(--font-body);
  font-size: var(--font-size-14);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-23);
}

.update-item__text strong {
  font-weight: 600;
}

.update-item__text .amount--lent,
.update-item__text .amount--owe {
  font-family: var(--font-display);
  font-size: var(--font-size-13);
  font-weight: var(--weight-semibold);
  line-height: var(--line-height-18);
  letter-spacing: -0.32px;
}

.update-item__text .amount--lent {
  color: var(--expense-lent-fg);
}

.update-item__text .amount--owe {
  color: var(--expense-owe-fg);
}

/* Meta row */
.update-item__meta {
  display: flex;
  align-items: center;
  gap: var(--spacing-8);
}

.update-item__time {
  color: var(--text-secondary);
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-17);
}

.update-item__tag {
  color: var(--text-secondary);
  background: var(--surface-bg);
  border-radius: var(--radius-4);
  padding: 0 var(--spacing-4);
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-17);
}

/* Action buttons */
.update-item__actions {
  display: flex;
  gap: var(--spacing-8);
  margin-top: var(--spacing-4);
}

/* Unread dot — optically centred on the FIRST line of the message, not on the
   row's full height. `align-self: center` was centring it against however tall
   the body grew: on a 4-line notification (137px row) the dot landed 65px down,
   floating in the middle of line 3 with nothing to relate to. Anchoring to the
   top keeps it beside the text it actually marks, at any body length. The
   offset optically centres an 8px dot on the ~23px first line. */
.update-item__dot {
  width: var(--spacing-8);
  height: var(--spacing-8);
  border-radius: var(--radius-full);
  background: var(--action-primary);
  flex-shrink: 0;
  align-self: flex-start;
  margin-top: var(--spacing-8);
}

.update-item:not(.update-item--unread) .update-item__dot {
  display: none;
}

/* ---- css/hero-section.css ---- */
/* ============================================
   Settlr — Hero Section Component

   Full-width 180px tall feature section (variants: --tall 220px for
   group-detail, --short 150px for edit-group) used at the top of detail
   and edit screens. Has a gradient background, decorative diamond
   texture overlay (::before), an action overlay row at top
   (back / settings buttons), and an optional avatar that overlaps
   the hero/content boundary.

   Replaces: .hero-photo (group-detail), .hero-banner
   (individual-detail), .hero (edit-group)

   2026-08-06 (E8 fix): band height reduced (240/300/200 -> 180/220/150) and
   __actions top offset changed from a fixed 52px to var(--spacing-16) — same
   as the horizontal inset — via new *-compact tokens in tokens/semantic.css.
   No real screen renders .hero-section__emoji or __bg (group-detail /
   individual-detail / edit-group all leave the band as bare gradient +
   action buttons + overlapping avatar), so the old height was pure dead
   space and the old top offset had nothing to clear (settlr-status-bar is
   display:none in the real app; env(safe-area-inset-top) is handled by
   .app-shell, not by this component).
   ============================================ */

.hero-section {
  position: relative;
  width: 100%;
  height: var(--hero-section-height-compact);
  flex-shrink: 0;
  overflow: hidden;
  background: var(--surface-hero-gradient);
}

/* ---- Size variants ---- */
.hero-section--tall  { height: var(--hero-section-height-tall-compact);  }
.hero-section--short { height: var(--hero-section-height-short-compact); }

/* ---- Diamond texture overlay (decorative) ---- */
.hero-section::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(60deg,  var(--surface-hero-texture-overlay) 25%, transparent 25%),
    linear-gradient(-60deg, var(--surface-hero-texture-overlay) 25%, transparent 25%),
    linear-gradient(60deg,  transparent 75%, var(--surface-hero-texture-overlay) 75%),
    linear-gradient(-60deg, transparent 75%, var(--surface-hero-texture-overlay) 75%);
  background-size: var(--hero-section-texture-tile) var(--hero-section-texture-tile);
  pointer-events: none;
}

/* ---- Optional photo background (replaces gradient) ---- */
.hero-section__bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
}

/* ---- Optional centered emoji (e.g. group-detail placeholder) ---- */
.hero-section__emoji {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--hero-section-emoji-size);
  z-index: 1;
  pointer-events: none;
}

/* ---- Overlay action row (top: back, settings) ----
   top offset matches the horizontal inset (--spacing-16) on all three sides —
   there is no in-page status bar to clear (settlr-status-bar renders nothing;
   the real app relies on the OS status bar + the app-shell's own
   safe-area-inset-top padding), so the old 52px top offset was pure excess
   space, not clearance for anything. */
.hero-section__actions {
  position: absolute;
  top: var(--spacing-16);
  left: 0;
  right: 0;
  display: flex;
  justify-content: space-between;
  padding: 0 var(--spacing-16);
  z-index: 5;
}

/* ---- Avatar wrapper — sits below the hero, vertically overlapping ---- */
.hero-section__avatar-wrap {
  display: flex;
  justify-content: center;
  width: 100%;
  margin-top: calc(-1 * var(--spacing-48));
  position: relative;
  z-index: 2;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* When the wrap is a button (edit screens), apply press feedback to its
   children — the avatar itself stays visually intact. */
.hero-section__avatar-wrap:active .avatar,
.hero-section__avatar-wrap:active .hero-section__avatar-edit-badge {
  opacity: var(--opacity-disabled);
}

/* ---- Optional edit badge on the avatar (camera / pencil) ---- */
/* Pattern shared with edit-profile and edit-group. Position the badge
   relative to a positioned avatar wrap. */
.hero-section__avatar-edit-badge {
  position: absolute;
  right: 0;
  bottom: 0;
  width: var(--hero-section-badge-size);
  height: var(--hero-section-badge-size);
  border-radius: var(--radius-full);
  background: var(--hero-section-badge-bg);
  color: var(--hero-section-badge-fg);
  border: var(--border-medium) solid var(--avatar-border-on-hero);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-shadow: var(--shadow-sm);
}
.hero-section__avatar-edit-badge i {
  font-size: var(--icon-xs);
}

/* ---- css/toggle.css ---- */
/* ============================================
   Toggle Switch — .toggle-control
   ----------------------------------------------
   44x26 pill switch. The native <input type="checkbox">
   is visually hidden but remains the source of truth
   for state — :checked drives the visual change via
   the sibling combinator.

   States:
     - Off (default)
     - On  (input:checked)
     - Disabled (input:disabled)

   Accessibility:
     Use role="switch" + aria-checked on the visible
     <label>/<input> pair, or rely on the native
     checkbox semantics provided by the <input>.
   ============================================ */

.toggle-control {
  position: relative;
  display: inline-block;
  width: 44px;
  height: 26px;
  flex-shrink: 0;
}

/* Visually hidden but functional native input */
.toggle-control input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
  margin: 0;
  pointer-events: none;
}

/* Track — pill background */
.toggle-control__track {
  position: absolute;
  inset: 0;
  border-radius: var(--radius-full);
  background: var(--toggle-track-bg-off);
  transition: background 0.2s ease;
  cursor: pointer;
}

/* Thumb — circular knob that slides on toggle */
.toggle-control__thumb {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 20px;
  height: 20px;
  border-radius: var(--radius-full);
  background: var(--toggle-thumb-bg);
  box-shadow: var(--toggle-thumb-shadow);
  pointer-events: none;
}

@media (prefers-reduced-motion: no-preference) {
  .toggle-control__thumb {
    transition: transform var(--duration-base) var(--ease-spring);
  }
  .toggle-control__track {
    transition: background-color var(--duration-base) var(--ease-out);
  }
}

/* On state — drives both track and thumb via sibling combinator */
.toggle-control input:checked ~ .toggle-control__track {
  background: var(--toggle-track-bg-on);
}
.toggle-control input:checked ~ .toggle-control__thumb {
  transform: translateX(18px);
}

/* Disabled state
   NOTE: intentionally does NOT reference --toggle-track-bg-disabled /
   --toggle-thumb-bg-disabled (tokens/semantic.css lines ~371/373). Those
   resolve to --neutral-mid (--color-gray-200), a cool blue-gray primitive
   that reads as an off-palette, jarring color against Settlr's warm
   beige-neutral scale (CLAUDE.md Rule 4) — this was the "particular color"
   flagged as odd in the states matrix. Using --surface-track / --text-faint
   instead: both are already-existing warm-neutral semantic tokens, so this
   stays Rule-8 compliant without editing semantic.css's existing values. */
.toggle-control input:disabled ~ .toggle-control__track {
  background: var(--surface-track);
  cursor: not-allowed;
}
.toggle-control input:disabled ~ .toggle-control__thumb {
  background: var(--text-faint);
  box-shadow: none;
}

/* ---- css/settings-row.css ---- */
/* ============================================
   Settings Row Family
   ----------------------------------------------
   Three nested levels:
     .settings-section         — wrapper (label + card)
       .settings-section__label
       .settings-card          — rounded grouping container
         .settings-row         — interactive row (anchor or div)
           .settings-row__icon-wrap (variants: --coral, --green, --neutral, --brand)
           .settings-row__text
             .settings-row__label
             .settings-row__value
           .settings-row__right
             .settings-row__chevron
           Modifiers on row: --destructive, --logout, --no-pointer
   ============================================ */

/* ── Section ── */
.settings-section {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-8);
}

.settings-section__label {
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-semibold);
  letter-spacing: 1.54px;
  text-transform: uppercase;
  color: var(--settings-section-label-fg);
  padding: 0 var(--spacing-4);
}

/* ── Settings Card ── */
.settings-card {
  background: var(--settings-card-bg);
  border-radius: var(--radius-12);
  border: var(--border-small) solid var(--settings-card-border);
  overflow: hidden;
}

/* ── Settings Row ── */
.settings-row {
  display: flex;
  align-items: center;
  gap: var(--spacing-12);
  padding: var(--spacing-16);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  border-bottom: var(--border-small) solid var(--settings-row-divider);
  text-decoration: none;
}

.settings-row:last-child {
  border-bottom: none;
}

.settings-row:active {
  background: var(--settings-row-press-bg);
}

.settings-row--no-pointer {
  cursor: default;
}

.settings-row--no-pointer:active {
  background: transparent;
}

/* Icon wrap — base + colour variants */
.settings-row__icon-wrap {
  width: 36px;
  height: 36px;
  border-radius: var(--radius-8);
  background: var(--settings-row-icon-bg);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.settings-row__icon-wrap i {
  font-size: var(--font-size-18);
  color: var(--settings-row-icon-fg);
}

.settings-row__icon-wrap--coral {
  background: var(--expense-owe-bg);
}
.settings-row__icon-wrap--coral i {
  color: var(--expense-owe-fg);
}

.settings-row__icon-wrap--green {
  background: var(--expense-lent-bg);
}
.settings-row__icon-wrap--green i {
  color: var(--expense-lent-fg);
}

.settings-row__icon-wrap--neutral {
  background: var(--surface-input);
}
.settings-row__icon-wrap--neutral i {
  color: var(--text-tertiary);
}

.settings-row__icon-wrap--brand {
  background: var(--action-muted);
}
.settings-row__icon-wrap--brand i {
  color: var(--action-dark);
}

/* Text block */
.settings-row__text {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-2);
  min-width: 0;
}

.settings-row__label {
  font-family: var(--font-body);
  font-size: var(--font-size-14);
  font-weight: var(--weight-medium);
  color: var(--settings-row-label-fg);
  line-height: var(--line-height-20);
}

.settings-row__value {
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-regular);
  color: var(--settings-row-value-fg);
  line-height: var(--line-height-18);
}

/* Right-aligned trailing slot */
.settings-row__right {
  display: flex;
  align-items: center;
  gap: var(--spacing-8);
  flex-shrink: 0;
}

.settings-row__chevron {
  color: var(--settings-row-chevron-fg);
  display: inline-flex;
  align-items: center;
}

.settings-row__chevron i {
  font-size: var(--icon-sm);
}

/* ── Destructive Row ── */
.settings-row--destructive .settings-row__label {
  color: var(--settings-row-destructive-label-fg);
}

/* ── Logout Row ── */
.settings-row--logout .settings-row__label {
  color: var(--settings-row-logout-label-fg);
}

/* ---- css/detail-row.css ---- */
/* ============================================
   Detail Row — Read-only / Selectable Row
   ============================================
   A composable row showing icon + label + value
   with optional chevron or selection radio.

   Variants:
     .detail-row                — Default (transparent, divider-bottom)
     .detail-row--clickable     — Tap-affordant with chevron
     .detail-row--selectable    — Boxed, radio-style selection (settle-method)

   Sub-elements:
     __icon     - Square 40px tinted icon container
     __text     - Label + value column
     __label    - Smaller caption above value
     __value    - Primary content
     __right    - Right-aligned slot (chevron, radio, custom)
     __chevron  - Caret-right indicator
     __radio    - Radio circle for selectable variant
     __radio-dot- Inner dot of radio
   ============================================ */

.detail-row {
  display: flex;
  align-items: center;
  gap: var(--spacing-12);
  padding: var(--spacing-12) 0;
  background: var(--detail-row-bg);
  border-bottom: var(--border-small) solid var(--border-subtle);
  -webkit-tap-highlight-color: transparent;
}

.detail-row:last-child { border-bottom: none; }

/* Icon container — square tinted tile */
.detail-row__icon {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-8);
  background: var(--detail-row-icon-bg);
  color: var(--detail-row-icon-fg);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--font-size-18);
  flex-shrink: 0;
}

/* Text column */
.detail-row__text {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-2);
  min-width: 0;
}

.detail-row__label {
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-19);
  color: var(--detail-row-label-fg);
}

.detail-row__value {
  font-family: var(--font-body);
  font-size: var(--font-size-14);
  font-weight: var(--weight-semibold);
  color: var(--detail-row-value-fg);
}

/* Right slot — generic */
.detail-row__right {
  display: flex;
  align-items: center;
  gap: var(--spacing-8);
  flex-shrink: 0;
}

/* Chevron indicator */
.detail-row__chevron {
  font-size: var(--font-size-18);
  color: var(--detail-row-chevron-fg);
  flex-shrink: 0;
}

/* ── Variant: Clickable (with chevron) ── */
.detail-row--clickable {
  cursor: pointer;
}

.detail-row--clickable:active {
  background: var(--detail-row-bg-pressed);
}

/* ── Variant: Selectable (boxed, radio-style) ── */
.detail-row--selectable {
  padding: var(--spacing-12) var(--spacing-16);
  border-radius: var(--radius-12);
  border: var(--border-medium) solid var(--detail-row-border);
  background: var(--detail-row-bg);
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease;
}

.detail-row--selectable + .detail-row--selectable {
  margin-top: var(--spacing-12);
}

/* Boxed rows do not get a divider */
.detail-row--selectable,
.detail-row--selectable:last-child {
  border-bottom: var(--border-medium) solid var(--detail-row-border);
}

.detail-row--selectable:active {
  background: var(--detail-row-bg-pressed);
}

.detail-row--selectable.is-selected {
  background: var(--detail-row-selected-bg);
  border-color: var(--detail-row-selected-border);
}

.detail-row--selectable.is-selected .detail-row__icon {
  background: var(--detail-row-icon-bg-selected);
}

/* Radio control inside selectable variant */
.detail-row__radio {
  width: 20px;
  height: 20px;
  border-radius: var(--radius-full);
  border: var(--border-medium) solid var(--detail-row-radio-border);
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: border-color 0.15s ease, background 0.15s ease;
}

.detail-row.is-selected .detail-row__radio {
  border-color: var(--detail-row-radio-border-selected);
  background: var(--detail-row-radio-bg-selected);
}

.detail-row__radio-dot {
  width: 8px;
  height: 8px;
  border-radius: var(--radius-full);
  background: var(--detail-row-radio-dot);
  opacity: 0;
  transition: opacity 0.15s ease;
}

.detail-row.is-selected .detail-row__radio-dot {
  opacity: 1;
}

/* ---- css/notes-card.css ---- */
/* ============================================
   Notes Card — Read-only / Editable Notes Block
   ============================================
   A tinted (or bordered) card for notes,
   descriptions, comments — with optional textarea
   and character counter.

   Variants:
     .notes-card                — Default (readonly tinted card)
     .notes-card--readonly      — Explicit readonly (alias for default)
     .notes-card--editable      — Bordered card with textarea + counter

   Sub-elements:
     __label    - Overline label
     __text     - Display-only body text
     __textarea - Editable textarea
     __counter  - Character counter (right-aligned)
     __helper   - Helper text below textarea
   ============================================ */

.notes-card {
  padding: var(--spacing-12) var(--spacing-16);
  border-radius: var(--radius-12);
  background: var(--notes-card-bg);
  border: var(--border-small) solid var(--notes-card-border);
}

/* Label — overline */
.notes-card__label {
  display: block;
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-semibold);
  letter-spacing: 1.76px;
  text-transform: uppercase;
  color: var(--notes-card-label-fg);
  margin-bottom: var(--spacing-4);
}

/* Read-only body text */
.notes-card__text {
  font-family: var(--font-body);
  font-size: var(--font-size-14);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-23);
  color: var(--notes-card-text-fg);
}

/* Helper / hint below textarea or text */
.notes-card__helper {
  display: block;
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-regular);
  color: var(--notes-card-counter-fg);
  margin-top: var(--spacing-4);
}

/* ── Variant: Read-only (default) ─────────── */
.notes-card,
.notes-card--readonly {
  background: var(--notes-card-bg);
  border: none;
}

/* ── Variant: Editable (with textarea) ────── */
.notes-card--editable {
  background: var(--notes-card-bg-editable);
  border: var(--border-small) solid var(--notes-card-border);
}

.notes-card--editable .notes-card__label {
  margin-bottom: var(--spacing-8);
}

/* Textarea — borderless, expands inside card */
.notes-card__textarea {
  width: 100%;
  background: transparent;
  border: none;
  outline: none;
  font-family: var(--font-body);
  font-size: var(--font-size-14);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-23);
  color: var(--notes-card-textarea-fg);
  resize: none;
  min-height: 48px;
  padding: 0;
}

.notes-card__textarea::placeholder {
  color: var(--notes-card-textarea-placeholder);
}

/* Focused state — card-level */
.notes-card--editable:focus-within {
  background: var(--notes-card-bg-editable-focused);
  border-color: var(--notes-card-border-focused);
}

/* Counter — right-aligned beneath textarea */
.notes-card__counter {
  display: block;
  text-align: right;
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-regular);
  color: var(--notes-card-counter-fg);
  margin-top: var(--spacing-4);
}

.notes-card__counter--warning {
  color: var(--notes-card-counter-fg-warning);
}

/* ---- css/summary-card.css ---- */
/* ============================================
   Summary Card — Centered Settlement Summary
   ============================================
   A vertically-stacked, centered card showing
   avatar + name + amount + meta. Used for
   settlement and confirmation flows.

   Variants:
     .summary-card              — Default bordered card
     .summary-card--success     — Success state (no border, used on settle-success)

   Sub-elements:
     __avatar  - 56px circular avatar (uses .avatar component or inline)
     __name    - Person name
     __amount  - Large amount (display font)
     __meta    - Subtitle / timestamp / method label
   ============================================ */

.summary-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--spacing-12);
  padding: var(--spacing-24) var(--spacing-16);
  margin: var(--spacing-8) var(--spacing-16) 0;
  border-radius: var(--radius-16);
  background: var(--summary-card-bg);
  border: var(--border-small) solid var(--summary-card-border);
  text-align: center;
}

/* Avatar — circular, 56px */
.summary-card__avatar {
  width: 56px;
  height: 56px;
  border-radius: var(--radius-full);
  background: var(--summary-card-avatar-bg);
  color: var(--summary-card-avatar-fg);
  font-family: var(--font-display);
  font-size: var(--font-size-20);
  font-weight: var(--weight-bold);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

/* Name */
.summary-card__name {
  font-family: var(--font-body);
  font-size: var(--font-size-16);
  font-weight: var(--weight-bold);
  color: var(--summary-card-name-fg);
  line-height: var(--line-height-24);
}

/* Primary amount */
.summary-card__amount {
  font-family: var(--font-display);
  font-size: var(--font-size-28);
  font-weight: var(--weight-black);
  letter-spacing: -1.12px;
  color: var(--summary-card-amount-fg);
  line-height: var(--line-height-34);
}

/* Meta — subtitle, timestamp, method tag */
.summary-card__meta {
  font-family: var(--font-body);
  font-size: var(--font-size-13);
  font-weight: var(--weight-regular);
  color: var(--summary-card-meta-fg);
  line-height: var(--line-height-20);
}

/* ── Variant: Success (used on settle-success) ── */
.summary-card--success {
  background: transparent;
  border: none;
  margin: 0;
  padding: 0;
  gap: var(--spacing-8);
}

.summary-card--success .summary-card__avatar {
  width: 48px;
  height: 48px;
  font-size: var(--font-size-16);
  font-family: var(--font-body);
  margin-bottom: var(--spacing-4);
}

.summary-card--success .summary-card__amount {
  font-size: var(--font-size-24);
  letter-spacing: -0.72px;
  color: var(--summary-card-name-fg);
}

/* Directional amount color — applied via modifier */
.summary-card__amount--owe { color: var(--expense-owe-fg); }
.summary-card__amount--lent { color: var(--expense-lent-fg); }

/* ---- css/success-state.css ---- */
/* ============================================
   Settlr — Success State Component
   Full-screen confirmation/celebration layout used after
   completing a flow (group created, settlement done, etc.).

   Composition: __icon (large circular badge) + __heading +
   __body + optional __info-card slot + __actions footer.

   Variants:
     --celebration  — bouncier scale-in, used for create-group-done
     --confirmation — gentler scale-in, used for settle-success

   Required L3 semantic tokens (defined in tokens/semantic.css):
     --success-state-icon-bg
     --success-state-icon-fg
     --success-state-icon-bg-confirmation
     --success-state-icon-fg-confirmation
     --success-state-heading-fg
     --success-state-heading-fg-confirmation
     --success-state-body-fg
     --success-state-info-bg
     --success-state-info-border
     --success-state-meta-fg
     --success-state-timestamp-fg
   ============================================ */

.success-state {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: var(--spacing-32) var(--spacing-24);
  gap: var(--spacing-16);
  width: 100%;
}

/* ---- Icon (large circular/rounded badge) ---- */
.success-state__icon {
  width: 96px;
  height: 96px;
  border-radius: var(--radius-24);
  background: var(--success-state-icon-bg);
  color: var(--success-state-icon-fg);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

@media (prefers-reduced-motion: no-preference) {
  .success-state__icon {
    animation: successStateIconIn var(--duration-slow) var(--ease-spring) 0.2s both;
  }
}

.success-state__icon-emoji {
  font-size: var(--icon-xl);
  line-height: 1;
}

.success-state__icon-glyph {
  font-size: var(--icon-xl);
  line-height: 1;
  color: inherit;
  animation: successStateGlyphIn 0.4s ease 0.6s both;
}

/* ---- Heading ---- */
.success-state__heading {
  font-family: var(--font-display);
  font-size: var(--font-size-28);
  font-weight: var(--weight-black);
  line-height: var(--line-height-34);
  letter-spacing: -0.84px;
  color: var(--success-state-heading-fg);
  animation: successStateFadeUp var(--duration-slow) var(--ease-out) 0.6s both;
}

/* ---- Body / supporting copy ---- */
.success-state__body {
  font-family: var(--font-body);
  font-size: var(--font-size-15);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-22);
  color: var(--success-state-body-fg);
  max-width: 280px;
  animation: successStateFadeUp 0.4s ease 0.8s both;
}

/* ---- Info card (slot for screen-specific content: group info, settlement details) ---- */
.success-state__info-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--spacing-8);
  width: 100%;
  animation: successStateFadeUp 0.4s ease 0.9s both;
}

.success-state__info-card--boxed {
  padding: var(--spacing-16);
  border-radius: var(--radius-16);
  background: var(--success-state-info-bg);
  border: var(--border-small) solid var(--success-state-info-border);
}

/* ---- Meta (small pill / chip — e.g. group type, payment method) ---- */
.success-state__meta {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-4);
  padding: var(--spacing-4) var(--spacing-12);
  border-radius: var(--radius-full);
  background: var(--btn-icon-bg);
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-medium);
  color: var(--success-state-meta-fg);
}

/* ---- Timestamp ---- */
.success-state__timestamp {
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  color: var(--success-state-timestamp-fg);
  margin-top: var(--spacing-4);
  animation: successStateFadeUp 0.4s ease 1.1s both;
}

/* ---- Actions (footer button stack) ---- */
.success-state__actions {
  padding: var(--spacing-12) var(--spacing-24) var(--spacing-32);
  display: flex;
  flex-direction: column;
  gap: var(--spacing-12);
  width: 100%;
  animation: successStateFadeUp 0.4s ease 1.3s both;
}

/* ============================================================
   Variants
   ============================================================ */

/* Celebration — scale + bouncier easing (group-done) */
.success-state--celebration .success-state__icon {
  animation-duration: 0.6s;
  animation-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* Confirmation — settle-success (green check, success palette) */
.success-state--confirmation .success-state__icon {
  border-radius: var(--radius-full);
  width: 88px;
  height: 88px;
  background: var(--success-state-icon-bg-confirmation);
  color: var(--success-state-icon-fg-confirmation);
}

.success-state--confirmation .success-state__heading {
  color: var(--success-state-heading-fg-confirmation);
}

/* ============================================================
   Animations
   ============================================================ */

@keyframes successStateIconIn {
  from { transform: scale(0); opacity: 0; }
  to   { transform: scale(1); opacity: 1; }
}

@keyframes successStateGlyphIn {
  from { transform: scale(0.5); opacity: 0; }
  to   { transform: scale(1);   opacity: 1; }
}

@keyframes successStateFadeUp {
  from { transform: translateY(12px); opacity: 0; }
  to   { transform: translateY(0);    opacity: 1; }
}

/* ---- css/invite-banner.css ---- */
/* ============================================
   Settlr — Invite Banner Component
   Promotional row inviting users to share a join link.
   Compact horizontal layout: icon + text block + optional action.

   Required L3 semantic tokens (defined in tokens/semantic.css):
     --invite-banner-bg
     --invite-banner-bg-pressed
     --invite-banner-border
     --invite-banner-icon-bg
     --invite-banner-icon-fg
     --invite-banner-title-fg
     --invite-banner-subtitle-fg
   ============================================ */

.invite-banner {
  display: flex;
  align-items: center;
  gap: var(--spacing-12);
  padding: var(--spacing-12) var(--spacing-16);
  border-radius: var(--radius-12);
  background: var(--invite-banner-bg);
  border: var(--border-small) dashed var(--invite-banner-border);
  cursor: pointer;
  width: 100%;
  -webkit-tap-highlight-color: transparent;
  text-decoration: none;
}

.invite-banner:active {
  background: var(--invite-banner-bg-pressed);
}

/* ---- Icon ---- */
.invite-banner__icon {
  width: 36px;
  height: 36px;
  border-radius: var(--radius-full);
  background: var(--invite-banner-icon-bg);
  color: var(--invite-banner-icon-fg);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.invite-banner__icon i {
  font-size: var(--icon-md);
  color: inherit;
}

/* ---- Text block ---- */
.invite-banner__text {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-2);
  min-width: 0;
}

.invite-banner__title {
  font-family: var(--font-body);
  font-size: var(--font-size-14);
  font-weight: var(--weight-semibold);
  line-height: var(--line-height-20);
  color: var(--invite-banner-title-fg);
}

.invite-banner__subtitle {
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-16);
  color: var(--invite-banner-subtitle-fg);
}

/* ---- Action slot (for trailing button or icon) ---- */
.invite-banner__action {
  flex-shrink: 0;
  display: flex;
  align-items: center;
}

/* ---- css/invite-card.css ---- */
/* ============================================
   Settlr — Invite Card
   "Invite via link" composition (add-friend). A copyable link field with an
   inline copy icon, plus a single Share secondary CTA that opens the native
   OS share sheet (navigator.share).
   Family: .invite-card / __title / __subtitle / __row / .invite-link-box (+ __url, __copy).
   The link box + Share CTA sit side by side in .invite-card__row (link flexes,
   Share is a standard .btn.btn--secondary on the right).

   NON-TOKEN VALUES (kept exact; flagged): .invite-link-box height 40px,
   .invite-link-box__copy 32px tap target (no matching spacing tokens).
   ============================================ */

.invite-card {
  margin: var(--spacing-12) var(--spacing-16);
  padding: var(--spacing-16);
  background: var(--surface-card);
  border-radius: var(--radius-12);
  border: var(--border-small) solid var(--border-subtle);
  display: flex;
  flex-direction: column;
  gap: var(--spacing-12);
}
/* title — text style via .text-title-sm in markup; only color stays here */
.invite-card__title {
  color: var(--text-primary);
}
/* subtitle — text style via .text-body-xs in markup; color + spacing here */
.invite-card__subtitle {
  color: var(--text-tertiary);
  margin-top: calc(-1 * var(--spacing-8));
}

/* ── Link box + Share CTA in one row (link flexes, Share on the right) ── */
.invite-card__row {
  display: flex;
  align-items: stretch;
  gap: var(--spacing-8);
}
.invite-card__row .invite-link-box {
  flex: 1;
  min-width: 0;
}
.invite-card__row .btn {
  flex-shrink: 0;
}

/* ── Link field with inline copy ── */
.invite-link-box {
  /* NON-TOKEN: 40px control height — no spacing token; kept exact. */
  height: 40px;
  padding: 0 var(--spacing-4) 0 var(--spacing-12);
  background: var(--surface-primary);
  border: var(--border-small) solid var(--border-default);
  border-radius: var(--radius-8);
  display: flex;
  align-items: center;
  gap: var(--spacing-8);
  overflow: hidden;
}
/* link text — text style via .text-body-xs in markup; color + truncation here */
.invite-link-box__url {
  flex: 1;
  min-width: 0;
  color: var(--text-tertiary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* inline copy icon button */
.invite-link-box__copy {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  /* NON-TOKEN: 32px tap target — no spacing token; kept exact. */
  width: 32px;
  height: 32px;
  border: none;
  background: transparent;
  border-radius: var(--radius-8);
  color: var(--text-brand);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

@media (prefers-reduced-motion: no-preference) {
  .invite-link-box__copy {
    transition: transform var(--duration-fast) var(--ease-out);
  }
  .invite-link-box__copy:active {
    transform: scale(var(--press-scale-sm));
  }
}

/* ---- css/qr-section.css ---- */
/* ============================================
   Settlr — QR Section
   Screen-unique "QR share" card used by the static add-friend markup.
   Promoted verbatim from the [data-view="add-friend"] scoped block (the
   [data-view] prefix was dropped — zero visual change). Family:
   .qr-section / .qr-placeholder / .qr-text / .qr-text__title /
   .qr-text__sub / .qr-text__id.

   NON-TOKEN VALUES (kept exact to guarantee zero visual change; flagged)
     - .qr-placeholder width/height: 64px  (no 64px sizing token)
     - .qr-placeholder font-size: 32px  (drives the bare .icon-holder glyph;
       no 32px icon token — --icon-lg is 24px, would change the visual)
   ============================================ */

/* ── QR Code section (tap to open the QR overlay) ── */
.qr-section {
  margin: 0 var(--spacing-16) var(--spacing-8);
  padding: var(--spacing-16);
  background: var(--surface-card);
  border-radius: var(--radius-12);
  border: var(--border-small) solid var(--border-subtle);
  display: flex;
  align-items: center;
  gap: var(--spacing-16);
  cursor: pointer;
}
/* Action button (View) — pinned to the 40px control height shared with the
   invite-card Share CTA so both secondary actions read at the same size.
   NON-TOKEN: 40px control height — no spacing token; matches .invite-link-box. */
.qr-section .btn { height: 40px; }

.qr-placeholder {
  /* NON-TOKEN: 64px tile — no sizing token; kept exact. */
  width: 64px;
  height: 64px;
  border-radius: var(--radius-8);
  background: var(--surface-primary);
  border: var(--border-small) solid var(--border-default);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  color: var(--text-brand);
  /* NON-TOKEN: 32px drives the bare .icon-holder glyph; no 32px icon token. */
  font-size: 32px;
}
/* ── Enlarged QR tile for the overlay ── */
.qr-placeholder--lg {
  /* NON-TOKEN: 200px QR preview tile — no sizing token; kept exact. */
  width: 200px;
  height: 200px;
  /* NON-TOKEN: 120px drives the bare .icon-holder glyph at preview scale. */
  font-size: 120px;
}
/* Real QR image inside the preview tile (160px leaves a quiet-zone inside 200px).
   NON-TOKEN: 160px — no sizing token; sized to the 200px tile. */
.qr-placeholder__img {
  width: 160px;
  height: 160px;
  display: block;
}
.qr-text { flex: 1; }
/* qr title — text style via .text-title-sm in markup; color here */
.qr-text__title {
  color: var(--text-primary);
}
/* qr sub — text style via .text-body-xs in markup; color + spacing here */
.qr-text__sub {
  color: var(--text-tertiary);
  margin-top: var(--spacing-2);
}
/* qr id — display font, screen-unique style: font props kept (no text-* match) */
.qr-text__id {
  font-family: var(--font-display);
  font-size: var(--font-size-12);
  font-weight: var(--weight-semibold);
  color: var(--text-brand);
  margin-top: var(--spacing-4);
}

/* ---- css/photo-upload.css ---- */
/* ============================================
   Settlr — Photo Upload Component
   Dashed image-picker tile used in group creation.
   Promoted from the create-group-name screen-scoped block (zero visual
   change). Non-token values kept exact: 96px tile, 2px dashed border, the
   "all 0.15s ease" transition, 28px icon glyph, 10px caption font.
   ============================================ */

.photo-area {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--spacing-12);
}
.photo-upload {
  /* NON-TOKEN: 96px tile — no sizing token; kept exact. */
  width: 96px;
  height: 96px;
  border-radius: var(--radius-24);
  background: var(--type-chip-bg-on);
  /* NON-TOKEN: 2px dashed — kept exact for the dashed style shorthand. */
  border: 2px dashed var(--toast-brand-border);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--spacing-4);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  /* NON-TOKEN: transition carried over verbatim from source. */
  transition: all 0.15s ease;
}
.photo-upload:active {
  background: var(--btn-secondary-bg);
}
/* Selected-photo state: the chosen image fills the tile (set as an inline
   background-image by JS); the dashed border + icon/caption are dropped. */
.photo-upload--photo {
  border-style: solid;
  border-color: transparent;
  background-size: cover;
  background-position: center;
}
.photo-upload--photo .photo-upload__icon,
.photo-upload--photo .photo-upload__text {
  display: none;
}
.photo-upload__icon {
  /* NON-TOKEN: 28px drives the bare .icon-holder glyph; no 28px icon token. */
  font-size: 28px;
  color: var(--card-create-fg);
}
/* upload caption — no text-* style ≤ 11px exists; font props kept (flagged). */
.photo-upload__text {
  font-family: var(--font-body);
  font-size: 10px;
  font-weight: var(--weight-medium);
  color: var(--text-brand);
  letter-spacing: 0.5px;
  text-transform: uppercase;
}

/* ---- css/confetti.css ---- */
/* ============================================
   Settlr — Confetti Utility (decorative animation)

   Pinned-overlay container with falling, rotating dots.
   Decorative only: pointer-events disabled, z-index 0
   so it sits behind interactive content.

   Used by: welcome.html, create-group-done.html,
            settle-success.html.

   Usage:
     <div class="confetti">
       <div class="confetti__dot"
            style="width: 8px; height: 8px;
                   left: 15%; top: 20%;
                   background: var(--color-olive-300);
                   animation-delay: 0.3s;"></div>
       ...repeat for each dot
     </div>

   The position (left/top), size (width/height), color
   (background) and stagger (animation-delay) are
   parameterized inline per-dot so the same utility
   serves multiple celebratory contexts without modifier
   classes.

   Modifier:
     .confetti--slow  — slower fall (2.5s) for a calmer
                        welcome feel; default is 2s.

   Tokens: none required — colors come from existing
   primitive palette (olive/green) referenced inline at
   the screen level. Radius uses --radius-full.
   ============================================ */

.confetti {
  position: fixed;
  inset: 0;
  max-width: 393px;
  margin: 0 auto;
  pointer-events: none;
  overflow: hidden;
  z-index: 0;
}

.confetti__dot {
  position: absolute;
  border-radius: var(--radius-full);
}

@media (prefers-reduced-motion: no-preference) {
  .confetti__dot {
    animation: confettiFall 2s var(--ease-out) both;
  }
}

@media (prefers-reduced-motion: reduce) {
  .confetti__dot { display: none; }
}

.confetti--slow .confetti__dot {
  animation-duration: 2.5s;
}

@keyframes confettiFall {
  0%   { opacity: 1; transform: translateY(-20px) rotate(0deg)   scale(1); }
  100% { opacity: 0; transform: translateY(120px) rotate(360deg) scale(0.3); }
}

/* ---- css/index.css ---- */


/* Global motion — must come last to override component transitions */

/* ---- css/motion.css ---- */
/* ============================================
   Settlr Motion — global animations & transitions
   Performance-first: cheap properties only (transform, opacity).
   No box-shadow / background-color in transitions.
   No body-level animations (forces full-page repaints).
   ============================================ */

@media (prefers-reduced-motion: no-preference) {

  /* ── Tap / press feedback ────────────────────────────────
     Only `transform` is transitioned — composite-only, GPU-friendly.
     Listening for `transitionend` is cheap per element. */

  .btn,
  .icon-btn,
  .chip,
  .currency-chip,
  .toggle-control,
  .type-chip,
  .card-create,
  .summary-card,
  .invite-banner,
  .settings-row,
  .detail-row,
  .radio-item,
  .radio-item-boxed,
  .checkbox-item {
    transition: transform var(--duration-fast) var(--ease-out);
    will-change: transform;
  }

  .btn:active,
  .card-create:active,
  .summary-card:active,
  .invite-banner:active,
  .settings-row:active,
  .detail-row:active,
  .radio-item:active,
  .radio-item-boxed:active,
  .checkbox-item:active,
  .type-chip:active {
    transform: scale(var(--press-scale));
  }

  .icon-btn:active,
  .chip:active,
  .currency-chip:active,
  .toggle-control:active {
    transform: scale(var(--press-scale-sm));
  }

  /* List rows / cards: avoid scaling images during press —
     subpixel rescaling on photos looks blurry & laggy.
     Use a subtle opacity dim instead. */
  .person-item,
  .expense-item,
  .update-item,
  .group-row,
  .balance-row,
  .card-group {
    transition: opacity var(--duration-fast) var(--ease-out);
  }

  .person-item:active,
  .expense-item:active,
  .update-item:active,
  .group-row:active,
  .balance-row:active,
  .card-group:active {
    opacity: 0.7;
  }

  /* ── Avatar / photo fade-in ──────────────────────────────
     Photos in avatar tiles, group cards, and balance rows fade
     in once. Decoded image paint coincides with `to` keyframe. */
  @keyframes settlr-img-fade-in {
    from { opacity: 0; }
    to   { opacity: 1; }
  }

  .avatar--photo img,
  .card-group__image img,
  .person-item__group-icon img,
  .group-row__icon img,
  .balance-row__avatar img {
    animation: settlr-img-fade-in var(--duration-base) var(--ease-out) both;
  }

  /* ── Sheet / overlay open animations ─────────────────────
     One-shot keyframes that fire whenever a .sheet is shown. The sheet slides
     fully up from the bottom edge (translateY 100% → 0) so it reads as a real
     bottom-sheet everywhere it's used. */
  @keyframes settlr-sheet-in {
    from { transform: translateY(100%); }
    to   { transform: translateY(0); }
  }

  @keyframes settlr-overlay-in {
    from { opacity: 0; }
    to   { opacity: 1; }
  }

  .sheet {
    animation: settlr-sheet-in var(--duration-slow) var(--ease-out) both;
  }

  .sheet-overlay {
    animation: settlr-overlay-in var(--duration-base) var(--ease-out) both;
  }

  /* ── Sheet / overlay close animations ────────────────────
     Added by JS (SettlrSheetDrag.close) while the sheet is still shown; the
     sheet slides back down and the overlay fades out, then the host hides it. */
  @keyframes settlr-sheet-out {
    from { transform: translateY(0); }
    to   { transform: translateY(100%); }
  }

  @keyframes settlr-overlay-out {
    from { opacity: 1; }
    to   { opacity: 0; }
  }

  .sheet-overlay.is-closing {
    animation: settlr-overlay-out var(--duration-base) var(--ease-in) both;
  }
  .sheet-overlay.is-closing .sheet {
    animation: settlr-sheet-out var(--duration-base) var(--ease-in) both;
  }
}

/* ---- css/transitions.css ---- */
/* ============================================
   Settlr — View Transitions
   Cross-document page transitions via the View Transitions API.
   Direction class on <html> selects the animation.
   Set by js/router.js based on link intent (data-tx attribute,
   route table, or browser back).
   ============================================ */

/* Enable cross-document view transitions on every page that loads
   this stylesheet (effectively all of them). */
@view-transition {
  navigation: auto;
}

/* ============================================
   Default crossfade (replace) — used when no
   direction class is applied (e.g. auth flow).
   ============================================ */
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: var(--duration-slow);
  animation-timing-function: var(--ease-out);
  animation-fill-mode: both;
}

/* ============================================
   Lateral — peer screens (Home ↔ People ↔ Activity)
   Right: outgoing slides left, incoming enters from right.
   Left: mirrored.
   ============================================ */
@keyframes settlr-tx-out-left  { to   { transform: translateX(-30%); opacity: 0.6; } }
@keyframes settlr-tx-in-right  { from { transform: translateX(100%); } }
@keyframes settlr-tx-out-right { to   { transform: translateX(30%);  opacity: 0.6; } }
@keyframes settlr-tx-in-left   { from { transform: translateX(-100%); } }

html.tx-lateral-right::view-transition-old(root) { animation-name: settlr-tx-out-left; }
html.tx-lateral-right::view-transition-new(root) { animation-name: settlr-tx-in-right; }

html.tx-lateral-left::view-transition-old(root)  { animation-name: settlr-tx-out-right; }
html.tx-lateral-left::view-transition-new(root)  { animation-name: settlr-tx-in-left; }

/* Persistent bottom dock during lateral tab transitions.
   Assigning a unique view-transition-name to .bottom-nav-bar
   pulls it out of the root transition group so the dock stays
   pinned to the viewport while only the content above slides.
   Default behavior between old and new is a crossfade — exactly
   right since the active-tab highlight differs between pages. */
html.tx-lateral-left  .bottom-nav-bar,
html.tx-lateral-right .bottom-nav-bar {
  view-transition-name: settlr-bottom-dock;
}

::view-transition-old(settlr-bottom-dock),
::view-transition-new(settlr-bottom-dock) {
  animation-duration: var(--duration-base);
  animation-timing-function: var(--ease-out);
}

/* ============================================
   Push — drill-down (forward)
   Outgoing parallaxes left ~30%, incoming slides full from right.
   ============================================ */
@keyframes settlr-tx-push-out { to   { transform: translateX(-30%); } }
@keyframes settlr-tx-push-in  { from { transform: translateX(100%); } }

html.tx-push::view-transition-old(root) { animation-name: settlr-tx-push-out; }
html.tx-push::view-transition-new(root) { animation-name: settlr-tx-push-in; }

/* ============================================
   Pop — back (mirror of push)
   Outgoing slides right (off-screen), incoming parallaxes back from left ~30%.
   ============================================ */
@keyframes settlr-tx-pop-out  { to   { transform: translateX(100%); } }
@keyframes settlr-tx-pop-in   { from { transform: translateX(-30%); } }

html.tx-pop::view-transition-old(root) { animation-name: settlr-tx-pop-out; }
html.tx-pop::view-transition-new(root) { animation-name: settlr-tx-pop-in; }

/* ============================================
   Modal-up — new task (Add Expense, Add Group, Settle)
   Incoming rises from below; outgoing dims slightly in place.
   ============================================ */
@keyframes settlr-tx-modal-in   { from { transform: translateY(100%); } }
@keyframes settlr-tx-modal-fade { to   { opacity: 0.5; } }

html.tx-modal-up::view-transition-old(root) {
  animation-name: settlr-tx-modal-fade;
  animation-duration: var(--duration-base);
}
html.tx-modal-up::view-transition-new(root) {
  animation-name: settlr-tx-modal-in;
}

/* ============================================
   Modal-down — dismissing the modal back to caller.
   ============================================ */
@keyframes settlr-tx-modal-out  { to   { transform: translateY(100%); } }
@keyframes settlr-tx-modal-restore { from { opacity: 0.5; } }

html.tx-modal-down::view-transition-old(root) {
  animation-name: settlr-tx-modal-out;
}
html.tx-modal-down::view-transition-new(root) {
  animation-name: settlr-tx-modal-restore;
  animation-duration: var(--duration-base);
}

/* ============================================
   Strict reduced-motion: cancel all transitions.
   ============================================ */
@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation: none !important;
  }
}
