/* ============================================
   GENERATED FILE — DO NOT HAND-EDIT.
   Built by build-css.py from css/index.css and its @import graph,
   followed by every css/screens/<slug>.css in build-shell.py's
   VIEWS order. Same bytes as css/dist/app.css up to the screen
   banner below. Every change here is lost on the next build.
   Edit the source file under css/, css/screens/ 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;
  }
}

/* ============================================================
   SCREEN STYLESHEETS BEGIN HERE — everything above this line is
   component CSS from css/index.css, everything below is
   css/screens/<slug>.css in build-shell.py's VIEWS order.
   The compiled shell loads the screen sheets AFTER css/dist/app.css,
   so screen rules beat component rules of equal specificity. That
   is load-bearing: screen CSS must stay LAST in this bundle.
   ============================================================ */

/* ---- css/screens/home-dashboard.css ---- */
/* ============================================
   Settlr — Home Dashboard screen layout
   Genuine screen-specific structure + component overrides only, scoped under
   [data-view="home-dashboard"] so they never leak into other views in the
   compiled shell. Component styling (status-bar, top-app-bar, avatar, btn,
   heading, card-group, card-create, expense-item, empty-state, bottom-nav)
   lives in component CSS. Typography is applied via text-* classes in markup,
   not font props here.

   The body-shell + duplicate `*{}` reset rules from the old inline <style>
   are dropped — the compiled shell (.app-shell / .view / .view__content)
   owns them now. This view keeps the shell's default bottom padding because
   it has a bottom-nav dock.
   ============================================ */

/* Pin the main tab-bar height so the title aligns across Home / Activity /
   People. Without this the bar only sets min-height and grows to fit its
   tallest child (here the 52px brand avatar), so each tab's header was a
   different thickness. 64px seats the avatar centered (align-items: center). */
[data-view="home-dashboard"] .top-app-bar { height: var(--spacing-64); }

/* ── Hero / Balance Area ──
   Screen-local feature band above the scroll content. */
[data-view="home-dashboard"] .hero {
  background: var(--btn-icon-bg);
  height: 200px;
  padding: var(--spacing-12) var(--spacing-16);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: var(--spacing-16);
  flex-shrink: 0;
}
[data-view="home-dashboard"] .hero__info {
  display: flex;
  flex-direction: column;
}
[data-view="home-dashboard"] .hero__label {
  color: var(--text-primary);
}
[data-view="home-dashboard"] .hero__amount {
  color: var(--heading-fg);
}
[data-view="home-dashboard"] .hero__actions {
  display: flex;
  gap: var(--spacing-8);
}

/* ── Cards Row (horizontal scroll) ──
   Screen-local carousel strip that holds the create card + group cards. */
[data-view="home-dashboard"] .cards-row {
  display: flex;
  gap: var(--spacing-12);
  padding: 0;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding-left: var(--spacing-16);
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
[data-view="home-dashboard"] .cards-row::-webkit-scrollbar { display: none; }
[data-view="home-dashboard"] .cards-row::before,
[data-view="home-dashboard"] .cards-row::after {
  content: '';
  min-width: var(--spacing-16);
  flex-shrink: 0;
}

/* ── Group Card (carousel overrides of shared .card-group) ──
   COMPONENT OVERRIDE TO PROMOTE → candidate `.card-group--carousel` variant.
   Shared .card-group is a fixed 161x206 grid tile; here it becomes a
   scroll-snap carousel card with a fixed 150px width, auto height (stretch),
   and a shorter 120px image. Kept scoped to avoid touching shared CSS. */
[data-view="home-dashboard"] .card-group {
  flex-shrink: 0;
  width: 150px;
  height: auto;
  scroll-snap-align: start;
  align-self: stretch;
}
[data-view="home-dashboard"] .card-group__image {
  height: 120px;
}
[data-view="home-dashboard"] .card-group__info {
  padding: var(--spacing-8);
  gap: var(--spacing-12);
}
[data-view="home-dashboard"] .card-group__info .card-group__amount {
  margin-top: 0;
}

/* ── Create Card (carousel overrides of shared .card-create) ──
   COMPONENT OVERRIDE TO PROMOTE → same `.card-group--carousel`/`.card-create`
   carousel sizing. Shared .card-create is a fixed 160x200 tile; here it gets
   the same 150px width + auto height (stretch) + scroll-snap so it sits
   flush with the group cards in the row. */
[data-view="home-dashboard"] .card-create {
  flex-shrink: 0;
  width: 150px;
  height: auto;
  scroll-snap-align: start;
  text-decoration: none;
  align-self: stretch;
}

/* ── Expense List (activity feed) ──
   COMPONENT OVERRIDE TO PROMOTE → the expense-item__text gap tweak overrides
   the shared list-items component. Kept scoped. */
[data-view="home-dashboard"] .expense-list { display: flex; flex-direction: column; }
[data-view="home-dashboard"] .expense-item__text { gap: var(--spacing-2); }

/* ── Bottom nav fills width (overrides shared .bottom-nav layout) ── */
[data-view="home-dashboard"] .bottom-nav-bar { padding: var(--spacing-16) var(--spacing-16) var(--spacing-24); }
[data-view="home-dashboard"] .bottom-nav { flex: 1; }
[data-view="home-dashboard"] .bottom-nav__tab { flex: 1; width: auto; }

/* ---- css/screens/people.css ---- */
/* ============================================
   Settlr — People screen layout
   Genuine screen-specific structure only, scoped under [data-view="people"]
   so it never leaks into other views in the compiled shell. Component styling
   (search-input, chip, person-item, avatar, empty-state, bottom-nav,
   top-app-bar, settings-row, sheet) lives in component CSS.
   Typography is applied via text-* classes in markup, not font props here.
   ============================================ */

/* ── Filter Chips ──
   Screen-local strip below the search field → promoted to the shared
   Header Chips component's `.header-chips--compact` modifier
   (css/header-chips.css; zero visual change). No longer scoped here. */

/* Pin the main tab-bar height so the title aligns across Home / Activity /
   People (matches home-dashboard / activity). The bar only sets min-height and
   would otherwise differ per tab based on its right-side action. */
[data-view="people"] .top-app-bar { height: var(--spacing-64); }

/* ── Person List ── */
[data-view="people"] .person-list { display: flex; flex-direction: column; }

/* ── Bottom nav fills width (overrides shared .bottom-nav layout) ── */
[data-view="people"] .bottom-nav-bar { padding: var(--spacing-16) var(--spacing-16) var(--spacing-24); }
[data-view="people"] .bottom-nav { flex: 1; }
[data-view="people"] .bottom-nav__tab { flex: 1; width: auto; }

/* ── Sheet hidden state (overrides .sheet-overlay's display:flex) ── */
[data-view="people"] .sheet-overlay[hidden] { display: none !important; }

/* ---- css/screens/activity.css ---- */
/* ============================================================
   Settlr — Activity screen layout
   Genuine screen-specific structure only, scoped under
   [data-view="activity"] so it never leaks into other views in the
   compiled shell. Component styling (search-input, chip, update-item,
   expense-item, empty-state, top-app-bar, bottom-nav) lives in component CSS.
   The handful of rules below are screen-level overrides of those shared
   components (kept scoped here, see "COMPONENT OVERRIDES TO PROMOTE"
   in the migration report). Typography on the title/list rows comes from
   component CSS + text-* classes already present in the rendered markup.
   ============================================================ */

/* Pin the main tab-bar height so the title aligns across Home / Activity /
   People (matches home-dashboard / people). The bar only sets min-height and
   would otherwise differ per tab based on its right-side action. */
[data-view="activity"] .top-app-bar { height: var(--spacing-64); }

/* Scrollable content region. activity HAS a bottom-nav dock, so it keeps the
   shell default bottom padding (do NOT override --app-shell-content-pad). */
[data-view="activity"] .view__content {
  /* default shell padding-bottom clears the floating bottom-nav dock */
}

/* ── Filter Chips ──
   Screen-level wrapper for the chip strip below the search field → promoted
   to the shared Header Chips component's `.header-chips--compact` modifier
   (css/header-chips.css; zero visual change). No longer scoped here. */

/* ── Expense List ── */
[data-view="activity"] .expense-list {
  display: flex;
  flex-direction: column;
}

/* ── Expense rows transparent on this screen (overrides component bg).
   .update-item is now transparent at the component level (css/update-item.css). ── */
[data-view="activity"] .expense-item {
  background: transparent;
}

/* update-item gets a divider on this screen (overrides component) */
[data-view="activity"] .update-item {
  border-bottom: var(--border-small) solid var(--contact-divider);
}

/* ── Bottom nav fills width (overrides component defaults) ── */
[data-view="activity"] .bottom-nav-bar { padding: var(--spacing-16) var(--spacing-16) var(--spacing-24); }
[data-view="activity"] .bottom-nav { flex: 1; }
[data-view="activity"] .bottom-nav__tab { flex: 1; width: auto; }

/* ---- css/screens/group-detail.css ---- */
/* ============================================
   Settlr — Group Detail screen layout
   Migrated from the former inline <style> in screens/group-detail.html.
   ALL rules scoped under [data-view="group-detail"] so nothing leaks into
   other views in the compiled shell. Component styling (hero-section,
   segment-control, empty-state, screen-footer, avatar, icon-btn) lives in
   component CSS. Typography is applied via text-* classes in markup where a
   clean snap exists; the display sizes (24/32px) below have no matching
   text-* token, so their font props stay here and are FLAGGED.

   NOTE — several rules below OVERRIDE shared component classes (.status-bar,
   .balance-row). They are kept scoped here per the hard rule and listed in the
   migration report under "COMPONENT OVERRIDES TO PROMOTE".
   ============================================ */

/* Scrollable content region. This screen has a fixed .screen-footer (Settle up /
   Add expense), NOT a bottom-nav dock, so override the shell's dock clearance to
   clear the ~93px footer. The iOS home-indicator inset is already reserved by
   `.app-shell { padding-bottom: env(safe-area-inset-bottom) }`, so no env() term
   here (that would double-count). Tokenized (was a hardcoded 100px). */
[data-view="group-detail"] .view__content {
  --app-shell-content-pad: calc(var(--spacing-96) + var(--spacing-8));
  background: transparent;
}

/* ── Status Bar (overlaid on hero — absolute, like the original) ──
   OVERRIDE of shared .status-bar (component default is non-absolute). Kept
   scoped; flagged to promote as a hero-overlay status-bar variant. */
[data-view="group-detail"] .status-bar {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 var(--spacing-24);
  z-index: 10;
}
[data-view="group-detail"] .status-bar__icons {
  display: flex;
  align-items: center;
  gap: var(--spacing-4);
  color: var(--text-primary);
}

/* ── Info Section ── */
[data-view="group-detail"] .info-section {
  text-align: center;
  padding: var(--spacing-12) var(--spacing-16) var(--spacing-20);
  background: var(--surface-primary);
}
/* name — display 24px/30 bold. No exact text-* STYLE match (text-display-sm is
   24px but uses 28 line-height + -0.96 ls), but size/line-height now use tokens. */
[data-view="group-detail"] .info-section__name {
  font-family: var(--font-display);
  font-size: var(--font-size-24);
  font-weight: var(--weight-bold);
  letter-spacing: -0.72px;
  color: var(--text-primary);
  line-height: var(--line-height-30);
}
[data-view="group-detail"] .info-section__label {
  font-family: var(--font-body);
  font-size: var(--font-size-13);
  font-weight: var(--weight-medium);
  margin-top: var(--spacing-4);
}
[data-view="group-detail"] .info-section__label--owe { color: var(--expense-owe-fg); }
[data-view="group-detail"] .info-section__label--lent { color: var(--expense-lent-fg); }
/* amount — typography via .text-amount-md (32px black). Screen-local: spacing + color. */
[data-view="group-detail"] .info-section__amount {
  margin-top: var(--spacing-4);
}
[data-view="group-detail"] .info-section__amount--owe { color: var(--expense-owe-fg); }
[data-view="group-detail"] .info-section__amount--lent { color: var(--expense-lent-fg); }

/* ── Segment Wrapper ── */
[data-view="group-detail"] .segment-wrap {
  padding: 0 var(--spacing-16) var(--spacing-16);
  background: var(--surface-primary);
}

/* ── Tab Panels ── */
[data-view="group-detail"] .tab-panel { display: none; }
[data-view="group-detail"] .tab-panel.is-active { display: block; }

/* ── Transaction Item ── now a shared component (css/txn-item.css) ── */

/* ── Balances Tab ── .balance-row → shared component css/balance-row.css */

/* ── Empty State (hidden by default; shown when a tab list is empty) ── */
[data-view="group-detail"] .tab-empty { display: none; }
[data-view="group-detail"] .tab-panel.is-empty .tab-empty { display: flex; }

/* ---- css/screens/individual-detail.css ---- */
/* ============================================
   Settlr — Individual (contact) Detail screen layout
   Migrated from the former inline <style> in screens/individual-detail.html.
   ALL rules scoped under [data-view="individual-detail"] so nothing leaks into
   other views in the compiled shell. Component styling (hero-section,
   segment-control, empty-state, screen-footer, avatar, icon-btn, avatar-stack)
   lives in component CSS. Typography is applied via text-* classes in markup
   where a clean snap exists; the display sizes (24/32px) below have no matching
   text-* token, so their font props stay here and are FLAGGED.

   NOTE — several rules below OVERRIDE / extend shared patterns:
     - .status-bar is forced absolute to overlay the hero (component default is
       non-absolute) — same override group-detail flagged.
     - the .group-row family here is the contact's "Common Groups" list layout
       (Render.groupRow markup) which is screen-specific, NOT the shared
       .group-row component CSS. Kept scoped and listed under "COMPONENT
       OVERRIDES TO PROMOTE" in the migration report (the .balance-row* family
       group-detail flagged is, here, the analogous .group-row* family).
   ============================================ */

/* Scrollable content region. This screen has a fixed .screen-footer (Settle up /
   Add expense), NOT a bottom-nav dock, so override the shell's dock clearance to
   clear the ~93px footer. The iOS home-indicator inset is already reserved by
   `.app-shell { padding-bottom: env(safe-area-inset-bottom) }`, so no env() term
   here (that would double-count). Tokenized (was a hardcoded 100px). */
[data-view="individual-detail"] .view__content {
  --app-shell-content-pad: calc(var(--spacing-96) + var(--spacing-8));
  background: transparent;
}

/* ── Status Bar (overlaid on hero — absolute, like the original) ──
   OVERRIDE of shared .status-bar (component default is non-absolute). Kept
   scoped; flagged to promote as a hero-overlay status-bar variant. */
[data-view="individual-detail"] .status-bar {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 var(--spacing-24);
  z-index: 10;
}
[data-view="individual-detail"] .status-bar__icons {
  display: flex;
  align-items: center;
  gap: var(--spacing-4);
  color: var(--text-primary);
}

/* ── Info Section ── */
[data-view="individual-detail"] .info-section {
  text-align: center;
  padding: var(--spacing-12) var(--spacing-16) var(--spacing-20);
  background: var(--surface-primary);
}
/* name — display 24px/30 bold. No exact text-* STYLE match (text-display-sm is
   24px but uses 28 line-height + -0.96 ls), but size/line-height now use tokens. */
[data-view="individual-detail"] .info-section__name {
  font-family: var(--font-display);
  font-size: var(--font-size-24);
  font-weight: var(--weight-bold);
  letter-spacing: -0.72px;
  color: var(--text-primary);
  line-height: var(--line-height-30);
}
[data-view="individual-detail"] .info-section__label {
  font-family: var(--font-body);
  font-size: var(--font-size-13);
  font-weight: var(--weight-medium);
  margin-top: var(--spacing-4);
}
[data-view="individual-detail"] .info-section__label--owe { color: var(--expense-owe-fg); }
[data-view="individual-detail"] .info-section__label--lent { color: var(--expense-lent-fg); }
/* amount — typography via .text-amount-md (32px black). Screen-local: spacing + color. */
[data-view="individual-detail"] .info-section__amount {
  margin-top: var(--spacing-4);
}
[data-view="individual-detail"] .info-section__amount--owe { color: var(--expense-owe-fg); }
[data-view="individual-detail"] .info-section__amount--lent { color: var(--expense-lent-fg); }

/* ── Segment Wrapper ── */
[data-view="individual-detail"] .segment-wrap {
  padding: 0 var(--spacing-16) var(--spacing-16);
  background: var(--surface-primary);
}

/* ── Tab Panels ── */
[data-view="individual-detail"] .tab-panel { display: none; }
[data-view="individual-detail"] .tab-panel.is-active { display: block; }

/* Favourite star — golden when active. Uses the gold `--label-warning-fg`
   semantic token (→ --color-gold-500 #B8860B), so the previous hardcoded hex
   fallback is gone with zero visual change. */
[data-view="individual-detail"] #js-fav-btn.is-favourite { color: var(--label-warning-fg); }

/* ── Transaction Item ── now a shared component (css/txn-item.css).
   Illustration radius standardized to --radius-8 (was --radius-12 here). ── */

/* ── Common Groups Tab ── .group-row → shared component css/group-row.css */

/* ── Empty State (hidden by default; shown when a tab list is empty) ── */
[data-view="individual-detail"] .tab-empty { display: none; }
[data-view="individual-detail"] .tab-panel.is-empty .tab-empty { display: flex; }

/* ---- css/screens/settings.css ---- */
/* ============================================
   Settlr — Settings screen layout
   Genuine screen-specific structure only, scoped under [data-view="settings"]
   so it never leaks into other views in the compiled shell. Component styling
   (settings-row, toggle, avatar, top-app-bar) lives in component CSS.
   Typography is applied via text-* classes in markup, not font props here.
   ============================================ */

[data-view="settings"] .view__content {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-24);
  /* No bottom dock on this screen — override the shell's dock clearance. */
  padding: var(--spacing-8) var(--spacing-16) var(--spacing-32);
}

