/* ─────────────────────────────────────────────────────────────────
   J.Hilburn iPhone Prototype · Slide-up sheets
   Sheet host + scrim + sheet chrome (drag indicator, header, body,
   optional footer). Pattern: `.sheet-host` covers .device-screen
   when active; scrim dims content + dismisses on tap; the visible
   `.sheet` slides up from the bottom with .presentationCornerRadius
   matching the shipped app's 20pt corner radius.
   ───────────────────────────────────────────────────────────────── */
.sheet-host {
  position: absolute;
  inset: 0;
  z-index: 10;
  display: flex;
  align-items: flex-end;
}

/* `display: flex` above overrides the [hidden] attribute's browser
   default. Re-assert display:none with higher specificity so the
   host is actually invisible (and non-blocking) when no sheet is up. */
.sheet-host[hidden] { display: none; }

.sheet-host__scrim {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
  cursor: pointer;
  animation: sheet-scrim-in 0.25s ease;
}

@keyframes sheet-scrim-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.sheet {
  position: relative;
  width: 100%;
  max-height: 90%;
  background: var(--app-bg);
  border-top-left-radius: var(--radius-sheet);
  border-top-right-radius: var(--radius-sheet);
  display: flex;
  flex-direction: column;
  animation: sheet-in 0.3s cubic-bezier(0.4, 0.0, 0.2, 1);
}

.sheet[hidden] { display: none; }

@keyframes sheet-in {
  from { transform: translateY(100%); }
  to   { transform: translateY(0); }
}

.sheet__handle {
  width: 36px;
  height: 5px;
  background: rgba(60, 60, 67, 0.3);
  border-radius: 999px;
  margin: 8px auto 4px;
  flex-shrink: 0;
}

.sheet__header {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--gutter-double);
  padding: var(--gutter) var(--gutter-double) var(--gutter-double);
  border-bottom: 0.5px solid var(--app-divider);
}

.sheet__title {
  font: var(--app-h4);
  color: var(--app-text-primary);
  text-align: center;
  margin: 0;
}

.sheet__btn {
  background: none;
  border: none;
  font: var(--app-body-lg);
  color: var(--app-text-secondary);
  cursor: pointer;
  padding: 0;
  -webkit-tap-highlight-color: transparent;
}

.sheet__btn--cancel { justify-self: start; }
.sheet__btn--clear  { justify-self: end; color: var(--app-text-primary); }
.sheet__btn--ghost  { visibility: hidden; }

.sheet__body {
  padding: var(--gutter-double);
  overflow-y: auto;
}

/* ───── Commission Details table ───── */
.commission__order {
  font: var(--app-body-sm);
  color: var(--app-text-secondary);
  margin: 0 0 var(--gutter-double) 0;
}

.commission-table {
  width: 100%;
  border-collapse: collapse;
}

.commission-table th,
.commission-table td {
  padding: var(--gutter) var(--gutter-half);
  font: var(--app-body-sm);
  color: var(--app-text-primary);
  text-align: left;
  border-bottom: 0.5px solid var(--app-divider);
}

.commission-table th {
  color: var(--app-text-secondary);
  font-weight: 500;
  text-transform: none;
}

.commission-table__num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.commission-table tfoot td {
  font: var(--app-h5);
  border-bottom: none;
  padding-top: var(--gutter-double);
}

/* ─────────────────────────────────────────────────────────────────
   Sheet size modifiers
   ───────────────────────────────────────────────────────────────── */
.sheet--medium { max-height: 75%; }
/* Matches iOS .large detent: fills the device-screen except for the
   status-bar area (54px). Uses fixed height (not max-height) so the sheet
   claims the full detent regardless of content. */
.sheet--tall   { height: calc(100% - 54px); max-height: calc(100% - 54px); }

/* Full-screen modal — mirrors FlowStacks presentCover (the iPhone
   presentation for Add Client). Covers the whole device-screen below
   the status bar; no drag handle, no rounded top corners (rounded
   corners are a partial-sheet affordance). The X glass-circle in the
   top-right is the dismiss control. */
.sheet--full {
  height: 100%;
  max-height: 100%;
  border-top-left-radius: 0;
  border-top-right-radius: 0;
  /* Inset content below the 54px status-bar / Dynamic Island safe area so
     the Apple time/battery + notch stay visible on top (they're raised to
     z-index 30). Mirrors how a fullScreenCover insets its content. */
  padding-top: 54px;
}

.sheet--full .sheet__handle { display: none; }

/* Body fills the sheet so the footer (Cancel / Add Client, Go Back /
   Skip) pins to the bottom — iOS pins compactBottomBar / photoBottomBar
   via ZStack(alignment: .bottom). min-height:0 lets the body scroll. */
.sheet--full .sheet__body {
  flex: 1;
  min-height: 0;
}

.sheet__footer {
  display: flex;
  align-items: center;
  gap: var(--gutter-double);
  /* Source applies `.padding([.horizontal, .bottom], .doubleGutter)` = 16pt,
     then SwiftUI's sheet host adds the home-indicator safe-area inset on top
     (~34pt on iPhone 17). The prototype has no system safe area, so we bake
     that in manually — total bottom = 16 + 22 = 38pt to clear the home pill. */
  padding: var(--gutter-double) var(--gutter-double) calc(var(--gutter-double) + 22px);
  background: var(--app-bg);
  border-top: 0.5px solid var(--app-divider);
}

.sheet__btn--secondary { color: var(--app-text-secondary); }

/* ─────────────────────────────────────────────────────────────────
   Filter & Sort sheet (Clients)
   FilterAndSortView.swift compactLayout — section headers w/
   chevron toggle, radio rows for Sort, TagLayout chip grid for
   filter types, PrimaryButton "Show Clients" pinned bottom.
   ───────────────────────────────────────────────────────────────── */
.filter-sheet {
  padding: 0;
}

.filter-section {
  border-bottom: 0.5px solid var(--app-divider);
}

.filter-section:last-child { border-bottom: none; }

.filter-section__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: var(--gutter-3) var(--gutter-double);
  background: transparent;
  border: none;
  font: var(--app-h4);
  color: var(--app-text-primary);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.filter-section__chevron {
  color: var(--app-text-secondary);
  transition: transform 0.2s ease;
}

.filter-section[data-expanded="true"] .filter-section__chevron {
  transform: rotate(180deg);
}

.filter-section__body {
  padding: 0 var(--gutter-double) var(--gutter-3);
}

.filter-section__body[hidden] { display: none; }

.radio-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.radio-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: var(--gutter-double) 0;
  background: transparent;
  border: none;
  border-bottom: 0.5px solid var(--app-divider);
  font: var(--app-body-lg);
  color: var(--app-text-primary);
  cursor: pointer;
  text-align: left;
  -webkit-tap-highlight-color: transparent;
}

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

.radio-row__dot {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  border: 2px solid var(--app-divider);
  position: relative;
  flex-shrink: 0;
}

.radio-row[data-checked] .radio-row__dot {
  border-color: var(--app-button-black);
}

.radio-row[data-checked] .radio-row__dot::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--app-button-black);
  transform: translate(-50%, -50%);
}

/* Shared chip cluster (Clients filter — Categories Purchased section,
   Orders filter — flat single-select). Inline-flex wrap, 16pt H+V gap
   per JSA-7352 (Clients/Notes/Gallery filter spacing rollout). */
.filter-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--gutter-double);
}

/* Orders filter sheet body — flat chip grid on beige, no accordion.
   Source: FilterOrdersView.compactLayout lines 51-68. */
.orders-filter-sheet {
  padding: var(--gutter-double);
}

.orders-filter-chips {
  /* Source: TagLayout(horizontalSpacing: .doubleGutter, verticalSpacing: .doubleGutter).
     padding: .top(.doubleGutter). */
  padding-top: var(--gutter-double);
}

/* ─────────────────────────────────────────────────────────────────
   Estimated Delivery Times sheet
   Source: Checkout/.../EstimatedDeliveryView.swift compactLayout +
   EstimatedDeliveryTableModel.swift column layouts.
   ───────────────────────────────────────────────────────────────── */
.ed-sheet__header {
  display: flex;
  justify-content: flex-end;
  /* Source: .padding(.horizontal, .doubleGutter).padding(.top, .gutter(×3))
     = 16/24/16 — but the prototype's `.sheet__handle` already eats 17px at
     the sheet top (vs. iOS's smaller native drag indicator), so trim our
     header top padding to 8px so total sheet-top → Done text ≈ 25px,
     matching the target visual in screenshot #155. */
  padding: var(--gutter) var(--gutter-double) var(--gutter-double);
}

/* Done button: H4 (16pt semibold), lightTextPrimary. */
.ed-sheet__done {
  font: var(--app-h4);
  color: var(--app-text-primary);
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

.ed-sheet__body {
  /* componentTitle pad: .horizontal(.doubleGutter); table scroller pad: same.
     `flex: 1` so the body fills available space inside the fixed-height sheet,
     pinning the "Got it" footer to the bottom (matches source's
     `Spacer()` + PrimaryButton at the end of compactLayout VStack). */
  padding: 0 var(--gutter-double);
  overflow-y: auto;
  flex: 1;
  min-height: 0;
}

/* Title: H4 on mobile (per componentTitle line 138). Centered visually
   in the screenshot — Group + centered alignment in source pattern. */
.ed-sheet__title {
  margin: 0;
  font: var(--app-h4);
  color: var(--app-text-primary);
  text-align: center;
}

/* Disclaimer: fontBodyMedium, lightTextSecondary, .padding(.vertical, .doubleGutter). */
.ed-sheet__disclaimer {
  margin: 0;
  padding: var(--gutter-double) 0;
  font: var(--app-body);
  color: var(--app-text-secondary);
  text-align: left;
}

/* 4-column table — Category | Standard | Rush | Extreme Rush.
   Card chrome: 8pt corner radius (.cornerRadius(.defaultGutter)),
   overflow hidden so striped row backgrounds clip cleanly. */
.ed-table {
  border-radius: var(--gutter);
  overflow: hidden;
  background: var(--app-card-bg);
}

.ed-table__head,
.ed-table__row {
  display: grid;
  /* Category wider to accommodate multi-line names; 3 value columns equal. */
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr);
  /* Top-align so single-line cells (Standard / Rush / Extreme Rush values)
     don't visually mid-line with multi-line Category cells like
     "Shirts / Knits / Casual / Bottoms". Matches screenshot #155. */
  align-items: start;
  padding: var(--gutter-double) var(--gutter);
  gap: var(--gutter);
}

.ed-table__head {
  background: var(--app-card-bg);
}

/* Striped rows: source uses TableView `oddRowColor: .biege` so every other
   row is beige; the rest stay white. Header counts as row index 0 (white). */
.ed-table__row:nth-child(odd)  { background: var(--app-bg); }
.ed-table__row:nth-child(even) { background: var(--app-card-bg); }

.ed-table__cell {
  font: var(--app-body);
  color: var(--app-text-primary);
}

/* Column-specific layout + colors per EstimatedDeliveryTableModel.swift:
     .leading(textColor: .lightTextSecondary)  → Category
     .centered(textColor: .lightSuccessText)   → Standard (green)
     .centered(textColor: .lightInfoTextBlue)  → Rush (blue)
     .centered(textColor: .lightInfoTextPurple) → Extreme Rush (purple) */
.ed-table__cell--cat {
  text-align: left;
  color: var(--app-text-primary);
  white-space: pre-line; /* honors \n from "/" → "\n" replacement in source */
}

.ed-table__cell--std,
.ed-table__cell--rush,
.ed-table__cell--ext {
  text-align: center;
}

/* Header row: font weight slightly heavier than body; source uses TableView
   header style which is bolded by the column model. */
.ed-table__head .ed-table__cell {
  font: var(--app-h5);   /* 14pt semibold — matches TableView header */
  color: var(--app-text-primary);
}