/* ── Profile hero ── */
[data-view="settings"] .profile-hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--spacing-12);
  padding: var(--spacing-16) 0 var(--spacing-8);
}

[data-view="settings"] .profile-hero__avatar-wrap {
  position: relative;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* Edit badge = Icon Button (.icon-btn.icon-btn--surface.icon-btn--xs); screen-local
   bits: avatar-overlap position, the page-bg ring border, the 28px footprint
   (overrides icon-btn--xs 32; no spacing token — flagged), and the muted icon. */
[data-view="settings"] .profile-hero__edit-badge {
  position: absolute;
  bottom: var(--spacing-2);
  right: var(--spacing-2);
  width: 28px;
  height: 28px;
  border: var(--border-large) solid var(--surface-primary);
  color: var(--text-secondary);
}

/* Handle subtitle (@handle) — text style via .text-body-sm in markup; only
   color + spacing live here (line-height snaps 18→21, accepted minor delta).
   Was .profile-hero__phone until 2026-08-06; phone left the product in Phase 0
   and the seed number was leaking to every real user. */
[data-view="settings"] .profile-hero__handle {
  color: var(--text-tertiary);
  margin-top: calc(-1 * var(--spacing-4));
}

/* ── App version footer ── text style via .text-body-xs in markup. ── */
[data-view="settings"] .app-version {
  text-align: center;
  padding: var(--spacing-8) 0 var(--spacing-16);
  color: var(--text-tertiary);
}

/* ── Preference picker sheets (Currency / Default Split / Language) ──
   settings.js injects bare .detail-row elements into .sheet__content. The
   Detail Row component deliberately carries no horizontal padding (its parent
   is expected to supply the inset), and .sheet__content carries none either
   (css/bottom-sheet.css — see the same note in js/confirm-sheet.js), so the
   rows rendered edge-to-edge: on a real device the ₹/$/€/£ icon tiles and the
   radio dots were clipped by the sheet's own rounded corners, while the sheet
   header above them sat correctly inset. Inset the list to match the header
   (--spacing-16) and give the last row breathing room above the safe area.
   Scoped to the three settings pickers so no other sheet is double-padded. */
[data-view="settings"] #js-pref-currency-list,
[data-view="settings"] #js-pref-split-list,
[data-view="settings"] #js-pref-language-list {
  padding: 0 var(--spacing-16) var(--spacing-24);
}

/* The final option needs no divider once the list is inset. */
[data-view="settings"] #js-pref-currency-list .detail-row:last-child,
[data-view="settings"] #js-pref-split-list .detail-row:last-child,
[data-view="settings"] #js-pref-language-list .detail-row:last-child {
  border-bottom: none;
}

/* ---- css/screens/edit-profile.css ---- */
/* ============================================
   Settlr — Edit Profile screen layout
   Genuine screen-specific structure only, scoped under [data-view="edit-profile"]
   so it never leaks into other views in the compiled shell. Component styling
   (avatar, btn, input-field, notes-card, top-app-bar) lives in component CSS.
   Typography is applied via text-* classes in markup, not font props here.
   ============================================ */

[data-view="edit-profile"] .view__content {
  flex: 1;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  /* No bottom dock on this screen, but there IS a fixed .screen-footer holding
     "Save Changes" (~96px: --spacing-12 top + a .btn--lg + --spacing-32 bottom).
     This used to override the shell clearance down to --spacing-32, which is
     less than the footer is tall — so the Bio textarea and its character
     counter sat underneath the footer and could not be scrolled into view.
     Reserve the footer's height instead. */
  padding-bottom: calc(var(--spacing-96) + var(--spacing-16));
}

/* ── Avatar Section ── */
[data-view="edit-profile"] .avatar-section {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--spacing-12);
  padding: var(--spacing-24) var(--spacing-16) var(--spacing-16);
}
[data-view="edit-profile"] .avatar-wrap {
  position: relative;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
/* Camera badge = Icon Button (.icon-btn.icon-btn--primary.icon-btn--xs); only the
   avatar-overlap position + the white ring border are screen-local. */
[data-view="edit-profile"] .avatar-camera {
  position: absolute;
  bottom: var(--spacing-2);
  right: var(--spacing-2);
  border: var(--border-large) solid var(--surface-card);
}
/* Hint text — text style via .text-body-xs in markup; only color lives here.
   (snap: 12px/regular kept; line-height 18→19 minor delta, accepted) */
[data-view="edit-profile"] .avatar-hint {
  color: var(--text-tertiary);
}

/* ── Settlr ID Banner ── */
[data-view="edit-profile"] .id-banner {
  margin: 0 var(--spacing-16) var(--spacing-16);
  padding: var(--spacing-12) var(--spacing-16);
  background: var(--card-create-bg);
  border-radius: var(--radius-12);
  border: var(--border-small) solid var(--card-create-border);
  display: flex;
  align-items: center;
  gap: var(--spacing-12);
}
[data-view="edit-profile"] .id-banner__icon {
  width: 36px;
  height: 36px;
  border-radius: var(--radius-full);
  background: var(--card-create-icon-bg);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  color: var(--text-brand);
}
[data-view="edit-profile"] .id-banner__icon .icon-holder { font-size: var(--font-size-18); }
[data-view="edit-profile"] .id-banner__text { flex: 1; }
/* Banner label — text style via .text-overline-md in markup (display family,
   12px, uppercase). The token is medium/1.76px/lh14 but the original was
   semibold/1.54px/lh16, so weight + letter-spacing are kept here to preserve
   ZERO visual change (no 12px-semibold-uppercase token exists). Flagged in the
   migration report for a future overline-strong token. */
[data-view="edit-profile"] .id-banner__label {
  color: var(--text-brand);
  font-weight: var(--weight-semibold);
  letter-spacing: 1.54px;
}
/* Banner value — text style via .text-heading-sm in markup (display/18px/bold).
   Original letter-spacing -0.36px and line-height 24px match the token exactly.
   color + spacing kept here. */
[data-view="edit-profile"] .id-banner__value {
  color: var(--text-primary);
  margin-top: var(--spacing-2);
}
[data-view="edit-profile"] .id-banner__copy {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-brand);
  padding: var(--spacing-4);
  -webkit-tap-highlight-color: transparent;
}
[data-view="edit-profile"] .id-banner__copy .icon-holder { font-size: var(--icon-md); }

/* ── Form ── */
[data-view="edit-profile"] .form-section {
  padding: 0 var(--spacing-16);
  display: flex;
  flex-direction: column;
  gap: var(--spacing-16);
}

/* ── Section Divider ── */
[data-view="edit-profile"] .form-divider {
  height: 1px;
  background: var(--border-subtle);
  margin: var(--spacing-8) 0;
}

/* ── Bio field label (UX-08) — normalize casing to match .input-field__label
   (the notes-card uppercase overline stays intact on other screens). ── */
[data-view="edit-profile"] .notes-card__label {
  text-transform: none;
  letter-spacing: normal;
  font-weight: var(--weight-medium);
  color: var(--input-label);
}

/* ── Settlr ID editor (revealed by the banner pencil) ──
   Screen-scoped layout (mirrors the id-banner / add-friend __prefix precedent).
   NOTE: the flex rule below would override the [hidden] attribute — the explicit
   [hidden] rule keeps the collapsed state real (same trap as .icon-btn). */
[data-view="edit-profile"] .handle-editor {
  margin: 0 var(--spacing-16) var(--spacing-16);
  display: flex;
  flex-direction: column;
  gap: var(--spacing-12);
}
[data-view="edit-profile"] .handle-editor[hidden] { display: none; }
[data-view="edit-profile"] .handle-editor__actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--spacing-8);
}
[data-view="edit-profile"] .input-field__prefix {
  color: var(--text-secondary);
  font-weight: var(--weight-semibold);
}

/* ---- css/screens/add-friend.css ---- */
/* ============================================
   Settlr — Add Friend screen layout
   Genuine screen-specific structure only, scoped under [data-view="add-friend"]
   so it never leaks into other views in the compiled shell. Component styling
   (search-input, search-wrap, btn, person-item, heading, top-app-bar) lives in
   component CSS. Typography is applied via text-* classes in markup where a
   text-* style matches; remaining color/spacing-only rules stay scoped here.

   COMPONENT OVERRIDES TO PROMOTE
   ------------------------------
   The following blocks are screen-unique compositions that duplicate the
   "card" + "list-avatar" patterns seen elsewhere. They are kept scoped here to
   avoid touching shared CSS during this migration, but are candidates to be
   promoted into components later:
     - .invite-card / .invite-link-row / .invite-link-box / .invite-card__divider
       / .share-row / .share-btn   → candidate "invite-card" component.
     - .qr-section / .qr-placeholder / .qr-text*   → candidate "qr-share" card.
     - .person-item__avatar-circle (+ --invite)   → overlaps the existing
       .avatar component (initials variant); these rows pre-date the avatar
       migration and should adopt .avatar--initials.

   NON-TOKEN VALUES (kept exact to guarantee zero visual change; flagged)
   ---------------------------------------------------------------------
     - .invite-link-box / .share-btn height: 40px  (no 40px spacing token)
     - .invite-card__divider::before/::after height: 1px (hairline; no token)
     - .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)
     - .person-item__avatar-circle width/height: 40px  (no 40px sizing token)
   ============================================ */

/* ── Invite Card ── .invite-card family → shared component css/invite-card.css */

/* ── QR Code section ── .qr-section family → shared component css/qr-section.css */

/* ── Person item avatars ──
   Conformed to the standard Avatar component: "On Settlr" rows use
   .avatar.avatar--initials.avatar--md (40px), and "Invite from Contacts"
   icon rows use .avatar.avatar--md.avatar--outline (the icon-holder inside
   carries .icon-holder--md to keep the glyph at 20px). No longer scoped here.
   See css/avatar.css for .avatar--outline. */

/* ── Content scroll clearance — footer-less flow screen ──
   No bottom-nav dock here; override the shell's dock clearance to match the
   footer-less flow-screen spacing used by settings/expense-detail. */
[data-view="add-friend"] {
  --app-shell-content-pad: var(--spacing-32);
}

/* ── No-results message (search filtered everything out) ── */
[data-view="add-friend"] .af-noresult {
  color: var(--text-tertiary);
  text-align: center;
  padding: var(--spacing-24) var(--spacing-16);
}
[data-view="add-friend"] .af-noresult[hidden] { display: none; }