/* Body cell colors per column. */
.ed-table__row .ed-table__cell--std  { color: var(--app-success-text); }
.ed-table__row .ed-table__cell--rush { color: #0F78C4; }   /* Color.lightInfoTextBlue */
.ed-table__row .ed-table__cell--ext  { color: #9F1D8A; }   /* Color.lightInfoTextPurple */

/* ─────────────────────────────────────────────────────────────────
   View Details (per-item) bottom sheet
   Source: Rebekah screenshots #180-#184. Header product card + 3
   sections (Measurements & Fit / Style Options / Personalization
   Options). Each section: H4 heading + 2-col label/value striped table.
   ───────────────────────────────────────────────────────────────── */
.view-details-sheet__body {
  padding: 0 var(--gutter-double);
  overflow-y: auto;
  flex: 1;
  min-height: 0;
  /* Bottom breathing room so the last section doesn't kiss the home indicator. */
  padding-bottom: var(--gutter-4);
}

/* Header card. White card with product image + SKU + name. */
.vd-header {
  display: flex;
  align-items: center;
  gap: var(--gutter-double);
  padding: var(--gutter-double);
  background: var(--app-card-bg);
  border-radius: var(--gutter);
  margin-bottom: var(--gutter-3);
}

.vd-header__img {
  width: 64px;
  height: 64px;
  object-fit: contain;
  flex-shrink: 0;
}

.vd-header__info {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.vd-header__sku {
  font: var(--app-body);
  color: var(--app-text-secondary);
}

.vd-header__name {
  font: var(--app-h4);
  color: var(--app-text-primary);
}

.vd-section {
  margin-bottom: var(--gutter-3);
}

.vd-section__title {
  margin: 0 0 var(--gutter) 0;
  font: var(--app-h4);
  color: var(--app-text-primary);
}

/* Striped 2-column table. Same row chrome as ed-table (alternating
   white/beige rows, 8pt corners, overflow hidden) but two columns:
   label (left, secondary text) + value (right, primary text). */
.vd-table {
  border-radius: var(--gutter);
  overflow: hidden;
}

.vd-table__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: center;
  /* Source: KeyMultiValueTableModel.swift uses minRowHeight: 0 + spacing: 10
     inside TableView, with rows that visually settle around 44pt tall via
     content padding. Mirror that: 12px vertical / 16px horizontal. */
  padding: 12px var(--gutter-double);
  gap: var(--gutter-double);
  min-height: 44px;
}

/* Striped rows: source uses evenRowColor: .primaryWhite + oddRowColor:
   .mainGray. In iOS row 0 is "even" → white. First child here is row 0, so
   CSS :nth-child(odd) (1, 3, 5...) maps to iOS evenRow (white). */
.vd-table__row:nth-child(odd)  { background: var(--app-card-bg); }
.vd-table__row:nth-child(even) { background: var(--app-main-gray); }

.vd-table__label {
  font: var(--app-body);
  color: var(--app-text-secondary);
}

.vd-table__value {
  font: var(--app-body);
  color: var(--app-text-primary);
  text-align: right;
}

/* ─────────────────────────────────────────────────────────────────
   Commission Details bottom sheet
   Source: Rebekah screenshot #179. "Commission Details for Order #X"
   left-aligned title + 4-col table (SKU/Quantity/PV-Q/PV-C) inside a
   white card with striped rows + bolded total row + 2 footer notes.
   ───────────────────────────────────────────────────────────────── */
.commission-sheet__body {
  padding: 0 var(--gutter-double);
  overflow-y: auto;
  flex: 1;
  min-height: 0;
  padding-bottom: var(--gutter-4);
}

.commission-sheet__title {
  margin: 0 0 var(--gutter-double) 0;
  font: var(--app-h4);
  color: var(--app-text-primary);
}

/* Source: CommissionDetailsView.swift compactSheetTable (lines 81-93):
   ONE white card with 8pt corners + 16pt padding all sides, containing a
   VStack with 16pt spacing between: table, total, footnotes. The title
   stays outside the card. */
.commission-card {
  background: var(--app-card-bg);
  border-radius: var(--gutter);
  padding: var(--gutter-double);
  display: flex;
  flex-direction: column;
  gap: var(--gutter-double);
}

.commission-table {
  border-radius: var(--gutter);
  overflow: hidden;
}

.commission-table__head,
.commission-table__row {
  display: grid;
  /* Source: 4 equal-width columns (tableWidth: .infinity, default layout). */
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr);
  align-items: start;
  padding: var(--gutter-double) var(--gutter);
  gap: var(--gutter);
}

/* Source (CommissionDetailsView.swift:175-178):
     headerRowBackgroundColor: .mainGray
     evenRowColor:             .primaryWhite
     oddRowColor:              .mainGray
   In iOS row-index terms, row 0 (A1M-S) is even → white. In CSS nth-child
   terms, A1M-S is :nth-child(2) (after the head at :nth-child(1)), so the
   CSS :nth-child(even) rule maps to iOS evenRow (white). */
.commission-table__head      { background: var(--app-main-gray); }
.commission-table__row:nth-child(even) { background: var(--app-card-bg); }
.commission-table__row:nth-child(odd)  { background: var(--app-main-gray); }

/* Per-column cell alignment + color, per CommissionDetailsTableModel.swift:8-22.
   SKU: .leading (left), Color.lightTextSecondary.
   Quantity / PV-Q / PV-C: .centered (default text color = primary). */
.commission-table__cell {
  font: var(--app-body);
  color: var(--app-text-primary);
}

.commission-table__cell--sku {
  text-align: left;
  color: var(--app-text-secondary);
}

.commission-table__cell--qty,
.commission-table__cell--pvq,
.commission-table__cell--pvc {
  text-align: center;
}

/* Header row: H5 (14pt semibold). Source: TableView header row inherits the
   column's text alignment and renders with header font weight. */
.commission-table__head .commission-table__cell {
  font: var(--app-h5);
}

/* Separate total table — no header, no stripes, transparent so the card bg
   shows through. Source: totalTableView (CommissionDetailsView.swift:157-168)
   uses showsHeaderRow: false + default clear bg.
   Total row fonts per CommissionDetailsTableModel.swift:61-66:
     Total label → fontHeading5 (semibold)
     empty       → nil (no font; column is the unused 2nd one)
     PV-Q        → fontBodyMedium (regular)
     PV-C        → fontHeading5 (semibold) */
.commission-total {
  background: transparent;
}

.commission-total__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr);
  align-items: center;
  padding: 0 var(--gutter);
  gap: var(--gutter);
}

.commission-total__row .commission-table__cell--sku   { font: var(--app-h5); color: var(--app-text-secondary); }
.commission-total__row .commission-table__cell--qty   { font: var(--app-body); }
.commission-total__row .commission-table__cell--pvq   { font: var(--app-body); text-align: center; }
.commission-total__row .commission-table__cell--pvc   { font: var(--app-h5); text-align: center; }

/* Footnote paragraphs — italic, secondary, inside the white card. */
.commission-notes {
  display: flex;
  flex-direction: column;
  gap: var(--gutter-double);
}

.commission-notes p {
  margin: 0;
  font: var(--app-body);
  font-style: italic;
  color: var(--app-text-secondary);
}

/* ─────────────────────────────────────────────────────────────────
   Add Client sheet (3 steps)
   AddClientStep1View+iPhone.swift / AddClientPhotoView.swift /
   AddClientStep2View+iPhone.swift — gold eyebrow + step indicator +
   H1 (with italic gold accent word) + subtitle + gold accent bar +
   form sections / camera lens / option cards + bottom action bar.
   ───────────────────────────────────────────────────────────────── */
.addclient {
  /* Source: every step's compactContent / photoContent / compactLayout adds
     .padding(.bottom, .gutter(withMultiplier: 12)) = 96pt to clear the
     pinned compactBottomBar / photoBottomBar overlay (see
     AddClientStep1View+iPhone:45, AddClientPhotoView:27,
     AddClientStep2View+iPhone:19). Without this on the prototype, the
     last scrollable element (e.g. Choose from Library) clips against the
     footer on shorter device frames. */
  padding: var(--gutter-double) var(--gutter-double) 96px;
}

.addclient__step {
  display: flex;
  flex-direction: column;
}

.addclient__step[hidden] { display: none; }

/* AddClientStep1View.compactContent: outer VStack spacing 16pt
   (header → forms group); compactForms inner VStack spacing 24pt
   between section accordions. */
.addclient__step > .form-section + .form-section {
  margin-top: var(--gutter-3);          /* 24pt between sections */
}

.addclient__header {
  display: flex;
  flex-direction: column;
  gap: var(--gutter);
  margin-bottom: var(--gutter-double);   /* 16pt to first form section */
  padding-bottom: var(--gutter-double);
}

.addclient__eyebrow-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.addclient__eyebrow {
  font: var(--app-button);
  color: var(--app-gold);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.addclient__progress {
  display: inline-flex;
  align-items: center;
  gap: var(--gutter);
  font: var(--app-button);
  color: var(--app-gold);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.addclient__step-dot {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--app-button-black);
  color: var(--app-card-bg);
  font: var(--app-button-sm);
}

.addclient__title {
  font: var(--app-h1);
  font-family: var(--app-font-serif);
  color: var(--app-text-primary);
  margin: 0;
  line-height: 1.1;
}

.addclient__title em {
  font-style: italic;
  color: var(--app-gold);
}

.addclient__subtitle {
  font: var(--app-body-lg);
  color: var(--app-text-secondary);
  margin: 0;
}

.addclient__accent {
  display: block;
  width: 32px;
  height: 2px;
  background: var(--app-gold);
  margin-top: var(--gutter);
}

/* Form sections — ClientFormSectionView.compactLayout + ClientFormSectionHeaderView:
   white card, 8pt corners, 1pt stroke (dividerBackground when collapsed,
   primaryGold when expanded). Header is HStack with 10pt spacing:
   36pt beige circle (containing 24pt template-tinted icon) + title block +
   Spacer + 22pt chevron-circle (white/dividerBackground stroke collapsed,
   filled lightTextPrimary expanded) with a 12pt chevron-down inside that
   rotates 180° on expand. Header padding: 16pt H × 12pt V. */
.form-section {
  background: var(--app-card-bg);
  border-radius: var(--radius-card);
  border: 1px solid var(--app-divider);
  overflow: hidden;
  transition: border-color 0.2s ease;
}

.form-section[data-expanded="true"] {
  border-color: var(--app-gold);
}

.form-section__header {
  display: flex;
  align-items: center;
  gap: 10px;                              /* gutter × 1.25 */
  width: 100%;
  padding: 12px var(--gutter-double);     /* 12pt V × 16pt H */
  background: transparent;
  border: none;
  cursor: pointer;
  text-align: left;
  -webkit-tap-highlight-color: transparent;
}

.form-section__icon {
  width: 36px;                            /* gutter × 4.5 */
  height: 36px;
  border-radius: 50%;
  background: var(--app-bg);              /* Color.biege */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.form-section__icon img {
  width: 24px;                            /* gutter × 3 */
  height: 24px;
  opacity: 0.65;                          /* approximates lightTextSecondary on currentColor */
}

.form-section__title-block {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.form-section__title {
  font: var(--app-button);                /* fontButtonMedium 14pt medium */
  color: var(--app-text-primary);
}

.form-section__hint {
  font: var(--app-body-sm);
  color: var(--app-text-secondary);
}

.form-section__chevron-circle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;                            /* gutter × 2.75 */
  height: 22px;
  border-radius: 50%;
  background: var(--app-card-bg);
  border: 1px solid var(--app-divider);
  flex-shrink: 0;
  transition: background 0.2s ease, border-color 0.2s ease;
}

.form-section[data-expanded="true"] .form-section__chevron-circle {
  background: var(--app-text-primary);    /* Color.lightTextPrimary */
  border-color: transparent;
}

/* CSS mask lets the chevron's color flip via background-color when the
   parent circle goes dark on expand. Uses the existing right-caret SVG
   rotated 90° to point down — saves an extra asset. */
.form-section__chevron {
  display: block;
  width: 12px;                            /* gutter × 1.5 */
  height: 12px;
  background-color: var(--app-text-primary);
  mask-image: url('../assets/icons/icon-chevron-right.svg');
  -webkit-mask-image: url('../assets/icons/icon-chevron-right.svg');
  mask-size: contain;
  -webkit-mask-size: contain;
  mask-repeat: no-repeat;
  -webkit-mask-repeat: no-repeat;
  mask-position: center;
  -webkit-mask-position: center;
  transform: rotate(90deg);               /* down when collapsed */
  transition: transform 0.2s ease, background-color 0.2s ease;
}

.form-section[data-expanded="true"] .form-section__chevron {
  background-color: var(--app-card-bg);
  transform: rotate(-90deg);              /* up when expanded */
}

.form-section__body {
  padding: 0 var(--gutter-double) var(--gutter-double);
  display: flex;
  flex-direction: column;
  gap: var(--gutter-double);
}

.form-section__body[hidden] { display: none; }

/* Form fields */
.form-row { display: flex; flex-direction: column; gap: var(--gutter-double); }

/* Pair row: PersonalInfoFormView.compactFields HStack(spacing: gutter×1.5 = 12pt),
   with the secondary field (Middle Initial / Collar Initials) capped at
   gutter × 13 = 104pt. The primary field grows. */
.form-row--pair {
  flex-direction: row;
  gap: 12px;
  align-items: flex-end;
}
.form-field--grow { flex: 1; min-width: 0; }
.form-field--initials { flex: 0 0 104px; }

/* Required-field asterisk in red (Color.lightStatusError). Appended to the
   label string in the SwiftUI source via CoreUI.LocalizableStrings.asterisk. */
.form-field__required { color: var(--app-error-text); }

/* Segmented control — ClientFormSegmentedControlView.compactLayout:
   fontLabelMedium label above + TagLayout row of capsule chips with 8pt
   spacing. Used for Phone Type, Address Type, and Preferred Method of
   Contact on Add Client Step 1. compactChip: 8pt V × 16pt H,
   fontButtonMedium, primaryWhite bg + dividerBackground stroke when
   unselected, primaryBlack + white text when selected. */
.seg-field {
  display: flex;
  flex-direction: column;
  gap: var(--gutter);
}

.seg-field__label {
  font: var(--app-h5);                /* fontLabelMedium = 14pt semibold */
  font-family: var(--app-font-sans);
  color: var(--app-text-primary);
}

.seg-field__chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--gutter);
}

/* ZIP + City/State pair — HStack(spacing: .doubleGutter) in both
   ShippingInfoFormView.zipCodeAndCityState and the same helper in
   BillingAndAccountFormView. Children share the row equally. */
.form-row--zip-city {
  flex-direction: row;
  gap: var(--gutter-double);
  align-items: flex-end;
}

.form-row--zip-city .form-field {
  flex: 1;
  min-width: 0;
}

/* Validate Address button — SecondaryButton.frame(178×50).border() with
   8pt iPhone corners + dividerBackground stroke + 8pt top padding. */