/* ── QR overlay (minimal placeholder — to be redesigned) ──
   Composes the shared .sheet/.sheet-overlay; only the centered QR-preview
   content layout is screen-local. [hidden] override mirrors the people screen
   (the shared .sheet-overlay sets display:flex). */
[data-view="add-friend"] .sheet-overlay[hidden] { display: none !important; }
[data-view="add-friend"] .qr-sheet {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--spacing-16);
  padding: var(--spacing-24) var(--spacing-16) var(--spacing-32);
}

/* ── Add-a-new-contact inline form ── */
/* Inset 16px so the input boxes + full-width "Add contact" button float with
   the same gutters as the search pill and the invite/QR cards (the input-box
   and .btn--full both fill 100% of this container, so without the inset they
   stretch full-bleed to the screen edges). The list-style .heading carries its
   own 16px internal padding for full-bleed contexts — zero it here so its title
   still aligns at 16px, not 32px. */
[data-view="add-friend"] .add-contact {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-12);
  margin-bottom: var(--spacing-24);
  padding: 0 var(--spacing-16);
}
[data-view="add-friend"] .add-contact .heading {
  padding-left: 0;
  padding-right: 0;
}
[data-view="add-friend"] .add-contact__error {
  color: var(--input-helper-error);
}
[data-view="add-friend"] .input-field__prefix {
  color: var(--input-fg-default);
  flex-shrink: 0;
}

/* ---- css/screens/search.css ---- */
/* ============================================
   Settlr — Search screen layout
   Genuine screen-specific structure only, scoped under [data-view="search"]
   so it never leaks into other views in the compiled shell. Component styling
   (chip, empty-state, status-bar) lives in component CSS.
   Typography is applied via text-* classes in markup where a token snaps;
   only color + spacing live here. Icon sizing is applied to .icon-holder
   (replacing the former `i { font-size }` rules) so inline SVGs scale exactly
   as the Phosphor <i> glyphs did — zero visual change.

   This is a modal/utility overlay screen with NO bottom-nav dock, so the
   shell's default dock clearance is overridden to the original small padding.
   ============================================ */

/* No bottom dock on this screen — override the shell's dock clearance to the
   original .content padding-bottom (var(--spacing-32)). */
[data-view="search"] .view__content {
  --app-shell-content-pad: var(--spacing-32);
}

/* ── Search Bar ── */
[data-view="search"] .search-bar {
  display: flex;
  align-items: center;
  gap: var(--spacing-8);
  padding: var(--spacing-8) var(--spacing-16) var(--spacing-12);
  background: var(--surface-primary);
  flex-shrink: 0;
}
[data-view="search"] .search-bar__back {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-full);
  background: var(--btn-icon-bg);
  border: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--btn-icon-fg);
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
  flex-shrink: 0;
}
[data-view="search"] .search-bar__back:active { background: var(--btn-icon-bg-pressed); }
[data-view="search"] .search-bar__back .icon-holder { font-size: var(--icon-md); }

[data-view="search"] .search-bar__input-wrap {
  flex: 1;
  display: flex;
  align-items: center;
  gap: var(--spacing-8);
  height: 44px;
  padding: 0 var(--spacing-16);
  background: var(--input-bg-focused);
  border: var(--border-medium) solid var(--input-border-focused);
  border-radius: var(--radius-full);
}
[data-view="search"] .search-bar__input-wrap .icon-holder { font-size: var(--icon-sm); color: var(--text-brand); flex-shrink: 0; }
[data-view="search"] .search-bar__input-wrap 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;
}
[data-view="search"] .search-bar__input-wrap input::placeholder { color: var(--input-fg-default); }
[data-view="search"] .search-bar__clear {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-tertiary);
  display: none;
  align-items: center;
  -webkit-tap-highlight-color: transparent;
}
[data-view="search"] .search-bar__clear .icon-holder { font-size: var(--icon-sm); }

/* ── Section Header ── */
[data-view="search"] .section-header {
  padding: var(--spacing-12) var(--spacing-16) var(--spacing-4);
  display: flex;
  align-items: center;
  justify-content: space-between;
}
[data-view="search"] .section-header__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(--text-tertiary);
}
[data-view="search"] .section-header__action {
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-semibold);
  color: var(--text-brand);
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
  -webkit-tap-highlight-color: transparent;
}

/* ── Recent Search Chips Row ── */
[data-view="search"] .recents-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing-8);
  padding: var(--spacing-4) var(--spacing-16) var(--spacing-12);
}

/* ── Person Result Row ── */
[data-view="search"] .result-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);
  cursor: pointer;
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
}
[data-view="search"] .result-row:active { background: var(--contact-bg-selected); }
[data-view="search"] .result-row:last-child { border-bottom: none; }

[data-view="search"] .result-avatar {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-full);
  background: var(--contact-avatar-bg);
  color: var(--contact-avatar-fg);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: var(--font-size-14);
  font-weight: var(--weight-bold);
  flex-shrink: 0;
}
[data-view="search"] .result-avatar--group {
  background: var(--action-muted);
  color: var(--action-dark);
  border-radius: var(--radius-8);
}
[data-view="search"] .result-avatar--expense {
  background: var(--expense-owe-bg);
  color: var(--expense-owe-fg);
  border-radius: var(--radius-8);
}
[data-view="search"] .result-avatar--settlement {
  background: var(--expense-lent-bg);
  color: var(--expense-lent-fg);
  border-radius: var(--radius-full);
}
[data-view="search"] .result-avatar .icon-holder { font-size: var(--icon-md); }

[data-view="search"] .result-text { flex: 1; min-width: 0; }
[data-view="search"] .result-text__name {
  font-family: var(--font-body);
  font-size: var(--font-size-14);
  font-weight: var(--weight-semibold);
  color: var(--contact-name);
  line-height: var(--line-height-20);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
[data-view="search"] .result-text__meta {
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-regular);
  color: var(--contact-subtext);
  line-height: var(--line-height-18);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
[data-view="search"] .result-right {
  flex-shrink: 0;
  text-align: right;
}
[data-view="search"] .result-chevron { color: var(--text-faint); }
[data-view="search"] .result-chevron .icon-holder { font-size: var(--icon-sm); }

/* ── Divider ── */
[data-view="search"] .section-divider {
  height: 1px;
  background: var(--border-subtle);
  margin: var(--spacing-4) 0;
}

/* ── Highlight match ── */
[data-view="search"] mark {
  background: var(--card-create-bg);
  color: var(--text-brand);
  border-radius: var(--radius-2);
  /* NON-TOKEN: 0 1px padding — no spacing token for 1px; kept exact. */
  padding: 0 1px;
}

/* ============================================================
   COMPONENT OVERRIDES TO PROMOTE
   (none — no shared component CSS is overridden by this screen.
   .chip / .empty-state / .status-bar render with their stock styles.)
   ============================================================ */

/* ---- css/screens/create-group-name.css ---- */
/* ============================================================
   Settlr — Create Group (Name) screen layout
   Genuine screen-specific structure only, scoped under
   [data-view="create-group-name"] so it never leaks into other views in the
   compiled shell. Component styling (input-field, button, top-app-bar,
   step-progress, screen-footer) lives in component CSS. Typography is applied
   via text-* classes in markup where a text-* style matches; remaining
   color/spacing-only rules stay scoped here.

   COMPONENT OVERRIDES TO PROMOTE
   ------------------------------
   The following blocks are screen-unique compositions kept scoped here to
   avoid touching shared CSS during this migration, but are candidates to be
   promoted into components later:
     - .photo-area / .photo-upload / .photo-upload__icon / .photo-upload__text
       → candidate "photo-upload" / "image-picker" component (the dashed
       96px upload tile also appears on other group-creation steps).
     - .type-section / .type-section__label / .type-grid → candidate
       "field-group" + grid wrapper for the type-chip grid; .type-grid is a
       layout shell for the existing .type-chip component. (As of 2026-06-18 the
       grid IS populated — group-type templates Trip/Roommates/Couple/Event/Other
       render as .type-chip tiles, wired in js/views/create-group-name.js.)

   NON-TOKEN VALUES (kept exact to guarantee zero visual change; flagged)
   ---------------------------------------------------------------------
     - --app-shell-content-pad: 120px  (original .content bottom padding that
       cleared the fixed .screen-footer; no spacing token = 120px — kept exact)
     - .photo-upload width/height: 96px  (no 96px sizing token)
     - .photo-upload border: 2px dashed  (2px is --border-large, but the
       shorthand needs the dashed style; kept as 2px to avoid a visual change)
     - .photo-upload transition: all 0.15s ease  (no motion token in source;
       carried over verbatim — candidate to adopt --transition-tap later)
     - .photo-upload__icon font-size: 28px  (drives the bare .icon-holder
       glyph; no 28px icon token — --icon-lg is 24px, would change the visual)
     - .photo-upload__text font-size: 10px  (no text-* style ≤ 11px exists;
       10px font tokens were retired — font props kept to avoid a visual change)
     - .type-section__label font-size: 11px / letter-spacing: 1.76px  (no
       text-* style at 11px; retired token — font props kept exact)
   ============================================================ */

/* ── Content scroll clearance — footer screen (fixed .screen-footer dock) ──
   Override the shell's bottom-nav dock clearance. This screen has a fixed
   footer, not a bottom-nav dock; keep the original 120px bottom clearance
   exactly. (120px has no spacing token — flagged above.)

   The clearance is declared on the VIEW ROOT (matching create-group-members.css)
   and the content padding uses LONGHANDS, never the `padding` shorthand: the
   shorthand also sets padding-bottom, which out-specifies app-shell.css's
   `.view__content { padding-bottom: var(--app-shell-content-pad, …) }` and left
   the scroller with only 24px of clearance — the last ~56px of the Description
   field sat permanently under the fixed footer, unreachable at full scroll. */
[data-view="create-group-name"] {
  /* NON-TOKEN: 120px footer clearance — matches create-group-members; no
     spacing token for 120px; kept exact. */
  --app-shell-content-pad: 120px;
}
[data-view="create-group-name"] .view__content {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-32);
  padding-top: var(--spacing-24);
  padding-left: var(--spacing-24);
  padding-right: var(--spacing-24);
}

/* ── Group Photo Area ──
   .photo-area / .photo-upload family → promoted to shared component
   css/photo-upload.css (zero visual change). No longer scoped here. */

/* ── Type Section (screen-specific section header for the type-chip grid) ── */
[data-view="create-group-name"] .type-section {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-8);
}
/* section label — no text-* style at 11px exists; font props kept (flagged). */
[data-view="create-group-name"] .type-section__label {
  font-family: var(--font-body);
  font-size: 11px;
  font-weight: var(--weight-semibold);
  letter-spacing: 1.76px;
  text-transform: uppercase;
  color: var(--text-tertiary);
}
[data-view="create-group-name"] .type-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--spacing-8);
}

/* ── Default-currency picker ──
   The chip hugs its content inside the flex-column .input-field; the
   currency-list sheet rows reuse the shared .detail-row look
   (css/detail-row.css), only the list padding + horizontal inset are local. */
[data-view="create-group-name"] .currency-chip { align-self: flex-start; }
[data-view="create-group-name"] .currency-list { padding: var(--spacing-8) 0; }
[data-view="create-group-name"] .currency-list .detail-row {
  padding-left: var(--spacing-16);
  padding-right: var(--spacing-16);
}

/* ---- css/screens/create-group-members.css ---- */
/* ============================================
   Settlr — Add Members screen layout
   (file is screens/create-group-members.html — the 2nd step of group
   creation). Genuine screen-specific structure only, scoped under
   [data-view="create-group-members"] so it never leaks into other views in the
   compiled shell. Component styling (top-app-bar, step-progress, search-input,
   search-wrap, person-item, checkbox, member-pill, avatar, invite-banner,
   heading, screen-footer, button) lives in component CSS. Typography is applied
   via text-* classes in markup where a text-* style matches; remaining
   color/spacing-only rules stay scoped here.

   COMPONENT OVERRIDES TO PROMOTE
   ------------------------------
   The following blocks are screen-unique compositions kept scoped here to
   avoid touching shared CSS during this migration, but are candidates to be
   promoted into components later:
     - .selected-row (horizontal selected-members chip strip)  → candidate
       "member-pill row" / chip-strip layout shared with other selector flows
       (overlaps add-group's .selected-row almost exactly).
     - .invite-banner-wrap  → candidate outer-margin wrapper for the shared
       invite-banner component (the banner's spec says the parent applies the
       margin); overlaps a generic "banner wrap" padding utility.
     - .person-item.is-selected + .person-item__avatar-circle  → candidate
       "selectable contact row" composition. .person-item__avatar-circle is a
       40px initials circle distinct from the .avatar component (different
       size/token set), so it is kept screen-scoped rather than swapped to
       .avatar to guarantee zero visual change.
     - .contact-list  → candidate scroll-wrapper; in the compiled shell the
       scroll region is the view's .view__content, so .contact-list becomes a
       plain flow container and its original bottom clearance moves to
       --app-shell-content-pad (see bottom of file).

   NON-TOKEN VALUES (kept exact to guarantee zero visual change; flagged)
   ---------------------------------------------------------------------
     - .person-item__avatar-circle width/height: 40px  (no 40px sizing token)
   ============================================ */

/* ── Selected Members Row (screen-unique strip below search) ── */
[data-view="create-group-members"] .selected-row {
  display: flex;
  padding: var(--spacing-4) var(--spacing-16) var(--spacing-8);
  gap: var(--spacing-8);
  overflow-x: auto;
  scrollbar-width: none;
  flex-shrink: 0;
}
[data-view="create-group-members"] .selected-row::-webkit-scrollbar { display: none; }

/* ── Contact List ──
   In the compiled shell the scroll region is the view's .view__content; the
   list is a plain flow container inside it. The original screen's
   padding-bottom: 120px clearance moves to --app-shell-content-pad on the
   scroller (see bottom of file). */
[data-view="create-group-members"] .contact-list {
  flex: 1;
}

/* ── Selected state on person-item ── */
[data-view="create-group-members"] .person-item.is-selected {
  background: var(--contact-bg-selected);
}

/* ── Avatar circle for contact rows ──
   Conformed to the standard Avatar component
   (.avatar.avatar--initials.avatar--md, 40px) — rendered by
   js/views/create-group-members.js. No longer scoped here. */

/* ── Invite banner outer margin (per spec, parent applies margin) ── */
[data-view="create-group-members"] .invite-banner-wrap {
  padding: 0 var(--spacing-16) var(--spacing-8);
}

/* ── Content scroll clearance ──
   The original screen put a 120px bottom clearance on the scrolling
   .contact-list (to clear the fixed .screen-footer). In the shell the scroller
   is .view__content, so the same value is applied via --app-shell-content-pad
   to keep the scroll bottom clearance identical (zero visual change). */
[data-view="create-group-members"] {
  /* NON-TOKEN: 120px footer clearance — matches the original .contact-list
     padding-bottom: 120px; no spacing token for 120px; kept exact. */
  --app-shell-content-pad: 120px;
}

/* ---- css/screens/edit-group.css ---- */
/* ============================================
   Settlr — Edit Group screen layout
   Migrated from the former inline <style> in screens/edit-group.html.
   ALL rules scoped under [data-view="edit-group"] so nothing leaks into other
   views in the compiled shell. Component styling (hero-section, avatar,
   input-field, screen-footer, bottom-sheet, btn, icon-btn, section-label)
   lives in component CSS. Typography is applied via text-* classes in markup
   where a clean snap exists; the remaining font props below have no matching
   text-* token, so they stay here and are FLAGGED.

   NOTE — several rules below OVERRIDE shared component classes
   (.status-bar overlay, .sheet-overlay show/hide helper). They are kept scoped
   here per the hard rule and listed in the migration report under
   "COMPONENT OVERRIDES TO PROMOTE".
   ============================================ */

/* Whole-screen scroll: the hero + avatar live at the top of `.view__content`
   full-bleed (no side/top padding), and the form below carries its own padding
   + column gap via `.edit-group__form`. Keep the original 140px footer
   clearance (no spacing token — flagged). */
[data-view="edit-group"] .view__content {
  --app-shell-content-pad: 140px;
  background: var(--surface-primary);
}
[data-view="edit-group"] .edit-group__form {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-24);
  padding: var(--spacing-16) var(--spacing-16) 0;
}

/* ── Status Bar (overlaid on hero — absolute, like the original) ──
   OVERRIDE of shared .status-bar (component default is non-absolute). Kept
   scoped; flagged to promote as a hero-overlay status-bar variant. */
[data-view="edit-group"] .status-bar {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 var(--spacing-24);
  z-index: 10;
}
[data-view="edit-group"] .status-bar__icons {
  display: flex;
  align-items: center;
  /* 6px gap — no spacing token (between --spacing-4 and --spacing-8). Kept
     exact to avoid a visual change. FLAGGED non-token value. */
  gap: 6px;
  color: var(--text-primary);
}

/* ── Members List (screen-unique) ── */
[data-view="edit-group"] .members-list {
  background: var(--surface-card);
  border-radius: var(--radius-12);
  overflow: hidden;
  border: var(--border-small) solid var(--border-subtle);
}
[data-view="edit-group"] .member-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);
}
[data-view="edit-group"] .member-row:last-child { border-bottom: none; }
[data-view="edit-group"] .member-row__avatar {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-full);
  background: var(--contact-avatar-bg);
  color: var(--contact-avatar-fg);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
[data-view="edit-group"] .member-row__avatar--you {
  background: var(--btn-secondary-bg);
  color: var(--btn-secondary-fg);
}
[data-view="edit-group"] .member-row__text { flex: 1; display: flex; flex-direction: column; gap: var(--spacing-2); }
/* name — text style via .text-title-sm in markup (14/20 semibold — exact) */
[data-view="edit-group"] .member-row__name {
  color: var(--contact-name);
}
/* role — text style via .text-body-xs in markup (12/19 regular vs original
   12/18; +1px line-height delta — same delta accepted elsewhere). Flagged. */
[data-view="edit-group"] .member-row__role {
  color: var(--contact-subtext);
}
/* Remove control is the shared Icon Button (.icon-btn.icon-btn--destructive.icon-btn--xs);
   only the flex behaviour in the row is screen-local. */
[data-view="edit-group"] .member-row__remove { flex-shrink: 0; }

/* ── Add Member Row (screen-unique) ── */
[data-view="edit-group"] .add-member-row {
  display: flex;
  align-items: center;
  gap: var(--spacing-12);
  padding: var(--spacing-12) var(--spacing-16);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
[data-view="edit-group"] .add-member-row:active { background: var(--surface-primary); }
[data-view="edit-group"] .add-member-row__icon {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-full);
  background: var(--surface-primary);
  border: var(--border-small) dashed var(--border-default);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-tertiary);
  flex-shrink: 0;
}
[data-view="edit-group"] .add-member-row__icon .icon-holder { width: 18px; height: 18px; }
/* label — text style via .text-body-md in markup (14/23 — original was 14/500
   medium; .text-body-md is 14/400 regular. Weight differs, so keep weight +
   color here and FLAG. */
[data-view="edit-group"] .add-member-row__label {
  font-family: var(--font-body);
  font-size: var(--font-size-14);
  font-weight: var(--weight-medium);
  color: var(--text-brand);
}

/* ── Danger Zone (screen-unique) ── */
[data-view="edit-group"] .danger-card {
  background: var(--expense-owe-bg);
  border-radius: var(--radius-12);
  overflow: hidden;
  border: var(--border-small) solid var(--card-group-owe-border);
}
[data-view="edit-group"] .danger-row {
  display: flex;
  align-items: center;
  gap: var(--spacing-12);
  padding: var(--spacing-16);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
[data-view="edit-group"] .danger-row:active { opacity: 0.7; }
[data-view="edit-group"] .danger-row__icon {
  width: 36px;
  height: 36px;
  border-radius: var(--radius-8);
  background: var(--label-error-bg);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
[data-view="edit-group"] .danger-row__icon .icon-holder { width: 18px; height: 18px; color: var(--label-error-fg); }
[data-view="edit-group"] .danger-row__text { flex: 1; display: flex; flex-direction: column; gap: var(--spacing-2); }
/* label — text style via .text-title-sm-ish (15px) has no token. Original was
   15/20 semibold; no matching text-* token (text-title-sm is 14px). Kept here,
   flagged. */
[data-view="edit-group"] .danger-row__label {
  font-family: var(--font-body);
  font-size: var(--font-size-15);
  font-weight: var(--weight-semibold);
  color: var(--expense-owe-fg);
  line-height: var(--line-height-20);
}
/* sublabel — text style via .text-body-xs in markup (12/19 vs original 12/18;
   +1px delta). Color + opacity stay here. Flagged. */
[data-view="edit-group"] .danger-row__sublabel {
  color: var(--expense-owe-fg);
  opacity: 0.7;
}
[data-view="edit-group"] .danger-row__chevron { color: var(--expense-owe-fg); opacity: 0.5; }
[data-view="edit-group"] .danger-row__chevron .icon-holder { width: 16px; height: 16px; }

/* ── Sheet visibility helper (overlay hidden by default) ──
   OVERRIDE of shared .sheet-overlay (component default is display:flex, always
   visible). This screen toggles sheets via .is-open. Kept scoped; flagged to
   promote as a canonical hidden-by-default sheet behavior. */
[data-view="edit-group"] .sheet-overlay { display: none; }
[data-view="edit-group"] .sheet-overlay.is-open { display: flex; }

/* ── Default-currency sheet rows → shared Detail Row component ──
   Rows reuse the shared .detail-row look (css/detail-row.css); only the list
   wrapper padding + the row's horizontal inset are screen-local. */
[data-view="edit-group"] .currency-list { padding: var(--spacing-8) 0; }
[data-view="edit-group"] .currency-list .detail-row {
  padding-left: var(--spacing-16);
  padding-right: var(--spacing-16);
}

/* ── Confirm sheet body copy (screen-unique) ──
   text style via .text-body-md in markup (14/23 regular vs original 14/22;
   +1px line-height delta — flagged). Only color + reset margin live here. */
[data-view="edit-group"] .confirm-sheet__body {
  color: var(--text-secondary);
  margin: 0;
}
/* Confirm sheet content padding column (was an inline style attribute). */
[data-view="edit-group"] .confirm-sheet__content {
  padding: var(--spacing-16);
  display: flex;
  flex-direction: column;
  gap: var(--spacing-16);
}
[data-view="edit-group"] .confirm-sheet__actions {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-8);
}

/* ── Avatar edit overlay ──
   The badge is the shared Icon Button (.icon-btn.icon-btn--surface.icon-btn--sm).
   Screen-local: the top-right overlap position, the page-bg ring border, the lift
   shadow, and the press feedback (avatar dims + badge scales). */
[data-view="edit-group"] .avatar-edit-btn { position: relative; display: inline-flex; }
[data-view="edit-group"] .avatar-edit-btn .avatar { transition: opacity 0.15s; }
[data-view="edit-group"] .avatar-edit-btn__overlay {
  position: absolute;
  right: -6px;
  top: -6px;
  border: var(--border-medium) solid var(--surface-primary);
  box-shadow: var(--shadow-sm);
}
[data-view="edit-group"] .avatar-edit-btn:active .avatar { opacity: var(--opacity-disabled); }
[data-view="edit-group"] .avatar-edit-btn:active .avatar-edit-btn__overlay { transform: scale(0.94); }

/* ── Emoji Picker (screen-unique grid inside the canonical bottom-sheet) ── */
[data-view="edit-group"] .emoji-grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: var(--spacing-8);
  padding: var(--spacing-16);
}
[data-view="edit-group"] .emoji-btn {
  width: 52px;
  height: 52px;
  border-radius: var(--radius-12);
  border: var(--border-small) solid var(--border-subtle);
  background: var(--surface-primary);
  font-size: var(--font-size-28);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: all 0.15s ease;
}
[data-view="edit-group"] .emoji-btn:active { background: var(--type-chip-bg-on); border-color: var(--type-chip-border-on); }
[data-view="edit-group"] .emoji-btn.is-selected { background: var(--type-chip-bg-on); border-color: var(--type-chip-border-on); }

/* ---- css/screens/add-amount.css ---- */
/* ============================================
   Settlr — Add Amount (Add Expense, step 1) screen layout
   Genuine screen-specific structure only, scoped under
   [data-view="add-amount"] so it never leaks into other views in the compiled
   shell. Component styling (currency-chip, bottom-sheet, screen-footer,
   step-progress, top-app-bar, input-field helper) lives in component CSS.
   Typography is applied via text-* classes in markup where an exact token
   exists; the few one-off type scales with no matching token are kept scoped
   below and flagged.
   ============================================ */

/* Scrollable content region. Mirrors the old standalone `.content-area`:
   flex column with a 100px bottom pad so the keyboard-aware fixed
   .screen-footer overlaps the tail exactly as before. This is a flow screen
   with a footer (not the bottom-nav dock), so override the shell's default
   dock clearance to clear the ~93px footer. Tokenized (was a hardcoded 100px);
   the iOS home-indicator inset is already reserved by .app-shell's env padding. */
[data-view="add-amount"] .view__content {
  --app-shell-content-pad: calc(var(--spacing-96) + var(--spacing-4));
  display: flex;
  flex-direction: column;
}

/* ── Amount Entry ── */
[data-view="add-amount"] .amount-area {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--spacing-16);
  padding: var(--spacing-32) var(--spacing-16) var(--spacing-24);
}

[data-view="add-amount"] .amount-row {
  display: flex;
  align-items: baseline;
  justify-content: center;
  /* UX-15: visible input affordance — hairline underline that brightens on
     focus, mirroring the .title-input pattern below. */
  padding-bottom: var(--spacing-4);
  border-bottom: var(--border-medium) solid var(--border-default);
  transition: border-color 0.15s;
}
[data-view="add-amount"] .amount-row:focus-within {
  border-bottom-color: var(--input-border-focused);
}

/* Per-expense currency chip — sits above the amount. In centered mode the
   .amount-area gap (16px) spaces it from the amount; in keyboard mode the area
   gap collapses to 0 (see .is-kbd below) so the chip carries its own 8px gap. */
[data-view="add-amount"].is-kbd .currency-chip { margin-bottom: var(--spacing-8); }

/* prefix — text style via .text-display-lg in markup */
[data-view="add-amount"] .amount-prefix {
  color: var(--text-primary);
  flex-shrink: 0;
}

/* field — text style via .text-display-lg in markup. caret-color + sizing
   only; min-width 1ch / width 2ch / 1ch caret are intrinsic-unit values, not
   spacing tokens — kept exact (flagged).
   NOTE: calc(100vw - 80px) max-width retained exactly. */
[data-view="add-amount"] .amount-field {
  color: var(--text-primary);
  background: transparent;
  border: none;
  outline: none;
  min-width: 1ch;
  width: 2ch;
  max-width: calc(100vw - 80px);
  padding: 0;
  text-align: left;
  caret-color: var(--text-brand);
}
[data-view="add-amount"] .amount-field::placeholder { color: var(--text-placeholder); }

/* ── Amount Error ── */
[data-view="add-amount"] .amount-error {
  padding: 0 var(--spacing-24);
  width: 100%;
  text-align: center;
}

/* ── Title + Category column (chip above text) ── */
[data-view="add-amount"] .title-cat-row {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--spacing-12);
  padding: 0 var(--spacing-32) var(--spacing-8);
}
[data-view="add-amount"] .title-cat-row .title-area {
  width: 100%;
  padding: 0;
}
[data-view="add-amount"] .title-cat-row .category-area {
  padding: 0;
}

/* ── Keyboard-open reflow ──
   When the soft keyboard is open the view root gets `.is-kbd` (set by the
   visualViewport handler in js/views/add-amount.js). The centered amount layout
   then collapses into a compact top-anchored stack — amount → category chip →
   title, each 16px apart, snug under the step-progress. The header stays put and
   the footer is lifted above the keyboard (inline bottom offset set by the same
   handler). Without `.is-kbd` the default centered design is unchanged. */