.form-validate-btn {
  align-self: flex-start;
  min-width: 178px;
  height: 50px;
  padding: 0 var(--gutter-double);
  margin-top: var(--gutter);
  font: var(--app-button);
  font-family: var(--app-font-sans);
  color: var(--app-text-primary);
  background: var(--app-card-bg);
  border: 1px solid var(--app-divider);
  border-radius: var(--gutter);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background 0.15s ease;
}

.form-validate-btn:active {
  background: var(--app-bg);
}

/* additionalAddressesInfo footer note — fontBodyMedium + lightTextTertiary. */
.form-section__footer-note {
  margin: 0;
  font: var(--app-body);
  font-family: var(--app-font-sans);
  color: var(--app-text-tertiary);
}

/* Disabled credit-card fields — Option A from the prototype safety rule:
   PrimaryTextFieldView labels and placeholders are preserved verbatim
   from BillingAndAccountFormDomain.State, but the inputs are non-
   interactive in this portfolio prototype. Matches enabled-field
   styling (white bg, divider border) so the section reads as part of
   the form; the italic caption above carries the "non-interactive"
   signal. cursor:not-allowed surfaces it on hover. */
.form-field__input:disabled {
  cursor: not-allowed;
}

/* Read-only City/State — auto-filled by the AVS service after Validate
   Address succeeds (cityState model has editable: false in iOS). */
.form-field__input--readonly {
  cursor: default;
}

/* Inline P.O.-box rejection row under the Shipping Address field —
   address1.additionalInformation = "J.Hilburn is unable to ship to
   P.O. boxes." rendered in lightStatusError red with an iconError
   exclamation circle. fontBodyMedium per the iOS error pattern. */
.form-field__error {
  display: flex;
  align-items: flex-start;
  gap: var(--gutter);
  margin-top: var(--gutter-half);
  font: var(--app-body);
  font-family: var(--app-font-sans);
  color: var(--app-error-text);
}
.form-field__error[hidden] { display: none; }
.form-field__error-icon {
  flex: 0 0 16px;
  width: 16px;
  height: 16px;
  margin-top: 2px;
}

/* Billing-section caption — sits above the disabled credit-card fields
   to explain why they're non-interactive in this prototype. */
.form-section__caption {
  margin: 0;
  font: var(--app-body-sm);
  font-family: var(--app-font-sans);
  color: var(--app-text-secondary);
  font-style: italic;
}

.billing-cards {
  display: flex;
  flex-direction: column;
  gap: var(--gutter-double);
}

/* Referred By picker button — ReferredByView.compactLayout: a Button
   wrapping a 50pt-tall bordered row with value text + chevron-right.
   Label "Referred By" at fontLabelMedium (14pt semibold) above the
   row, 8pt gap (.defaultGutter) — VStack spacing in iOS. */
.form-picker {
  display: flex;
  flex-direction: column;
  gap: var(--gutter);
  background: transparent;
  border: 0;
  padding: 0;
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.form-picker__label {
  font: var(--app-h5);                /* fontLabelMedium = 14pt semibold */
  font-family: var(--app-font-sans);
  color: var(--app-text-primary);
}

.form-picker__chip {
  display: flex;
  align-items: center;
  gap: var(--gutter);
  height: 50px;                       /* gutter * 6.25 */
  padding: 0 var(--gutter-double);
  background: var(--app-card-bg);
  border: 1px solid var(--app-divider);
  border-radius: var(--gutter);       /* 8pt on iPhone per JSA-6911 */
}

.form-picker__value {
  flex: 1;
  min-width: 0;
  font: var(--app-body-lg);
  font-family: var(--app-font-sans);
  color: var(--app-text-tertiary);    /* placeholder colour while unset */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.form-picker__value[data-selected] {
  color: var(--app-text-primary);
}

.form-picker__chevron {
  flex: 0 0 16px;
  opacity: 0.6;
}

/* Referee picker overlay — separate host from .sheet-host so it stacks
   on top of the open Add Client sheet, matching iOS .sheet(isPresented:)
   on the Button. The parent sheet stays visible behind the scrim. */
.referee-host {
  position: absolute;
  inset: 0;
  z-index: 20;
  display: flex;
  align-items: flex-end;
}
.referee-host[hidden] { display: none; }

.referee-host__scrim {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
  cursor: pointer;
  animation: sheet-scrim-in 0.25s ease;
}

.referee-sheet {
  position: relative;
  width: 100%;
  max-height: 85%;
  background: var(--app-bg);
  border-top-left-radius: var(--radius-sheet);
  border-top-right-radius: var(--radius-sheet);
  display: flex;
  flex-direction: column;
  animation: sheet-in 0.3s cubic-bezier(0.4, 0.0, 0.2, 1);
}

/* Cancel sits in the right grid column here (title is .principal-centered,
   Cancel is .navigationBarTrailing in ReferredByView.compactRefereeSheet),
   so align it to the trailing edge — the base --cancel rule uses
   justify-self:start for left-column Cancel buttons on other sheets. */
.referee-sheet .sheet__btn--cancel { justify-self: end; }

/* Referee picker body — beige outer with a white search bar card +
   a white results-list card. Matches ReferredByView.compactSearchBar
   and compactResultsList structure (each is its own white card with
   16pt outer padding). */
.referee-picker {
  display: flex;
  flex-direction: column;
  gap: var(--gutter-double);
  padding: var(--gutter-double);
  overflow-y: auto;
}

.referee-picker__search {
  display: flex;
  align-items: center;
  gap: var(--gutter);
  padding: 12px var(--gutter-double);   /* gutter*1.5 vertical */
  background: var(--app-card-bg);
  border-radius: var(--gutter);
}

.referee-picker__search img {
  flex: 0 0 20px;                       /* gutter*2.5 */
  height: 20px;
  opacity: 0.7;
}

.referee-picker__search input {
  flex: 1;
  min-width: 0;
  border: 0;
  outline: 0;
  background: transparent;
  font: var(--app-body-lg);
  font-family: var(--app-font-sans);
  color: var(--app-text-primary);
  height: 40px;                          /* gutter*5 */
}

.referee-picker__search input::placeholder {
  color: var(--app-text-tertiary);
}

.referee-list {
  list-style: none;
  margin: 0;
  padding: 0;
  background: var(--app-card-bg);
  border-radius: var(--gutter);
  overflow: hidden;
}

.referee-list li {
  margin: 0;
}

.referee-row {
  display: flex;
  align-items: center;
  gap: var(--gutter);
  width: 100%;
  padding: 12px var(--gutter-double);   /* gutter*1.5 vertical */
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--app-divider);
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.referee-list li:last-child .referee-row { border-bottom: 0; }

.referee-row[hidden] { display: none; }

.referee-row__name {
  font: var(--app-body-lg);
  font-family: var(--app-font-sans);
  color: var(--app-text-primary);
}

.referee-row__dot {
  font: var(--app-body-lg);
  font-family: var(--app-font-sans);
  color: var(--app-divider);
}

.referee-row__id {
  font: var(--app-body);
  font-family: var(--app-font-sans);
  color: var(--app-text-secondary);
}

.seg-chip {
  font: var(--app-button);            /* fontButtonMedium 14pt medium */
  font-family: var(--app-font-sans);
  padding: var(--gutter) var(--gutter-double);   /* 8pt V × 16pt H */
  background: var(--app-card-bg);     /* primaryWhite when unselected */
  color: var(--app-text-primary);     /* lightTextPrimary */
  border: 1px solid var(--app-divider);
  border-radius: 999px;               /* Capsule */
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.seg-chip--selected {
  background: var(--app-button-black);
  color: var(--app-card-bg);
  border-color: transparent;
}

.form-field {
  display: flex;
  flex-direction: column;
  gap: var(--gutter-half);
  /* Allow shrinking below content width inside .form-row--pair. Without
     this the flex item inherits min-width:auto and inflates to the
     <input>'s intrinsic size (default size=20 ≈ 150–200px), which
     overrides the 104px basis on .form-field--initials and makes MI/CI
     render as wide as — or wider than — FN/LN. */
  min-width: 0;
}

.form-field__label {
  font: var(--app-body-sm);
  color: var(--app-text-secondary);
}

.form-field__input {
  /* Fill the parent .form-field's allocated width and ignore the
     intrinsic 'size' attribute so MI/CI can sit at 104px. */
  width: 100%;
  min-width: 0;
  box-sizing: border-box;
  height: 44px;
  padding: 0 var(--gutter-double);
  background: var(--app-card-bg);
  border: 1px solid var(--app-divider);
  border-radius: var(--radius-button);
  font: var(--app-body-lg);
  color: var(--app-text-primary);
  outline: none;
  -webkit-appearance: none;
  appearance: none;
}

.form-field__input:focus {
  border-color: var(--app-stroke-gray);
}

.form-field__input::placeholder {
  color: var(--app-text-tertiary);
}

/* Step 2 camera placeholder */
/* Step 2 top toolbar — back / "Client Photo" / X. Title centered between
   two 44pt glass-circle buttons (matches AddClientPhotoView's
   navigationBarLeading + .principal + navigationBarTrailing). */
.addclient-toolbar {
  display: grid;
  grid-template-columns: 44px 1fr 44px;
  align-items: center;
  gap: var(--gutter-double);
  margin-bottom: var(--gutter-double);
}

.addclient-toolbar__title {
  font: var(--app-nav-title);
  font-family: var(--app-font-sans);
  color: var(--app-text-primary);
  text-align: center;
}

.addclient-toolbar__btn { color: var(--app-text-primary); }

.addclient-camera {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--gutter-3);
}

/* CameraLensView — layered black lens barrel. The radial-gradient bands
   approximate the concentric barrelRing/barrelFill stack; ::before is the
   gold aperture ring (apertureRing, Color.primaryGold); the glass child is
   the dark center (Color(white:0.1)) holding the camera icon + hint. */
.addclient-camera__lens {
  position: relative;
  /* Source: AddClientPhotoView.swift:171 — lensSize = .gutter(withMultiplier: 37.5) = 300pt */
  width: 300px;
  height: 300px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background:
    radial-gradient(circle at 50% 42%,
      #1b1b1b 0%,
      #141414 58%,
      #2c2c2c 60%,
      #111 64%,
      #1f1f1f 71%,
      #2a2a2a 82%,
      #161616 90%,
      #363636 97%,
      #181818 100%);
  box-shadow:
    0 12px 32px rgba(0, 0, 0, 0.35),
    inset 0 2px 6px rgba(255, 255, 255, 0.05);
}

/* Gold aperture ring (apertureRing inset 80 → ~73% of the barrel). */
.addclient-camera__lens::before {
  content: "";
  position: absolute;
  width: 73%;
  height: 73%;
  border-radius: 50%;
  border: 2px solid var(--app-gold);
  opacity: 0.8;
}

/* Dark glass center (glassSize = lensSize − 110 ≈ 63%). */
.addclient-camera__glass {
  position: relative;
  z-index: 1;
  width: 63%;
  height: 63%;
  border-radius: 50%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--gutter);
  background: radial-gradient(circle at 42% 32%, #242424 0%, #0d0d0d 72%);
  color: #666666;                 /* camera icon — Color(white: 0.4) */
}

.addclient-camera__hint {
  font: var(--app-body);
  font-family: var(--app-font-sans);
  color: #595959;                 /* Color(white: 0.35) */
  text-align: center;
  line-height: 1.25;
}

/* Selected photo fills the glass (clipped to the circle), matching the
   captured-image state in CameraLensView. */
.addclient-camera__photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 50%;
}

/* Photo-loaded state lives on .addclient-camera (the wrapper) so it can
   drive both the glass content AND sibling controls' opacity. */
.addclient-camera[data-has-photo="true"] .addclient-camera__placeholder,
.addclient-camera[data-has-photo="true"] .addclient-camera__hint {
  display: none;
}

/* Source: AddClientPhotoView.swift:196, 219 — Flip + Capture dim to 0.3
   when capturedImage != nil; line 235 — Retake rises to 1.0 (the JS
   already removes the --disabled class on Retake when a photo loads). */
.addclient-camera[data-has-photo="true"] [data-camera-flip],
.addclient-camera[data-has-photo="true"] .addclient-camera__capture {
  opacity: 0.3;
}

/* Mock iOS photo-library picker overlay — same stacking model as the
   referee picker (z-index above the Add Client sheet host). */
.library-host {
  position: absolute;
  inset: 0;
  z-index: 20;
  display: flex;
  align-items: flex-end;
}
.library-host[hidden] { display: none; }

.library-host__scrim {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
  cursor: pointer;
  animation: sheet-scrim-in 0.25s ease;
}

.library-sheet {
  position: relative;
  width: 100%;
  max-height: 85%;
  background: var(--app-card-bg);
  border-top-left-radius: var(--radius-sheet);
  border-top-right-radius: var(--radius-sheet);
  display: flex;
  flex-direction: column;
  animation: sheet-in 0.3s cubic-bezier(0.4, 0.0, 0.2, 1);
}

.library-sheet__header {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--gutter-double);
  padding: var(--gutter) var(--gutter-double) var(--gutter-double);
  border-bottom: 0.5px solid var(--app-divider);
}
.library-sheet__header .sheet__btn { justify-self: start; }

.library-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2px;
  padding: 2px;
  overflow-y: auto;
}