[data-view="add-amount"].is-kbd .amount-area {
  flex: 0 0 auto;
  justify-content: flex-start;
  /* drop the 16px gap to the (empty, hidden-helper) .amount-error so the chip
     sits exactly 16px under the amount, not 32px */
  gap: 0;
  padding: var(--spacing-16) var(--spacing-16) 0;
}
[data-view="add-amount"].is-kbd .title-cat-row {
  gap: var(--spacing-16);
  padding: var(--spacing-16) var(--spacing-32) 0;
}

/* ── Title Input ── */
[data-view="add-amount"] .title-area {
  padding: 0 var(--spacing-32) var(--spacing-8);
}

/* Inline validation for the title, mirroring .amount-error above: the title
   row is centre-aligned, so the helper is too. Hidden until #js-next finds
   the field empty (replaced a native alert(), which is suppressed in
   standalone PWA/TWA mode). */
[data-view="add-amount"] .title-area .input-field__helper--error {
  text-align: center;
  padding-top: var(--spacing-4);
}

/* title input — text style via .text-title-md in markup; structural + caret
   only here. */
[data-view="add-amount"] .title-input {
  width: 100%;
  background: transparent;
  border: none;
  border-bottom: var(--border-medium) solid var(--border-default);
  outline: none;
  color: var(--text-primary);
  text-align: center;
  padding: var(--spacing-8) 0;
  transition: border-color 0.15s;
  caret-color: var(--text-brand);
}
[data-view="add-amount"] .title-input::placeholder { color: var(--input-fg-default); }
[data-view="add-amount"] .title-input:focus { border-bottom-color: var(--input-border-focused); }

/* ── Category Selector ── */
[data-view="add-amount"] .category-area {
  padding: var(--spacing-8) var(--spacing-32) var(--spacing-8);
  display: flex;
  justify-content: center;
}
/* category chip — markup carries .text-title-xs, but this one-off chip scale
   (13px / semibold) has NO matching text-* token (text-title-xs is 12px,
   text-body-sm is 13px but regular). Kept scoped to preserve zero visual
   change; flagged in TYPOGRAPHY for a future token. */
[data-view="add-amount"] .category-chip-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-8);
  height: 40px;
  padding: 0 var(--spacing-16);
  background: var(--chip-bg-off);
  border: var(--border-small) solid var(--chip-border-off);
  border-radius: var(--radius-full);
  font-family: var(--font-body);
  font-size: var(--font-size-13);
  font-weight: var(--weight-semibold);
  color: var(--chip-fg-off);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
[data-view="add-amount"] .category-chip-btn.has-value {
  background: var(--chip-bg-on);
  border-color: var(--chip-border-on);
  color: var(--chip-fg-on);
}
[data-view="add-amount"] .category-chip-btn:active { opacity: 0.8; }
[data-view="add-amount"] .category-chip-btn__emoji { font-size: var(--font-size-16); line-height: 1; }
/* dynamic caret icon is now an inline-SVG .icon-holder; size via .icon-sm token */
[data-view="add-amount"] .category-chip-btn .icon-holder { width: var(--icon-sm); height: var(--icon-sm); }

/* ── Category Sheet Grid ── */
[data-view="add-amount"] .cat-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--spacing-8);
  padding: var(--spacing-8) var(--spacing-16) var(--spacing-16);
}
[data-view="add-amount"] .cat-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--spacing-4);
  padding: var(--spacing-12) var(--spacing-4);
  border-radius: var(--radius-12);
  border: var(--border-small) solid var(--border-subtle);
  background: var(--surface-card);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
[data-view="add-amount"] .cat-item:active { background: var(--contact-bg-selected); }
[data-view="add-amount"] .cat-item.is-selected {
  background: var(--contact-bg-selected);
  border-color: var(--input-border-focused);
}
/* 24px emoji glyph — not a spacing/type token; kept exact (flagged) */
/* color: duotone SVGs are fill=currentColor and must not inherit body text
   colour. Safe here — .cat-item.is-selected recolors only .cat-item__label.
   font-size stays load-bearing: a bare .icon-holder sizes off inherited font-size. */
[data-view="add-amount"] .cat-item__emoji { color: var(--text-primary); font-size: var(--font-size-24); line-height: 1; }
/* cat label — markup carries .text-caption-sm, but this one-off scale
   (12px / medium / line-height-16) has NO matching text-* token (caption-sm
   is regular / line-height-17). Kept scoped to preserve zero visual change;
   flagged in TYPOGRAPHY. */
[data-view="add-amount"] .cat-item__label {
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-medium);
  color: var(--text-secondary);
  text-align: center;
  line-height: var(--line-height-16);
}
[data-view="add-amount"] .cat-item.is-selected .cat-item__label { color: var(--text-brand); }

/* ── Auto-category pop feedback ── */
@keyframes addAmountCatPop {
  0%, 100% { transform: scale(1); }
  40%       { transform: scale(1.1); }
}
[data-view="add-amount"] .category-chip-btn.is-popping {
  animation: addAmountCatPop 0.22s ease;
}

/* ── Currency sheet rows → shared Detail Row component ──
   Each row is a `.detail-row.detail-row--clickable` (symbol in __icon, code in
   __value, name in __label, a radio in __radio; `.is-selected` fills it). Only
   the list wrapper padding + the row's horizontal inset are screen-local; the
   row look comes from css/detail-row.css. */
[data-view="add-amount"] .currency-list { padding: var(--spacing-8) 0; }
[data-view="add-amount"] .currency-list .detail-row {
  padding-left: var(--spacing-16);
  padding-right: var(--spacing-16);
}

/* ---- css/screens/add-group.css ---- */
/* ============================================
   Settlr — Select People screen layout
   (file is screens/add-group.html — the "Select People" step of the
   add-expense flow). Genuine screen-specific structure only, scoped under
   [data-view="add-group"] so it never leaks into other views in the compiled
   shell. Component styling (search-input, search-wrap, step-progress,
   top-app-bar, person-item, avatar, checkbox, member-pill, screen-footer,
   empty-state, input-field helper) lives in component CSS. Typography is
   applied via text-* classes in markup where a text-* style matches; remaining
   color/spacing-only rules stay scoped here.

   COMPONENT OVERRIDES TO PROMOTE
   ------------------------------
   The following blocks are screen-unique compositions kept scoped here to
   avoid touching shared CSS during this migration, but are candidates to be
   promoted into components later:
     - .selected-row (horizontal selected-people chip strip)  → candidate
       "member-pill row" / chip-strip layout shared with other selector flows.
     - .save-group-row / .save-group-row__* / .save-group-input  → candidate
       "save-as-group" inline-form row used by the people-selection flow.
     - .bottom-stack  → candidate "footer-stack" wrapper (an extra row stacked
       above .screen-footer); overlaps the screen-footer dock pattern.
     - .section-header (rendered by JS into the list)  → candidate shared
       "list section header" overline; overlaps .text-overline-md but keeps a
       distinct size/line-height/letter-spacing, so left as a screen-unique
       style (no exact text-* match — font props retained here).
     - .search-empty  → overlaps .empty-state; kept as an inline (search
       no-results) visibility wrapper around the shared empty-state markup.

   NON-TOKEN VALUES (kept exact to guarantee zero visual change; flagged)
   ---------------------------------------------------------------------
     - .save-group-row__icon width/height: 36px  (no 36px sizing token)
     - .save-group-row__icon font-size: var(--icon-sm)  (icon glyph size token,
       drives the bare emoji glyph — kept exact)
     - .save-group-input height: 40px  (no 40px control-height spacing token)
     - .section-header letter-spacing: 1.92px  (no letter-spacing token)
   ============================================ */

/* ── Selected People Chips Row (screen-unique strip below search) ── */
[data-view="add-group"] .selected-row {
  display: none;
  padding: 0 var(--spacing-16) var(--spacing-8);
  gap: var(--spacing-8);
  overflow-x: auto;
  scrollbar-width: none;
}
[data-view="add-group"] .selected-row::-webkit-scrollbar { display: none; }
[data-view="add-group"] .selected-row--visible { display: flex; }

/* ── List ──
   The combined Groups/Friends list. In the compiled shell the scroll region is
   the view's .view__content; the list is a plain flow container inside it. The
   bottom clearance for the fixed .bottom-stack lives on the scroller via
   --app-shell-content-pad (see bottom of file) — replicating the original
   .people-list padding-bottom: calc(var(--spacing-64) * 2 + var(--spacing-32)). */

/* Empty state inline (search no results) */
[data-view="add-group"] .search-empty {
  display: none;
  padding: var(--spacing-32) var(--spacing-16);
  text-align: center;
}
[data-view="add-group"] .search-empty--visible { display: block; }
[data-view="add-group"] .search-empty .empty-state__title {
  margin-bottom: var(--spacing-4);
}

/* Section header (rendered by JS — no static markup to carry a text-* class,
   and no exact text-* match: 12/semibold/lh16/ls1.92 uppercase). Font props
   retained here as a screen-unique style. */
[data-view="add-group"] .section-header {
  padding: var(--spacing-8) var(--spacing-16) var(--spacing-4);
  color: var(--text-tertiary);
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-semibold);
  /* NON-TOKEN: 1.92px tracking — no letter-spacing token; kept exact. */
  letter-spacing: 1.92px;
  text-transform: uppercase;
  line-height: var(--line-height-16);
  position: sticky;
  top: 0;
  background: var(--surface-primary);
  z-index: 2;
}

/* ── Bottom container holding save-as-group + screen-footer ── */
[data-view="add-group"] .bottom-stack {
  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 it never sits narrower than the
     content above it on >393px phones like Pro Max. */
  width: 100%;
  max-width: 100%;
  background: var(--surface-card);
  border-top: var(--border-small) solid var(--border-subtle);
  display: flex;
  flex-direction: column;
  z-index: 20;
}
@media (min-width: 480px) {
  [data-view="add-group"] .bottom-stack { max-width: 393px; }
}
[data-view="add-group"] .bottom-stack .screen-footer {
  position: static;
  transform: none;
  width: 100%;
  border-top: none;
}

/* Save-as-group row (screen-unique) */
[data-view="add-group"] .save-group-row {
  display: flex;
  flex-direction: column;
  border-bottom: var(--border-small) solid var(--border-subtle);
}
[data-view="add-group"] .save-group-row__trigger {
  display: flex;
  align-items: center;
  gap: var(--spacing-12);
  padding: var(--spacing-12) var(--spacing-16);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
[data-view="add-group"] .save-group-row__icon {
  /* NON-TOKEN: 36px tile — no sizing token; kept exact. */
  width: 36px;
  height: 36px;
  border-radius: var(--radius-8);
  background: var(--card-create-bg);
  display: flex;
  align-items: center;
  justify-content: center;
  /* NON-TOKEN(icon): drives the bare emoji glyph; kept exact (--icon-sm). */
  font-size: var(--icon-sm);
  flex-shrink: 0;
}
[data-view="add-group"] .save-group-row__text { flex: 1; }
/* title — no exact text-* match (13/semibold/lh18); font props kept here. */
[data-view="add-group"] .save-group-row__title {
  font-family: var(--font-body);
  font-size: var(--font-size-13);
  font-weight: var(--weight-semibold);
  line-height: var(--line-height-18);
  color: var(--text-primary);
}
/* sub — text style via .text-caption-sm in markup; only color stays here. */
[data-view="add-group"] .save-group-row__sub {
  color: var(--text-tertiary);
}

/* Group name input (shown when checked) */
[data-view="add-group"] .save-group-row__form {
  display: none;
  padding: 0 var(--spacing-16) var(--spacing-12);
  gap: var(--spacing-8);
}
[data-view="add-group"] .save-group-row__form--visible { display: flex; flex-direction: column; }

/* group name input — text style via .text-body-sm in markup (line-height
   snaps 18→21, accepted minor delta to reuse the token); box + color here. */
[data-view="add-group"] .save-group-input {
  width: 100%;
  /* NON-TOKEN: 40px control height — no spacing token; kept exact. */
  height: 40px;
  padding: 0 var(--spacing-12);
  background: var(--surface-primary);
  border: var(--border-medium) solid var(--input-border-default);
  border-radius: var(--radius-8);
  color: var(--text-primary);
  outline: none;
}
[data-view="add-group"] .save-group-input::placeholder { color: var(--input-fg-default); }
[data-view="add-group"] .save-group-input:focus { border-color: var(--input-border-focused); background: var(--input-bg-focused); }

/* Error state for group name input */
[data-view="add-group"] .save-group-input--error { border-color: var(--input-border-error); background: var(--input-bg-error); }

/* Disabled CTA */
[data-view="add-group"] .btn--disabled {
  opacity: var(--opacity-strong);
  pointer-events: none;
}

/* Visibility utility */
[data-view="add-group"] .is-hidden { display: none !important; }

/* ── Content scroll clearance ──
   The fixed .bottom-stack overlaps the page. The original screen put this
   clearance on the scrolling .people-list; in the shell the scroller is
   .view__content, so the same value is applied via --app-shell-content-pad to
   keep the scroll bottom clearance identical (zero visual change). */
[data-view="add-group"] {
  --app-shell-content-pad: calc(var(--spacing-64) * 2 + var(--spacing-32));
}

/* ---- css/screens/add-split.css ---- */
/* ============================================
   Settlr — Add Split screen layout
   Step 3 of the add-expense flow (the split editor). Genuine
   screen-specific structure only, scoped under [data-view="add-split"] so it
   never leaks into other views in the compiled shell. Component styling
   (segment-control, amount-input, checkbox, avatar, button, screen-footer,
   bottom-sheet, top-app-bar, step-progress) lives in component/navigation CSS.

   Typography is applied via text-* classes in MARKUP where an exact token
   style matches; the remaining font props (no matching text-* token, or a
   className that JS overwrites at runtime) are kept scoped and flagged below
   under NON-TOKEN VALUES / typography notes.
   ============================================ */

/* Scrollable content region. Mirrors the old standalone `.scroll-content`:
   the sections own their own padding (full-bleed rows), so the scroll
   container only carries the bottom clearance for the fixed .screen-footer.
   Original standalone pad was `calc(var(--spacing-96) + var(--spacing-4))`.
   Override the shell's bottom-nav dock clearance — this flow screen has a
   footer, not a dock. No top/horizontal padding (matches the original). */
[data-view="add-split"] .view__content {
  --app-shell-content-pad: calc(var(--spacing-96) + var(--spacing-4));
  /* Neutral/warm page bg (inherits the app-shell surface, matching the header
     and edit-expense) so the white .paid-by card and section blocks read. */
  background: var(--surface-primary);
}

/* Paid by → shared .paid-by component (--card variant); see css/paid-by.css.
   add-split is a full-bleed sheet, so inset the card from the screen edges. */
[data-view="add-split"] .paid-by {
  margin: var(--spacing-16);
}

/* ── Split header (screen-unique) ── */
[data-view="add-split"] .split-header {
  padding: var(--spacing-16);
  display: flex; flex-direction: column; gap: var(--spacing-16);
  background: var(--surface-card);
}
[data-view="add-split"] .split-summary {
  display: flex; align-items: center; justify-content: center;
  gap: var(--spacing-8); padding: var(--spacing-12);
  background: var(--card-create-bg); border-radius: var(--radius-8);
}
/* summary amount — display 14px/semibold has no matching text-* token
   (text-amount-xs is 13px); kept exact (see NON-TOKEN VALUES). */
[data-view="add-split"] .split-summary__amount {
  font-family: var(--font-display);
  font-size: var(--font-size-14);
  font-weight: var(--weight-semibold);
  color: var(--text-brand);
}
/* summary label — text style via .text-body-sm in markup */
[data-view="add-split"] .split-summary__label {
  color: var(--text-secondary);
}

/* ── Participant list (screen-unique) ── */
[data-view="add-split"] .participant-list {
  display: flex; flex-direction: column;
  background: var(--surface-card);
}
[data-view="add-split"] .participant-item {
  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);
}
[data-view="add-split"] .participant-item:last-child { border-bottom: none; }
/* Inactive participant: greyed text + checkbox, but the amount
   column stays interactive (click to reactivate). */