.library-tile {
  position: relative;
  aspect-ratio: 1 / 1;
  padding: 0;
  border: 0;
  background: var(--app-bg);
  cursor: pointer;
  overflow: hidden;
  -webkit-tap-highlight-color: transparent;
}

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

.addclient-camera__controls {
  /* Parent .addclient-camera uses align-items: center (flex-column), so
     children only take their content width. Override here so the controls
     row spans the full column — that's what lets flex:1 on Flip/Retake
     actually push them outward to either end (matching iOS's
     .frame(maxWidth: .infinity) on flipButton + retakeButton). */
  align-self: stretch;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Flip (left) + Retake (right) — each expands equally either side of the
   centered Capture button (HStack maxWidth:.infinity in photoControls).
   Icon over fontButtonSmall label, lightTextSecondary. */
.addclient-camera__control {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--gutter-half);
  background: none;
  border: 0;
  padding: 0;
  color: var(--app-text-secondary);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.addclient-camera__control-label {
  font: var(--app-button-sm);
  font-family: var(--app-font-sans);
}

/* Retake is disabled until a photo is captured (camera.capturedImage == nil). */
.addclient-camera__control--disabled {
  opacity: 0.3;
}

/* Source: AddClientPhotoView.swift:202-216 — outer Circle().stroke(
   lightTextPrimary, lineWidth: 2.5).frame(60pt) + inner Circle().fill(
   lightTextPrimary).frame(48pt). The space between is transparent
   (shows the beige page bg), not a white border. */
.addclient-camera__capture {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  width: 60px;
  height: 60px;
  border-radius: 50%;
  background: transparent;
  border: 2.5px solid var(--app-text-primary);
  box-shadow: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  padding: 0;
}

.addclient-camera__capture::before {
  content: "";
  display: block;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: var(--app-text-primary);
}

/* Step 3 option cards */
.addclient-options {
  display: flex;
  flex-direction: column;
  /* Source: AddClientStep2View+iPhone.swift:135 — VStack(spacing: .gutter(withMultiplier: 1.5)) = 12pt */
  gap: 12px;
}

.option-card {
  display: flex;
  align-items: flex-start;
  gap: var(--gutter-double);
  width: 100%;
  padding: var(--gutter-double);
  background: var(--app-card-bg);
  border: 1px solid var(--app-divider);
  border-radius: var(--radius-card);
  cursor: pointer;
  text-align: left;
  -webkit-tap-highlight-color: transparent;
}

.option-card__icon {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--app-bg);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--app-text-primary);
  flex-shrink: 0;
}

.option-card__body {
  flex: 1;
  min-width: 0;
}

.option-card__title {
  font: var(--app-button);
  color: var(--app-text-primary);
  margin: 0;
}

.option-card__desc {
  font: var(--app-body-sm);
  color: var(--app-text-secondary);
  margin: var(--gutter-half) 0 0 0;
}

.option-card__chevron {
  color: var(--app-text-tertiary);
  flex-shrink: 0;
  align-self: center;
}

/* AddClientStep1View.compactBottomBar — Cancel left, Spacer, Add Client right
   (primary, disabled until First Name + Last Name + Email all filled).
   Background Color.biege, top divider. Same chrome on Step 2/3 with
   Go Back + Skip for now in place of Cancel + Add Client. */
.addclient__footer {
  display: flex;
  align-items: center;
  gap: var(--gutter-double);
  /* 16pt top + sides (compactBottomBar .padding(.vertical/.horizontal,
     .doubleGutter)); extra bottom padding stands in for the iPhone
     home-indicator safe area iOS adds below the bar. */
  padding: var(--gutter-double) var(--gutter-double) var(--gutter-4);
  background: var(--app-bg);
  border-top: 0.5px solid var(--app-divider);
}

.addclient__footer .sheet__btn[hidden],
.addclient__footer .addclient__advance[hidden] { display: none; }

/* Right-anchor whichever primary/skip lives on the right; everything
   else flows left. */
.addclient__advance,
.addclient__footer [data-addclient-skip] {
  margin-left: auto;
}

.addclient__advance:disabled {
  background: rgba(17, 17, 17, 0.15);     /* dim primaryBlack for disabled */
  color: rgba(255, 255, 255, 0.55);
  cursor: not-allowed;
}

/* Toast for "Client added" confirmation after Step 3 */
.toast {
  position: absolute;
  left: 50%;
  bottom: 100px;
  transform: translateX(-50%);
  background: var(--app-text-primary);
  color: var(--app-card-bg);
  padding: var(--gutter-double) var(--gutter-3);
  border-radius: var(--radius-card);
  font: var(--app-button);
  box-shadow: var(--card-shadow);
  z-index: 20;
  animation: toast-in 0.25s ease;
}