[data-view="add-split"] .participant-item--inactive .avatar,
[data-view="add-split"] .participant-item--inactive .participant-item__name,
[data-view="add-split"] .participant-item--inactive .participant-item__share { opacity: 0.5; }
[data-view="add-split"] .participant-item .checkbox-control { cursor: pointer; }
[data-view="add-split"] .participant-item__text { flex: 1; display: flex; flex-direction: column; gap: var(--spacing-2); }
/* name — text style via .text-title-sm in markup; only color overridden */
[data-view="add-split"] .participant-item__name {
  color: var(--contact-name);
}
/* share — text style via .text-body-xs in markup; only color overridden */
[data-view="add-split"] .participant-item__share {
  color: var(--contact-subtext);
}
[data-view="add-split"] .participant-item__amount {
  display: flex;
  align-items: center;
  justify-content: center;
  /* TODO(spacing): 120px column / 40px row have no spacing token — kept exact
     to avoid a visual change; see NON-TOKEN VALUES. */
  width: 120px;
  height: 40px;
  padding: var(--spacing-8);
  background: var(--amount-input-bg);
  border: var(--border-small) solid transparent;
  border-radius: var(--radius-8);
}
/* amount value — text style via .text-amount-sm in markup; only color
   overridden (display 16/regular/lh20/-0.32px == .text-amount-sm). */
[data-view="add-split"] .participant-item__amount-value {
  color: var(--amount-input-fg-disabled);
}

/* ── Total bar (screen-unique) ── */
[data-view="add-split"] .total-bar {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--spacing-12) var(--spacing-16);
  background: var(--btn-icon-bg);
  border-top: var(--border-medium) solid var(--border-default);
}
/* total label — text style via .text-title-sm in markup */
[data-view="add-split"] .total-bar__label {
  color: var(--text-secondary);
}
/* total value (ok/err) — display 13px/semibold. NO text-* snap: the view JS
   sets `el.className = 'total-bar__ok'|'total-bar__err'` at runtime, which
   would clobber any text-* class added in markup. Type kept scoped here so it
   survives the className swap. (see NON-TOKEN VALUES note.) */
[data-view="add-split"] .total-bar__ok {
  font-family: var(--font-display);
  font-size: var(--font-size-13);
  font-weight: var(--weight-semibold);
  color: var(--expense-lent-fg);
}
[data-view="add-split"] .total-bar__err {
  font-family: var(--font-display);
  font-size: var(--font-size-13);
  font-weight: var(--weight-semibold);
  color: var(--expense-owe-fg);
}

/* ── Split error message (screen-unique) ── */
/* type via .text-body-xs in markup; only color + spacing + display toggle
   live here. */
[data-view="add-split"] .split-error {
  color: var(--expense-owe-fg);
  padding: var(--spacing-4) var(--spacing-16);
  display: none;
}
[data-view="add-split"] .split-error--visible { display: block; }

/* Amount input in split context */
[data-view="add-split"] .participant-item .amount-input {
  /* TODO(spacing): 120px column width has no spacing token — kept exact. */
  width: 120px;
  flex-shrink: 0;
}

/* Payer-sheet rows + hint → shared css/payer-sheet.css (SettlrPayerSheet). */

/* ---- css/screens/add-review.css ---- */
/* ============================================
   Settlr — Add Review screen layout
   Final confirm step of the add-expense flow. Genuine screen-specific
   structure only, scoped under [data-view="add-review"] so it never leaks
   into other views in the compiled shell. Component styling (detail-row,
   notes-card, screen-footer, balance-pill color variants, top-app-bar,
   step-progress) lives in component/navigation CSS. Typography is applied
   via text-* classes in markup where an exact match exists; the remaining
   blocks below have NO exact text-* match (size/weight/ls differ) and so
   keep their own type, scoped, exactly as the original standalone screen.
   ============================================ */

/* Scrollable content region. Mirrors the old standalone `.scroll-content`:
   16px gap stack + the original bottom pad (the fixed .screen-footer overlaps
   the tail, exactly as before). Override the shell's bottom-nav dock clearance
   — this flow screen has a fixed footer, not a dock. Pad kept identical to the
   original: calc(--spacing-96 + --spacing-4) = 100px. */
[data-view="add-review"] .view__content {
  --app-shell-content-pad: calc(var(--spacing-96) + var(--spacing-4));
  display: flex;
  flex-direction: column;
  gap: var(--spacing-16);
}

/* ── Expense Hero (screen-unique) ── */
[data-view="add-review"] .expense-hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--spacing-12);
  padding: var(--spacing-24) var(--spacing-24) var(--spacing-20);
  margin: var(--spacing-8) var(--spacing-16) 0;
  border-radius: var(--radius-16);
  background: var(--surface-card);
  border: var(--border-small) solid var(--border-subtle);
  text-align: center;
}
/* category pill — text style via .text-label-xs in markup */
[data-view="add-review"] .expense-hero__category {
  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);
  color: var(--text-secondary);
}
/* amount — typography via .text-amount-lg (36px bold). Screen-local: color. */
[data-view="add-review"] .expense-hero__amount {
  color: var(--text-primary);
}
/* description — NO exact text-* match (body 16px / bold / no ls; .text-title-md
   is the same size/weight but adds ls -0.16px which would change rendering).
   Type kept scoped to preserve zero visual change. */
[data-view="add-review"] .expense-hero__desc {
  font-family: var(--font-body);
  font-size: var(--font-size-16);
  font-weight: var(--weight-bold);
  line-height: 24px; /* NON-TOKEN px — preserved exactly from original (matches --line-height-24 numerically) */
  color: var(--text-primary);
}
/* date — text style via .text-body-xs in markup */
[data-view="add-review"] .expense-hero__date {
  color: var(--contact-settled-fg);
}

/* ── Balance Pill (structural base — color comes from .balance-pill--*
   variants in css/labels.css, which only define the color modifiers). ── */
[data-view="add-review"] .expense-hero__balance,
[data-view="add-review"] .balance-pill {
  display: flex;
  align-items: center;
  padding: var(--spacing-8) var(--spacing-16);
  border-radius: var(--radius-8);
  width: 100%;
  justify-content: space-between;
}
/* label — NO exact text-* match (13px / semibold; no 13px-semibold class).
   Type kept scoped, exactly as original. */
[data-view="add-review"] .expense-hero__balance-label {
  font-size: var(--font-size-13);
  font-weight: var(--weight-semibold);
}
/* amount — NO exact text-* match (display 16px / bold / ls -0.32px; .text-amount-sm
   is display 16px but REGULAR weight). Type kept scoped, exactly as original. */
[data-view="add-review"] .expense-hero__balance-amount {
  font-family: var(--font-display);
  font-size: var(--font-size-16);
  font-weight: var(--weight-bold);
  letter-spacing: -0.32px; /* NON-TOKEN px — preserved exactly from original */
}

/* ── Detail Section wrapper (canonical detail-row used inside) ── */
[data-view="add-review"] .detail-section {
  padding: 0 var(--spacing-16);
  display: flex;
  flex-direction: column;
}

/* ── Section Divider ── */
[data-view="add-review"] .section-divider {
  height: var(--spacing-8);
  background: var(--btn-icon-bg);
}

/* ── Split Breakdown (screen-unique) ── */
[data-view="add-review"] .split-section {
  padding: 0 var(--spacing-16);
  display: flex;
  flex-direction: column;
  gap: var(--spacing-4);
}
[data-view="add-review"] .split-section__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--spacing-12) 0 var(--spacing-8);
}
/* section label — NO exact text-* match (12px / SEMIBOLD / ls 1.76px / uppercase;
   .text-overline-md is identical but MEDIUM weight). Type kept scoped, exactly
   as original. */
[data-view="add-review"] .split-section__label {
  font-size: var(--font-size-12);
  font-weight: var(--weight-semibold);
  letter-spacing: 1.76px; /* NON-TOKEN px — preserved exactly from original */
  text-transform: uppercase;
  color: var(--text-tertiary);
}
/* method — text style via .text-label-xs in markup */
[data-view="add-review"] .split-section__method {
  color: var(--text-brand);
}

[data-view="add-review"] .split-person {
  display: flex;
  align-items: center;
  gap: var(--spacing-12);
  padding: var(--spacing-8) 0;
}
/* avatar — text style via .text-title-xs (added in JS markup) */
[data-view="add-review"] .split-person__avatar {
  width: 32px; /* NON-TOKEN px — preserved exactly from original (avatar dimension) */
  height: 32px; /* NON-TOKEN px — preserved exactly from original (avatar dimension) */
  border-radius: var(--radius-full);
  background: var(--contact-avatar-bg);
  color: var(--contact-avatar-fg);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
/* name — text style via .text-title-sm (added in JS markup) */
[data-view="add-review"] .split-person__name {
  flex: 1;
  color: var(--text-primary);
}
/* amount — text style via .text-title-sm (added in JS markup) */
[data-view="add-review"] .split-person__amount--self { color: var(--expense-settled-fg); }
[data-view="add-review"] .split-person__amount--lent { color: var(--expense-lent-fg); }
[data-view="add-review"] .split-person__amount--owe { color: var(--expense-owe-fg); }

/* ── Notes Section wrapper (canonical notes-card used inside) ── */
[data-view="add-review"] .notes-section {
  padding: 0 var(--spacing-16);
}

/* ---- css/screens/expense-detail.css ---- */
/* ============================================
   Settlr — Expense Detail screen layout
   Genuine screen-specific structure only, scoped under
   [data-view="expense-detail"] so it never leaks into other views in the
   compiled shell. Component styling (detail-row, notes-card, screen-footer,
   balance-pill color variants, avatar, top-app-bar) lives in component CSS.
   Typography is applied via text-* classes in markup, not font props here.
   ============================================ */

/* Scrollable content region. 16px gap stack. The fixed .screen-footer (~97px)
   sits over the bottom of this scroll area, so the bottom pad must clear it or
   the last block (Notes) stays hidden behind the footer. Override the shell's
   bottom-nav dock clearance — this screen has a footer, not a dock. */
[data-view="expense-detail"] .view__content {
  --app-shell-content-pad: calc(var(--spacing-96) + var(--spacing-16));
  display: flex;
  flex-direction: column;
  gap: var(--spacing-16);
}

/* ── Expense Hero Card ── */
[data-view="expense-detail"] .expense-hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--spacing-12);
  padding: var(--spacing-24) var(--spacing-24) var(--spacing-20);
  margin: var(--spacing-8) var(--spacing-16) 0;
  border-radius: var(--radius-16);
  background: var(--surface-card);
  border: var(--border-small) solid var(--border-subtle);
  text-align: center;
}
/* category pill — text style via .text-label-xs in markup */
[data-view="expense-detail"] .expense-hero__category {
  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);
  color: var(--text-secondary);
}
/* amount — text style via .text-display-lg in markup */
[data-view="expense-detail"] .expense-hero__amount {
  color: var(--text-primary);
}
/* description — text style via .text-title-lg in markup */
[data-view="expense-detail"] .expense-hero__desc {
  color: var(--text-primary);
}

/* ── Balance Pill (structural base — color comes from .balance-pill--*
   variants in css/labels.css, which only define the color modifiers). ── */
[data-view="expense-detail"] .balance-pill {
  display: flex;
  align-items: center;
  gap: var(--spacing-8);
  padding: var(--spacing-8) var(--spacing-16);
  border-radius: var(--radius-8);
  width: 100%;
  justify-content: space-between;
}
/* label has no text-* class in markup (color inherits from pill) — keep its
   own type here. */
[data-view="expense-detail"] .balance-pill__label {
  font-family: var(--font-body);
  font-size: var(--font-size-13);
  font-weight: var(--weight-semibold);
}
/* amount — text style via .text-amount-sm in markup; ls retained inline to
   match the original render. */
[data-view="expense-detail"] .balance-pill__amount {
  letter-spacing: -0.32px;
}

/* ── Detail Section wrapper ── */
[data-view="expense-detail"] .detail-section {
  padding: 0 var(--spacing-16);
  display: flex;
  flex-direction: column;
}

/* ── Section Divider ── */
[data-view="expense-detail"] .section-divider {
  height: var(--spacing-8);
  background: var(--btn-icon-bg);
}

/* ── Split Breakdown ── */
[data-view="expense-detail"] .split-section {
  padding: 0 var(--spacing-16);
  display: flex;
  flex-direction: column;
  gap: var(--spacing-4);
}
[data-view="expense-detail"] .split-section__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--spacing-12) 0 var(--spacing-8);
}
/* section label — text style via .text-overline-md in markup */
[data-view="expense-detail"] .split-section__label {
  color: var(--text-tertiary);
}
/* method — text style via .text-label-xs in markup */
[data-view="expense-detail"] .split-section__method {
  color: var(--text-brand);
}

[data-view="expense-detail"] .split-person {
  display: flex;
  align-items: center;
  gap: var(--spacing-12);
  padding: var(--spacing-8) 0;
}
/* avatar — text style via .text-label-xs (added in JS markup) */
[data-view="expense-detail"] .split-person__avatar {
  width: 32px;
  height: 32px;
  border-radius: var(--radius-full);
  background: var(--contact-avatar-bg);
  color: var(--contact-avatar-fg);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
/* name — text style via .text-title-sm (added in JS markup) */
[data-view="expense-detail"] .split-person__name {
  flex: 1;
  color: var(--text-primary);
}
/* amount — text style via .text-title-sm (added in JS markup) */
[data-view="expense-detail"] .split-person__amount--self { color: var(--expense-settled-fg); }
[data-view="expense-detail"] .split-person__amount--lent { color: var(--expense-lent-fg); }
[data-view="expense-detail"] .split-person__amount--owe { color: var(--expense-owe-fg); }

/* ── Notes Section wrapper ── */
[data-view="expense-detail"] .notes-section {
  padding: 0 var(--spacing-16);
}

/* ── Comments Section ── */
[data-view="expense-detail"] .comments-section {
  padding: 0 var(--spacing-16);
  display: flex;
  flex-direction: column;
}
[data-view="expense-detail"] .comments-section__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--spacing-12) 0 var(--spacing-8);
}
/* section label — text style via .text-overline-md in markup */
[data-view="expense-detail"] .comments-section__label {
  color: var(--text-tertiary);
}
/* count — text style via .text-label-xs in markup */
[data-view="expense-detail"] .comments-section__count {
  color: var(--text-tertiary);
}
/* empty-state line — no text-* class in markup, keep its own type */
[data-view="expense-detail"] .comments-empty {
  padding: var(--spacing-8) 0 var(--spacing-12);
  font-family: var(--font-body);
  font-size: var(--font-size-13);
  color: var(--text-tertiary);
}
/* comment items are built in JS without text-* classes — keep type here */
[data-view="expense-detail"] .comment-item {
  display: flex;
  gap: var(--spacing-8);
  padding: var(--spacing-8) 0;
  border-bottom: var(--border-small) solid var(--border-subtle);
}
[data-view="expense-detail"] .comment-item__avatar {
  width: 28px;
  height: 28px;
  border-radius: var(--radius-full);
  background: var(--contact-avatar-bg);
  color: var(--contact-avatar-fg);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-semibold);
  flex-shrink: 0;
}
[data-view="expense-detail"] .comment-item__body {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-2);
}
[data-view="expense-detail"] .comment-item__meta {
  display: flex;
  align-items: baseline;
  gap: var(--spacing-8);
}
[data-view="expense-detail"] .comment-item__name {
  font-family: var(--font-body);
  font-size: var(--font-size-13);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
}
[data-view="expense-detail"] .comment-item__time {
  font-family: var(--font-body);
  font-size: var(--font-size-12);
  font-weight: var(--weight-regular);
  color: var(--text-tertiary);
}
[data-view="expense-detail"] .comment-item__text {
  font-family: var(--font-body);
  font-size: var(--font-size-14);
  font-weight: var(--weight-regular);
  line-height: var(--line-height-20);
  color: var(--text-primary);
}
/* ── Comment Input ──
   WhatsApp-style composer: avatar + a single-row .input-field--multiline that
   auto-grows (JS) up to ~5 lines then scrolls, with the send button OUTSIDE the
   field on the right. Row aligns to the bottom so the send button stays at the
   field's base as it grows. */
[data-view="expense-detail"] .comment-input {
  display: flex;
  align-items: flex-end;
  gap: var(--spacing-8);
  padding: var(--spacing-12) 0 var(--spacing-4);
}
/* the input-field fills the row between the avatar and the send button */
[data-view="expense-detail"] .comment-input .input-field {
  flex: 1;
  min-width: 0;
}
/* auto-grow textarea: JS sets height to scrollHeight; max-height caps it at
   ~5 lines and the textarea scrolls internally beyond that. */
[data-view="expense-detail"] .comment-input textarea {
  max-height: calc(var(--line-height-23) * 5);
  overflow-y: auto;
}
/* Send button is the shared Icon Button (.icon-btn.icon-btn--primary.icon-btn--md);
   only the flex behaviour in the row is screen-local. */
[data-view="expense-detail"] .comment-input__send { flex-shrink: 0; }

/* ── Footer action buttons ── */
/* edit — text style via .text-title-md in markup */
[data-view="expense-detail"] .btn-edit {
  flex: 1;
  display: flex;
  height: 52px;
  align-items: center;
  justify-content: center;
  gap: var(--spacing-8);
  border-radius: var(--radius-full);
  border: none;
  cursor: pointer;
  background: var(--btn-primary-bg);
  color: var(--btn-primary-fg);
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
}
[data-view="expense-detail"] .btn-edit:active { background: var(--btn-primary-bg-pressed); }
[data-view="expense-detail"] .btn-edit .icon-holder { font-size: var(--font-size-20); }
/* Delete is the shared Icon Button (.icon-btn.icon-btn--destructive.icon-btn--lg). */

/* ---- css/screens/edit-expense.css ---- */
/* ============================================
   Settlr — Edit Expense screen layout
   Genuine screen-specific structure only, scoped under
   [data-view="edit-expense"] so it never leaks into other views in the
   compiled shell. Component styling (chip, currency-chip, input-field,
   notes-card, button, segment-control, avatar, detail-row, screen-footer,
   top-app-bar) lives in component CSS.
   Typography is applied via text-* classes in markup where a token style
   matches; remaining font props (no matching text-* token) are kept scoped
   and flagged below under NON-TOKEN VALUES.
   ============================================ */

/* Scrollable content region. Mirrors the old standalone `.scroll-content`:
   24px gap stack + a top pad of 8px and a bottom pad sized for the fixed
   .screen-footer (the old standalone used spacing-96 + spacing-24 of
   clearance). Override the shell's bottom-nav dock clearance — this screen
   has a footer, not a dock. */
[data-view="edit-expense"] .view__content {
  --app-shell-content-pad: calc(var(--spacing-96) + var(--spacing-24));
  display: flex;
  flex-direction: column;
  gap: var(--spacing-24);
  /* Original standalone `.scroll-content` padding was
     `var(--spacing-8) var(--spacing-24) calc(var(--spacing-96) + var(--spacing-24))`.
     The shell's `.view__content` only owns padding-bottom (via the custom
     prop above), so restore the top + horizontal padding here exactly. */
  padding-top: var(--spacing-8);
  padding-left: var(--spacing-16);
  padding-right: var(--spacing-16);
}

/* Section headers reuse the activity list's .date-heading pattern. Zero its
   default 16px side padding for this screen so every label sits flush with the
   field/box left edge (and the category chips) on one left rail. */
[data-view="edit-expense"] .date-heading {
  padding-left: 0;
  padding-right: 0;
}

/* ── Amount field (editable hero) — uses the Input Field pattern: a section
   label above a boxed input (same beige surface as Description/Notes). The box
   holds the ₹ symbol, the amount input (flexes to fill), and the currency pill
   as a right-aligned affordance. ── */
[data-view="edit-expense"] .amount-input-wrap {
  display: flex;
  align-items: center;
  gap: var(--spacing-8);
  padding: var(--spacing-12) var(--spacing-16);
  border-radius: var(--radius-12);
  border: var(--border-small) solid var(--input-border-default);
  background: var(--input-bg);
}
/* symbol — typography via .text-amount-xl (48px) in markup. Screen-local: color. */
[data-view="edit-expense"] .amount-input-wrap__symbol {
  color: var(--text-primary);
  flex-shrink: 0;
}
/* input — typography via .text-amount-xl in markup; flexes to fill so the
   currency pill is pushed to the right edge. */
[data-view="edit-expense"] .amount-input-wrap input {
  flex: 1;
  min-width: 0;
  border: none;
  outline: none;
  background: transparent;
  color: var(--text-primary);
  caret-color: var(--text-brand);
  padding: 0;
}
[data-view="edit-expense"] .amount-input-wrap .currency-chip {
  flex-shrink: 0;
}

/* ── Category Chips (screen-unique horizontal scroller) ── */
[data-view="edit-expense"] .chips-section {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-8);
}
[data-view="edit-expense"] .chips-row {
  display: flex;
  gap: var(--spacing-8);
  overflow-x: auto;
  scrollbar-width: none;
}
[data-view="edit-expense"] .chips-row::-webkit-scrollbar { display: none; }

/* Paid by → shared .paid-by component (--card variant); see css/paid-by.css. */

/* ── Split section (mirrors add-split) ── */
[data-view="edit-expense"] .split-section {
  display: flex; flex-direction: column; gap: var(--spacing-12);
}
[data-view="edit-expense"] .split-section__summary {
  display: flex; align-items: center; justify-content: center;
  gap: var(--spacing-8); padding: var(--spacing-12);
  background: var(--card-create-bg); border-radius: var(--radius-8);
}
/* summary amount — display 14px/semibold has no text-* token; kept exact
   (see NON-TOKEN VALUES). */
[data-view="edit-expense"] .split-section__summary-amount {
  font-family: var(--font-display);
  font-size: var(--font-size-14);
  font-weight: var(--weight-semibold);
  color: var(--text-brand);
}
/* summary label — text style via .text-body-sm in markup */
[data-view="edit-expense"] .split-section__summary-label {
  color: var(--text-secondary);
}
[data-view="edit-expense"] .split-section__list {
  display: flex; flex-direction: column;
  background: var(--surface-card);
  border-radius: var(--radius-12);
  border: var(--border-small) solid var(--border-subtle);
  overflow: hidden;
}
[data-view="edit-expense"] .split-section__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);
}
[data-view="edit-expense"] .split-section__row:last-child { border-bottom: none; }
[data-view="edit-expense"] .split-section__check {
  width: 22px; height: 22px; border-radius: var(--radius-8);
  background: var(--btn-primary-bg); color: var(--btn-primary-fg);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
[data-view="edit-expense"] .split-section__check .icon-holder { font-size: 14px; }
[data-view="edit-expense"] .split-section__text { flex: 1; display: flex; flex-direction: column; gap: var(--spacing-2); min-width: 0; }
/* name — text style via .text-title-sm in markup */
[data-view="edit-expense"] .split-section__name {
  color: var(--text-primary);
}
/* share — text style via .text-body-xs in markup */
[data-view="edit-expense"] .split-section__share {
  color: var(--text-secondary);
}
/* amount pill — text style via .text-amount-xs in markup */
[data-view="edit-expense"] .split-section__amount-pill {
  min-width: 88px; padding: var(--spacing-8) var(--spacing-12);
  background: var(--input-bg);
  border-radius: var(--radius-8);
  color: var(--text-primary);
  text-align: center;
  flex-shrink: 0;
}
[data-view="edit-expense"] .split-section__total {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--spacing-12) var(--spacing-16);
  border-top: var(--border-small) solid var(--border-subtle);
  background: var(--card-create-bg);
}
/* total label — text style via .text-body-sm in markup */
[data-view="edit-expense"] .split-section__total-label {
  color: var(--text-secondary);
}
/* total value — display 14px/semibold has no text-* token; kept exact
   (see NON-TOKEN VALUES). */
[data-view="edit-expense"] .split-section__total-value {
  font-family: var(--font-display);
  font-size: var(--font-size-14);
  font-weight: var(--weight-semibold);
  color: var(--expense-lent-fg);
  display: flex; align-items: center; gap: var(--spacing-4);
}


/* ---- css/screens/settle-select.css ---- */
/* ============================================
   Settlr — Settle Select screen layout
   Genuine screen-specific structure only, scoped under
   [data-view="settle-select"] so it never leaks into other views in the
   compiled shell. Component styling (top-app-bar, step-progress, search-input,
   search-wrap, heading, person-item, expense-item, avatar) lives in component
   CSS. Typography is applied via text-* classes in markup (and by component
   CSS for the JS-rendered rows), not font props here.
   ============================================ */

/* Scrollable list region. This is a flow screen with no bottom-nav dock and no
   fixed footer — the list simply ends at the bottom of the view, exactly as the
   former standalone body flow did. Override the shell's dock clearance to 0 so
   no extra bottom padding is introduced. */
[data-view="settle-select"] .view__content {
  --app-shell-content-pad: 0px;
}

/* ---- css/screens/settle-amount.css ---- */
/* ============================================
   Settlr — Settle Amount screen layout
   Genuine screen-specific structure only, scoped under
   [data-view="settle-amount"] so it never leaks into other views in the
   compiled shell. Component styling (top-app-bar, step-progress, button,
   screen-footer) lives in component CSS.

   This is step 2 of the settle flow (settle-select → settle-amount →
   settle-method → settle-success). Two genuine screen-local clusters remain
   here: the person preview card and the centered amount display. Typography is
   snapped to text-* classes in markup where a token match exists; the large
   48px amount display has no typography token (like add-amount / expense-detail
   36–40px displays), so its font props stay scoped + flagged below.

   This is a flow screen: the .person-preview + .amount-area live OUTSIDE the
   scroll container (.view__content) and there is a fixed .screen-footer (no
   bottom-nav dock). The amount area fills the centre via flex.
   ============================================ */

/* The view itself is the column flex container the standalone <body> used to be
   (status-bar, top-app-bar, step-progress, preview, amount area, footer). The
   amount area grows to fill. .view__content is unused on this flow screen, but
   override the shell's dock clearance to the original 24px tail for safety. */
[data-view="settle-amount"] {
  display: flex;
  flex-direction: column;
}
[data-view="settle-amount"] .view__content {
  --app-shell-content-pad: var(--spacing-24);
}