@keyframes toast-in {
  from { opacity: 0; transform: translate(-50%, 20px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}

.toast[hidden] { display: none; }

/* ─────────────────────────────────────────────────────────────────
   Notification Banner — source: CoreUI/Components/Banners/
   NotificationBannerView.swift. Top-anchored white card with icon
   circle, title (H5), description (BodyMedium). Posted via
   InAppNotificationService.post(.clientAdded(...)) etc.

   Spec mapping:
     body HStack(top, .doubleGutter)         → 16px gap, top-aligned
     icon .frame(44, 44) + Circle + padding(10)
     title .fontHeading5 + lightTextPrimary
     description .fontBodyMedium + lightTextSecondary
     VStack inner spacing .defaultGutter      → 8px
     vertical padding .doubleGutter           → 16px
     horizontal padding .gutter(*3)           → 24px
     background Color.primaryWhite
     cornerRadius .defaultGutter (iPhone)     → 8px
     outer padding .horizontal .doubleGutter  → 16px from screen edge
     Shadow: 2 layers (shadow.opacity 0.09 r2, 0.08 r4 y2)

   Icon tint for .info type (used by .success factory per
   NotificationBannerView.swift:99):
     iconTint: lightTextTertiary  → #898989
     iconBackgroundTint: lightInfoBackground → #F5F5F5
     titleTint: lightTextPrimary → #111111
   ───────────────────────────────────────────────────────────────── */
.notification-banner {
  position: absolute;
  top: calc(54px + var(--gutter-double));
  left: var(--gutter-double);
  right: var(--gutter-double);
  z-index: 25;
  background: var(--app-card-bg);
  border-radius: 8px;
  padding: var(--gutter-double) var(--gutter-3);
  display: flex;
  align-items: flex-start;
  gap: var(--gutter-double);
  box-shadow:
    0 2px 4px rgba(53, 65, 80, 0.09),
    0 4px 8px rgba(53, 65, 80, 0.08);
  animation: notification-banner-in 0.3s cubic-bezier(0.32, 0.72, 0, 1);
}
.notification-banner[hidden] { display: none; }

@keyframes notification-banner-in {
  from { opacity: 0; transform: translateY(-16px); }
  to   { opacity: 1; transform: translateY(0); }
}

.notification-banner__icon {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: #F5F5F5;            /* Color.lightInfoBackground per ColorPalette.swift:142 */
  color: #898989;                 /* Color.lightTextTertiary per ColorPalette.swift:46 */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  padding: 10px;
}

.notification-banner__icon svg {
  width: 24px;
  height: 24px;
}

.notification-banner__text {
  display: flex;
  flex-direction: column;
  gap: var(--gutter);
  min-width: 0;
  flex: 1;
}

.notification-banner__title {
  margin: 0;
  font: var(--app-h5);
  color: var(--app-text-primary);
}

.notification-banner__description {
  margin: 0;
  font: var(--app-body);
  color: var(--app-text-secondary);
}

/* ─────────────────────────────────────────────────────────────────
   iOS action sheet (UIAlertController.actionSheet)
   Source: TCA ConfirmationDialogState rendered via SwiftUI's
   .confirmationDialog modifier in ClientOverviewView. Visual matches
   UIKit UIAlertController actionSheet style: bottom-anchored, two
   rounded-white pill groups separated by an 8px gap; first group has
   a small gray title and stacked action rows; second group is the
   Cancel pill (bold). Tap rows or backdrop to dismiss.
   ───────────────────────────────────────────────────────────────── */
.actionsheet-host {
  position: absolute;
  inset: 0;
  z-index: 11;                    /* above .sheet-host (10), below .referee-host */
  display: flex;
  align-items: flex-end;
}

.actionsheet-host[hidden] { display: none; }

.actionsheet-host__scrim {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
  cursor: pointer;
  animation: sheet-scrim-in 0.25s ease;
}

.actionsheet {
  position: relative;
  width: 100%;
  /* ~34pt clearance at the bottom for the home-indicator safe area —
     matches UIKit's actionSheet inset on iPhones with the dynamic island /
     notch chassis. Without it the Cancel pill renders flush against the
     screen bottom and gets visually clipped by the chassis curvature. */
  padding: 0 8px 34px 8px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  animation: actionsheet-in 0.28s cubic-bezier(0.32, 0.72, 0, 1);
}

@keyframes actionsheet-in {
  from { transform: translateY(100%); }
  to   { transform: translateY(0); }
}

.actionsheet__group {
  background: rgba(255, 255, 255, 0.82);
  backdrop-filter: blur(20px) saturate(180%);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  border-radius: 14px;
  overflow: hidden;
}

.actionsheet__title {
  padding: 14px 16px 12px;
  text-align: center;
  font: 400 13px/1.3 var(--app-font-sans);
  color: var(--app-text-secondary);
  border-bottom: 0.5px solid rgba(60, 60, 67, 0.36);
}

.actionsheet__title:empty { display: none; }

.actionsheet__actions {
  display: flex;
  flex-direction: column;
}

.actionsheet__action {
  background: transparent;
  border: 0;
  width: 100%;
  /* display:flex + center/center beats browser defaults that left-aligned
     <button> text inside a flex column container. */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 17px 16px;
  font: 400 20px/1.2 var(--app-font-sans);
  color: #007AFF;                 /* iOS system blue */
  cursor: pointer;
  border-bottom: 0.5px solid rgba(60, 60, 67, 0.36);
  -webkit-tap-highlight-color: transparent;
}

.actionsheet__action:last-child { border-bottom: 0; }
.actionsheet__action:active { background: rgba(0, 0, 0, 0.08); }

.actionsheet__action--cancel {
  font-weight: 600;
}

/* ─────────────────────────────────────────────────────────────────
   Edit Client sheet — content for the 3 sections that don't exist
   in Add Client (Profile Image, Active Status toggle, Comments).
   Visual matches the source ClientFormSectionView body padding.
   ───────────────────────────────────────────────────────────────── */

/* Profile Image row: 56pt circle avatar + button stack to the right. */
.editclient-profile-image {
  display: flex;
  align-items: center;
  gap: var(--gutter-double);
}

.editclient-profile-image .avatar--lg {
  width: 56px;
  height: 56px;
  font-size: 16px;
}

.editclient-profile-image__buttons {
  display: flex;
  gap: var(--gutter);
}

.editclient-profile-image__guidelines {
  margin: var(--gutter-double) 0 0 0;
  font: var(--app-body-sm);
  color: var(--app-text-secondary);
}

/* Leading-trailing toggle pattern. Source uses CoreUI's
   .toggleStyle(.leadingTrailing(leadingText:trailingText:)) — a label-left +
   switch-center + label-right row. Active label gets primary color, inactive
   gets secondary. Switch is a standard iOS toggle: gray track when off
   (leading active) → green track when on (trailing active). */
.leading-trailing-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--gutter-double);
  cursor: pointer;
  user-select: none;
}

.leading-trailing-toggle__input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.leading-trailing-toggle__leading,
.leading-trailing-toggle__trailing {
  font: var(--app-body);
  color: var(--app-text-secondary);
  transition: color 0.2s ease;
}

.leading-trailing-toggle__input:not(:checked) ~ .leading-trailing-toggle__leading,
.leading-trailing-toggle__input:checked ~ .leading-trailing-toggle__trailing {
  color: var(--app-text-primary);
  font-weight: 500;
}

.leading-trailing-toggle__track {
  position: relative;
  display: inline-block;
  width: 51px;
  height: 31px;
  border-radius: 999px;
  background: #E9E9EB;
  transition: background 0.2s ease;
}

.leading-trailing-toggle__track::after {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 27px;
  height: 27px;
  border-radius: 50%;
  background: #FFFFFF;
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.15), 0 3px 1px rgba(0, 0, 0, 0.06);
  transition: transform 0.2s ease;
}

.leading-trailing-toggle__input:checked ~ .leading-trailing-toggle__track {
  background: #34C759;             /* iOS system green */
}

.leading-trailing-toggle__input:checked ~ .leading-trailing-toggle__track::after {
  transform: translateX(20px);
}

/* Comments editor: 153pt min/max height per source's
   ClientProfileCommentsEditSection.clientCommentsEditorHeight = 153. */
.editclient-comments {
  display: flex;
  flex-direction: column;
  gap: var(--gutter);
}

.editclient-comments__label {
  font: var(--app-h5);
  color: var(--app-text-primary);
}

.editclient-comments__editor {
  min-height: 153px;
  max-height: 153px;
  padding: var(--gutter-double);
  border-radius: var(--gutter);
  border: 1px solid var(--app-divider);
  background: var(--app-card-bg);
  font: var(--app-body);
  color: var(--app-text-primary);
  resize: none;
  outline: none;
  font-family: inherit;
}

.editclient-comments__editor::placeholder {
  color: var(--app-text-tertiary, var(--app-text-secondary));
}

.editclient-comments__editor:focus {
  border-color: var(--app-text-primary);
}