/* ── Person Preview ── */
[data-view="settle-amount"] .person-preview {
  display: flex;
  align-items: center;
  gap: var(--spacing-12);
  padding: var(--spacing-12) var(--spacing-16);
  margin: 0 var(--spacing-16);
  border-radius: var(--radius-12);
  background: var(--surface-card);
  border: var(--border-small) solid var(--border-subtle);
}
[data-view="settle-amount"] .person-preview__avatar {
  /* TODO(spacing): 40px avatar has no spacing token — kept exact to avoid a
     visual change; flag for the spacing-enforcer pass. */
  width: 40px;
  height: 40px;
  border-radius: var(--radius-full);
  background: var(--contact-avatar-bg);
  color: var(--contact-avatar-fg);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
[data-view="settle-amount"] .person-preview__text { flex: 1; }
[data-view="settle-amount"] .person-preview__name {
  color: var(--text-primary);
}
[data-view="settle-amount"] .person-preview__balance {
  color: var(--expense-owe-fg);
}

/* ── Amount Area ── */
[data-view="settle-amount"] .amount-area {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--spacing-8);
  padding: var(--spacing-24) var(--spacing-16);
}
[data-view="settle-amount"] .currency-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-4);
  /* TODO(spacing): 4px/10px pill padding has no spacing token — kept exact to
     avoid a visual change; flag for the spacing-enforcer pass. */
  padding: 4px 10px;
  border-radius: var(--radius-full);
  background: var(--btn-icon-bg);
  color: var(--text-secondary);
}
/* Amount row: ₹ prefix + native decimal input (mirrors add-amount). The field
   grows with content; typography via .text-amount-xl (48px) in markup. */
[data-view="settle-amount"] .amount-row {
  display: flex;
  align-items: baseline;
  justify-content: center;
}
[data-view="settle-amount"] .amount-prefix {
  color: var(--text-primary);
  flex-shrink: 0;
}
[data-view="settle-amount"] .amount-field {
  color: var(--text-primary);
  background: transparent;
  border: none;
  outline: none;
  /* min-width 1ch / width 2ch / max-width are intrinsic-unit values, not
     spacing tokens — kept exact (matches add-amount). */
  min-width: 1ch;
  width: 2ch;
  max-width: calc(100vw - 80px);
  padding: 0;
  text-align: left;
  caret-color: var(--text-brand);
}
[data-view="settle-amount"] .amount-field::placeholder { color: var(--text-placeholder); }

/* Validation message under the amount (hidden until the amount is invalid). */
[data-view="settle-amount"] .amount-error {
  padding: 0 var(--spacing-24);
  width: 100%;
  text-align: center;
}

/* ---- css/screens/settle-method.css ---- */
/* ============================================
   Settlr — Settle Method screen layout
   Genuine screen-specific structure only, scoped under
   [data-view="settle-method"] so it never leaks into other views in the
   compiled shell. Component styling (top-app-bar, step-progress, summary-card,
   detail-row, heading, screen-footer, button) lives in component CSS.
   Typography is supplied entirely by component CSS — this screen's markup has
   no hardcoded font props, so there is nothing to snap to text-* classes.
   ============================================ */

/* Scrollable content region. Mirrors the old standalone `.content`:
   24px/16px padding stack + 12px gap. This is a flow screen with a fixed
   .screen-footer (no bottom-nav dock), so override the shell's dock clearance
   to the original 24px bottom padding — the fixed footer overlaps the tail
   exactly as before. */
[data-view="settle-method"] .view__content {
  --app-shell-content-pad: var(--spacing-24);
  padding-top: var(--spacing-24);
  padding-left: var(--spacing-16);
  padding-right: var(--spacing-16);
  display: flex;
  flex-direction: column;
  gap: var(--spacing-12);
}

/* ---- css/screens/settle-success.css ---- */
/* ============================================
   Settlr — Settle Success screen layout
   Genuine screen-specific structure only, scoped under
   [data-view="settle-success"] so it never leaks into other views in the
   compiled shell. Component styling (status-bar, confetti, success-state,
   summary-card, screen-footer, button) lives in component CSS.

   This is a flow screen (the final step of settle-select → settle-amount →
   settle-method → settle-success). It has NO scroll container: the
   .success-state (flex: 1) fills the space between the status-bar and the
   fixed .screen-footer and centers its content, exactly as the standalone
   body did (min-height: 100dvh; flex column). The fixed footer overlays the
   tail, so no --app-shell-content-pad clearance is needed.

   Typography is supplied entirely by component CSS (success-state,
   summary-card) — this screen's markup has no hardcoded font props, so there
   is nothing to snap to text-* classes.
   ============================================ */

/* Nothing screen-specific to declare: the success-state's own flex:1 +
   centering (from css/success-state.css) reproduces the original standalone
   layout inside the app-shell flex column. Block retained for parity with the
   other migrated screens and as the documented scope anchor. */

/* ---- css/screens/settlement-detail.css ---- */
/* ============================================
   Settlr — Settlement Detail screen layout
   Genuine screen-specific structure only, scoped under
   [data-view="settlement-detail"]. Mirrors the expense-detail hero + detail
   rows for a recorded settlement ("You paid X"). Component styling (detail-row,
   screen-footer, button, top-app-bar, avatar) lives in component CSS;
   typography is applied via text-* classes in markup.
   ============================================ */

[data-view="settlement-detail"] .view__content {
  --app-shell-content-pad: calc(var(--spacing-96) + var(--spacing-16));
  display: flex;
  flex-direction: column;
  gap: var(--spacing-16);
}

/* ── Settlement Hero Card ── */
[data-view="settlement-detail"] .settle-hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--spacing-12);
  padding: var(--spacing-24) var(--spacing-24) var(--spacing-20);
  margin: var(--spacing-8) var(--spacing-16) 0;
  border-radius: var(--radius-16);
  background: var(--surface-card);
  border: var(--border-small) solid var(--border-subtle);
  text-align: center;
}
[data-view="settlement-detail"] .settle-hero__illus {
  width: 56px;
  height: 56px;
  border-radius: var(--radius-full);
  background: var(--btn-icon-bg);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--font-size-24);
}
/* amount — text style via .text-display-lg in markup */
[data-view="settlement-detail"] .settle-hero__amount { color: var(--text-primary); }
/* title — text style via .text-title-lg in markup */
[data-view="settlement-detail"] .settle-hero__title { color: var(--text-primary); }
/* date — text style via .text-body-sm in markup */
[data-view="settlement-detail"] .settle-hero__date { color: var(--contact-settled-fg); }

/* ── Detail Section wrapper ── */
[data-view="settlement-detail"] .detail-section {
  padding: 0 var(--spacing-16);
  display: flex;
  flex-direction: column;
}

/* ── Footer: Undo (destructive text on the shared secondary button) ── */
[data-view="settlement-detail"] .btn-undo { color: var(--expense-owe-fg); }

/* ---- css/screens/onboarding-welcome.css ---- */
/* ============================================
   Settlr — Onboarding welcome (post-signup first-run view)
   Shown once right after signup (entered via welcome.html#onboarding-welcome),
   before home-dashboard. The flow is assembled from existing global components
   (.btn, .invite-card, .qr-section, .person-item, .search-input, .sheet,
   .avatar, .empty-state, web-component chrome); only a few screen-local
   onboarding bits (welcome block, action CTAs, user-ID page, import result)
   are defined here. All rules scoped under
   [data-view="onboarding-welcome"] so nothing leaks.

   Design source: the standalone review harness screens/prototype.html. The
   .onb-* classes are screen-local layout (same documented exception as the
   harness's .proto-* / other screen scoped files) — not new global components.
   ============================================ */

/* ── In-view panels (welcome / import / userid), swapped by JS ── */
[data-view="onboarding-welcome"] .onb-screen {
  display: flex;
  flex-direction: column;
  flex: 1;
}
[data-view="onboarding-welcome"] .onb-screen[hidden] {
  display: none;
}
[data-view="onboarding-welcome"] .onb-screen__content {
  flex: 1;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-16);
  padding: var(--spacing-16) 0 var(--spacing-32);
}

/* ── Welcome: fresh-user single screen ──
   A clean welcome centred on the import path + a "more ways" disclosure. */
[data-view="onboarding-welcome"] .onb-home {
  gap: var(--spacing-24);
  padding-top: var(--spacing-32);
}
[data-view="onboarding-welcome"] .onb-firstrun {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--spacing-12);
  padding: var(--spacing-24) var(--spacing-24) 0;
}
/* Settlr logo: the app-icon mark — olive squircle tile, cream chart glyph. */
[data-view="onboarding-welcome"] .onb-firstrun__art {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--spacing-64);
  height: var(--spacing-64);
  border-radius: var(--radius-16);
  background: var(--btn-primary-bg);
  color: var(--btn-primary-fg);
  margin-bottom: var(--spacing-4);
}
[data-view="onboarding-welcome"] .onb-firstrun__art svg {
  width: var(--spacing-40);
  height: var(--spacing-40);
}
[data-view="onboarding-welcome"] .onb-firstrun__title { color: var(--heading-fg); }
[data-view="onboarding-welcome"] .onb-firstrun__sub {
  color: var(--text-secondary);
  max-width: 30ch;
}

/* Stacked priority actions. */
[data-view="onboarding-welcome"] .onb-actions {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-12);
  padding: 0 var(--spacing-16);
}

/* Reused .invite-card / .qr-section ship their own margins; inside the collapsed
   "More ways" panel the panel owns spacing (gap-12 + its own 16px inset), so zero
   out all four margins to avoid double inset/rhythm. */
[data-view="onboarding-welcome"] .onb-more-panel .invite-card,
[data-view="onboarding-welcome"] .onb-more-panel .qr-section {
  margin: 0;
}

/* ── "Show more ways" disclosure ──
   The secondary .btn toggles a panel of the demoted methods (add-by-ID, invite,
   QR) inline within the screen. Its trailing chevron flips when expanded. The
   panel matches .onb-actions' 16px inset + 12px gap. */
[data-view="onboarding-welcome"] .onb-more-btn__chevron {
  display: inline-flex;
}
[data-view="onboarding-welcome"] .onb-more-btn[aria-expanded="true"] .onb-more-btn__chevron {
  transform: rotate(180deg);
}
@media (prefers-reduced-motion: no-preference) {
  [data-view="onboarding-welcome"] .onb-more-btn__chevron {
    transition: transform var(--duration-fast) var(--ease-out);
  }
}
[data-view="onboarding-welcome"] .onb-more-panel {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-12);
  padding: 0 var(--spacing-16);
}
[data-view="onboarding-welcome"] .onb-more-panel[hidden] { display: none; }

/* Centred text link (skip / show-QR). */
[data-view="onboarding-welcome"] .onb-textlink {
  align-self: center;
  padding: var(--spacing-8);
  background: transparent;
  border: none;
  color: var(--text-brand);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* ── Action CTA cards (full-width feature rows) ── */
[data-view="onboarding-welcome"] .onb-cta {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: var(--spacing-16);
  padding: var(--spacing-20) var(--spacing-16);
  border-radius: var(--radius-12);
  background: var(--surface-card);
  border: var(--border-small) solid var(--border-subtle);
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
[data-view="onboarding-welcome"] .onb-cta__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: var(--spacing-48);
  height: var(--spacing-48);
  border-radius: var(--radius-full);
  background: var(--btn-icon-bg);
  color: var(--text-brand);
}
[data-view="onboarding-welcome"] .onb-cta__icon svg {
  width: var(--icon-md);
  height: var(--icon-md);
}
[data-view="onboarding-welcome"] .onb-cta__text {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-2);
}
[data-view="onboarding-welcome"] .onb-cta__label { color: var(--text-primary); }
[data-view="onboarding-welcome"] .onb-cta__sub { color: var(--text-tertiary); }

/* ── Share hint (revealed after Share) ── */
[data-view="onboarding-welcome"] .onb-sharehint {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--spacing-8);
  margin: 0 var(--spacing-16);
  padding: var(--spacing-16);
  background: var(--surface-card);
  border: var(--border-small) solid var(--border-subtle);
  border-radius: var(--radius-12);
}
[data-view="onboarding-welcome"] .onb-sharehint[hidden] { display: none; }
[data-view="onboarding-welcome"] .onb-sharehint__text {
  color: var(--text-secondary);
  text-align: center;
}

/* ── Add by user ID (dedicated page) ── */
[data-view="onboarding-welcome"] .onb-userid-hint {
  color: var(--text-tertiary);
  padding: 0 var(--spacing-16);
}
[data-view="onboarding-welcome"] .onb-userid-result {
  display: flex;
  flex-direction: column;
}

/* ── No-results message (add-by-ID + import search) ── */
[data-view="onboarding-welcome"] .onb-noresult {
  color: var(--text-tertiary);
  text-align: center;
  padding: var(--spacing-24) var(--spacing-16);
}
[data-view="onboarding-welcome"] .onb-noresult[hidden] { display: none; }

/* ── Import result ── */
[data-view="onboarding-welcome"] .onb-import-summary {
  color: var(--text-tertiary);
  padding: 0 var(--spacing-16);
}
[data-view="onboarding-welcome"] .onb-import-footer {
  margin-top: auto;
  padding: var(--spacing-12) var(--spacing-16) 0;
}

/* ── My QR / invite (inside the bottom sheet) ── */
[data-view="onboarding-welcome"] .onb-sheet[hidden] { display: none; }
[data-view="onboarding-welcome"] .sheet__content {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-24);
  padding: var(--spacing-24) var(--spacing-16) var(--spacing-32);
}
[data-view="onboarding-welcome"] .onb-qr {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--spacing-16);
}
[data-view="onboarding-welcome"] .onb-qr__caption {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--spacing-2);
}
[data-view="onboarding-welcome"] .onb-qr__name { color: var(--text-primary); }
/* Was .onb-qr__phone until 2026-08-06 — the caption under the invite QR shows
   the user's @handle, not a phone number (phone left the product in Phase 0). */
[data-view="onboarding-welcome"] .onb-qr__handle { color: var(--text-secondary); }
[data-view="onboarding-welcome"] .onb-qr__hint { color: var(--text-tertiary); text-align: center; }
