/* styles.css — עיצוב אפליקציית אלון */

  :root {
    --color-primary: #1E40AF;
    --color-secondary: #3B82F6;
    --color-accent: #059669;
    --color-bg: #0F172A;
    --color-fg: #FFFFFF;
    --color-muted: #101A34;
    --color-card: #16213E;
    --color-border: rgba(255,255,255,0.08);
    --color-destructive: #DC2626;
    --color-text-dim: #94A3B8;
    --color-success: #34D399;
    --chart-grid: rgba(255,255,255,0.06);
    --cat-arnona: #3B82F6;
    --cat-water: #06B6D4;
    --cat-electric: #F59E0B;
    --cat-gas: #EF4444;
    --radius: 12px;
    --space-1: 8px;
    --space-2: 12px;
    --space-3: 16px;
    --space-4: 24px;
    --space-5: 32px;
  }
  [data-theme="light"] {
    --color-bg: #F1F5F9;
    --color-fg: #0F172A;
    --color-muted: #E9EEF5;
    --color-card: #FFFFFF;
    --color-border: rgba(15,23,42,0.12);
    --color-text-dim: #566577;
    --color-success: #059669;
    --chart-grid: rgba(15,23,42,0.08);
  }
  /* Android PWA optimizations */
  @supports (padding: max(0px)) {
    body {
      padding-left: max(12px, env(safe-area-inset-left));
      padding-right: max(12px, env(safe-area-inset-right));
      padding-top: max(12px, env(safe-area-inset-top));
      padding-bottom: max(12px, env(safe-area-inset-bottom));
    }
  }
  /* Prevent text selection in UI elements on Android long-press */
  button, [role="button"], input, select, textarea {
    -webkit-user-select: none;
    user-select: none;
    -webkit-touch-callout: none;
  }
  /* Optimize for Android notch */
  html {
    padding-left: env(safe-area-inset-left);
    padding-right: env(safe-area-inset-right);
  }
  * { box-sizing: border-box; margin: 0; padding: 0; }
  /* Reserve the scrollbar's width always, whether or not the current tab's
     content is tall enough to need it - otherwise the page's horizontal
     position shifts left/right every time you switch to a tab that does
     (or doesn't) overflow the viewport. */
  html { scrollbar-gutter: stable; }
  body {
    background: var(--color-bg);
    color: var(--color-fg);
    transition: background 250ms ease-out, color 250ms ease-out;
    font-family: 'Noto Sans Hebrew', sans-serif;
    font-size: 16px;
    line-height: 1.5;
    min-height: 100dvh;
  }
  body.lang-ar { font-family: 'Noto Sans Arabic', sans-serif; }
  .container {
    max-width: 1200px; margin: 0 auto;
    padding: max(var(--space-4), env(safe-area-inset-top)) max(var(--space-3), env(safe-area-inset-right)) max(var(--space-4), env(safe-area-inset-bottom)) max(var(--space-3), env(safe-area-inset-left));
  }

  header {
    display: grid; grid-template-columns: auto 1fr; align-items: center;
    gap: var(--space-2); margin-bottom: var(--space-4);
  }
  header > .brand { justify-self: start; min-width: 0; }
  header > .header-actions { justify-self: end; min-width: 0; }
  .home-wrap { display: none; }
  .mobile-title-group { display: contents; }   /* desktop: transparent, no layout effect - see the mobile override below */
  @media (max-width: 600px) {
    /* Three real grid columns (title-group / logo / icons), auto 1fr auto: the two
       side columns size to their own content, the logo's middle column gets
       whatever space is left and centers the logo within it. Grid columns are hard,
       non-overlapping boundaries - unlike an absolutely-positioned "centered on the
       header" logo, this can never overlap the icons or the title even as the
       viewport narrows or the title text gets longer (a different language); the
       side columns just claim more of their own auto width and the middle (and the
       logo's apparent centering) shrinks gracefully instead. `order` reassigns the
       three groups to columns independent of their DOM sequence, same technique as
       flexbox's `order`. */
    /* #272: was `auto 1fr auto`, which centred the logo inside the MIDDLE COLUMN
       rather than on the page. The two side columns size to their own content and
       are never equal - the title group is wider than the icon cluster - so the
       middle column sat off to one side and took the logo with it, visibly
       leaning. `minmax(0,1fr) auto minmax(0,1fr)` gives both sides an equal share
       and lets the middle be exactly as wide as the logo, which puts the logo on
       the page's true centre line. minmax(0,…) rather than plain 1fr so a long
       title can still shrink instead of forcing the row wider. The non-overlap
       guarantee the note above describes is unchanged: these are still three hard
       grid columns, not an absolutely-positioned logo. */
    header { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); align-items: center; gap: 6px; }
    header > .brand { display: contents; }                                          /* let its children join the header's own grid row */
    .home-wrap { order: 1; }
    .mobile-title-group { order: 1; display: flex; align-items: center; gap: 6px; min-width: 0; }
    .brand-logo { order: 2; display: inline-flex; justify-self: center; }
    header > .header-actions { order: 3; justify-content: flex-end; gap: 6px; }
    header h1#appTitle { margin: 0; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    #vaadTabsToggle { flex: 0 0 auto; }
  }
  header h1 { font-size: 24px; font-weight: 700; display: flex; align-items: center; gap: var(--space-2); }
  header h1 svg { color: var(--color-secondary); }
  .header-actions { display: flex; gap: var(--space-2); align-items: center; }
  .file-hint { color: var(--color-text-dim); font-size: 13px; }
  /* A button meant to read as a plain word inline in a sentence (e.g. "click X"
     where X itself navigates), not a boxed control - resets all button chrome. */
  .inline-link-btn { background: none; border: none; padding: 0; margin: 0; font: inherit; color: var(--color-secondary); text-decoration: underline; cursor: pointer; min-height: 0; }
  /* Save icon, grouped with the rest of the header icon buttons - color
     switches to the destructive/red tone once the backup is overdue (the
     actual elapsed time lives in the button's title/aria-label tooltip,
     see updateBackupClock()) instead of a separate always-visible readout. */
  #backupClock.is-stale { color: var(--color-destructive); border-color: var(--color-destructive); }
  .link-thumb { width: 48px; height: 48px; object-fit: cover; border-radius: 6px; display: block; }
  /* A class `display` beats the UA [hidden]{display:none}, so a hidden preview img
     (e.g. the bug-report photo before one is attached) would otherwise show as an
     empty 48x48 box. Keep hidden thumbs actually hidden. */
  .link-thumb[hidden] { display: none; }
  .media-fallback { font-size: 20px; }

  /* Protect-your-data nudge — slim, dismissible banner. Surfaces the two strongest
     defenses against losing browser-only data (add-to-home-screen, which is exempt
     from iOS Safari's 7-day purge, and a one-tap file backup). Themed with tokens;
     works light + dark, RTL, and wraps its action row on narrow screens.
     DOM POSITION is load-bearing: this element is the LAST child of .container (after
     #dynamicViews), NOT under the header. maybeShowProtectNudge() reveals it reactively
     right after the user's first successful save (renderVaad() runs it after every
     add/edit/delete). If it lived above the tool views, appearing mid-work would shove
     the whole form (incl. the add button) down and the next click would miss. At the
     end of the flow, showing it only adds height BELOW everything - nothing above moves
     (no shift) - and being in normal flow it overlays nothing (no cover over the submit
     button, which a position:fixed bottom bar did do on mobile). */
  .protect-nudge {
    display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-3);
    background: var(--color-card); border: 1px solid var(--color-border);
    border-inline-start: 3px solid var(--color-secondary);
    border-radius: var(--radius); padding: var(--space-2) var(--space-3);
    margin-top: var(--space-4);
  }
  .protect-nudge[hidden] { display: none; }
  .protect-nudge-body { flex: 1 1 260px; min-width: 0; }
  .protect-nudge-title { font-size: 15px; font-weight: 700; }
  .protect-nudge-text { font-size: 13px; color: var(--color-text-dim); margin-top: 2px; }
  .protect-nudge-ios { margin-top: var(--space-1); }
  .protect-nudge-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1); }
  .protect-nudge-actions .btn-primary,
  .protect-nudge-actions .btn-edit { min-height: 38px; padding: 6px 14px; font-size: 14px; }
  .protect-nudge-link {
    background: transparent; color: var(--color-secondary); border: none;
    min-height: 38px; padding: 6px 10px; font-size: 14px; font-weight: 500; text-decoration: underline;
  }
  .protect-nudge-link:hover { color: var(--color-primary); }
  .protect-nudge-dismiss {
    background: transparent; color: var(--color-text-dim); border: none;
    min-height: 38px; padding: 6px 10px; font-size: 13px;
  }
  .protect-nudge-dismiss:hover { color: var(--color-fg); }
  @media (max-width: 600px) {
    .protect-nudge-actions { flex: 1 1 100%; }
  }

  /* Summary cards */
  .vaad-welcome-banner {
    display: flex; align-items: center; gap: var(--space-3);
    background: var(--color-card); border: 1px solid var(--color-border);
    border-radius: var(--radius); padding: var(--space-3) var(--space-4);
    margin-bottom: var(--space-3);
  }
  .vaad-welcome-wave { font-size: 28px; line-height: 1; flex: 0 0 auto; }
  .vaad-welcome-main { flex: 1 1 auto; min-width: 0; }
  .vaad-welcome-banner h2 { margin: 0 0 8px; font-size: 18px; font-weight: 700; }
  .vaad-welcome-banner p { margin: 0; color: var(--color-text-dim); font-size: 14px; }
  .vaad-welcome-banner p:empty, .vaad-welcome-banner p[hidden] { display: none; }
  /* Annual-collection bar - same expected/collected/debt figures the old
     collection+outstanding pie cards showed, same colors (accent green =
     collected, destructive red = debt) so a returning user reads it the
     same way; just one bar instead of two separate donuts. */
  .bar-row { display: flex; flex-direction: column; gap: 6px; }
  .bar-row[hidden] { display: none; }
  .bar-track { height: 8px; border-radius: 999px; background: var(--color-muted); overflow: hidden; display: flex; }
  .bar-seg.collected { background: var(--color-accent); }
  .bar-seg.debt { background: var(--color-destructive); }
  .bar-legend { display: flex; gap: var(--space-3); flex-wrap: wrap; font-size: 12.5px; color: var(--color-text-dim); }
  .bar-legend span { display: inline-flex; align-items: center; gap: 6px; }
  .bar-legend .dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
  .bar-legend .dot.forecast { background: var(--color-text-dim); opacity: .5; }
  .bar-legend .dot.collected { background: var(--color-accent); }
  .bar-legend .dot.debt { background: var(--color-destructive); }
  .vaad-welcome-balance {
    flex: 0 0 auto; text-align: center; padding-inline-start: var(--space-3);
    border-inline-start: 1px solid var(--color-border);
  }
  .vaad-welcome-balance[hidden] { display: none; }
  .vaad-welcome-balance .amt { font-size: 20px; font-weight: 800; }
  .vaad-welcome-balance .lbl { font-size: 12px; color: var(--color-text-dim); margin-top: 2px; }
  .vaad-welcome-balance .split { font-size: 11.5px; color: var(--color-text-dim); margin-top: 6px; }
  @media (max-width: 600px) {
    .vaad-welcome-banner { flex-wrap: wrap; }
    .vaad-welcome-balance { border-inline-start: none; padding-inline-start: 0; flex-basis: 100%; text-align: start; }
  }
  /* Lives inside a .dash-widget-card (half the row at best - see .dash-widgets
     grid), too narrow for 3 buttons side by side, so this one stacks instead
     of the row-of-equal-buttons pattern used elsewhere - same reasoning as
     any other "not enough room in width" exception: still same height/size
     per button, just one per line instead of one per column. */
  .vaad-quick-actions { display: flex; flex-direction: column; gap: var(--space-2); }
  .vaad-quick-actions[hidden] { display: none; }
  .vaad-quick-btn {
    background: transparent; color: var(--color-text-dim);
    border: 1px solid var(--color-primary); border-radius: var(--radius);
    padding: 10px 14px; min-height: 44px; font-size: 14px; font-weight: 500;
  }
  .vaad-quick-btn:hover { color: var(--color-fg); background: var(--color-muted); }
  .cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: var(--space-2); margin-bottom: var(--space-4); }
  .card {
    background: var(--color-card); border: 1px solid var(--color-border);
    border-radius: var(--radius); padding: var(--space-3);
    display: flex; flex-direction: column; gap: 4px;
    overflow: hidden;
  }
  .card .cat-label { display: flex; align-items: center; gap: 8px; color: var(--color-text-dim); font-size: 14px; font-weight: 500; }
  .card .dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
  .card .amount { font-size: 26px; font-weight: 700; font-variant-numeric: tabular-nums; }
  .card .sub { font-size: 12px; color: var(--color-text-dim); }
  /* #156: one row, split half/quarter/quarter - a wide data-table card
     (checks/faults/systems - pick one in Settings) is half the row; the
     other half is one merged card bundling upcoming-tasks and quick-action
     shortcuts (single on/off toggle), itself split evenly in two, so each
     of those reads as a quarter of the whole row. */
  .dash-widgets { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2); margin-bottom: var(--space-4); }
  @media (max-width: 700px) { .dash-widgets { grid-template-columns: 1fr; } }
  /* #189: either card alone spans the full row instead of sitting narrow
     next to a blank column track ([[prefers-symmetric-layouts]]). */
  .dash-widgets:has(#dashWidgetQuickActionsCard[hidden]) #dashWidgetSlot0:not([hidden]) {
    grid-column: 1 / -1;
  }
  .dash-widgets:has(#dashWidgetSlot0[hidden]) { grid-template-columns: 1fr; }
  .dash-widget-card {
    background: var(--color-card); border: 1px solid var(--color-border);
    border-radius: var(--radius); padding: var(--space-3);
    /* Grid items default to min-width:auto, which lets a nowrap table (see
       th/td above) grow the card past its 1fr track instead of scrolling
       inside .table-wrap - the card (and the whole row) then overflows the
       viewport on narrow/mobile screens. min-width:0 lets the grid track's
       width win, so .table-wrap's own overflow-x:auto is what actually
       handles a too-wide table, contained inside the card. */
    min-width: 0;
  }
  .dash-widget-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: var(--space-2); }
  .dash-widget-head h3 { margin: 0; font-size: 15px; }
  .dash-widget-all { background: transparent; border: none; color: var(--color-secondary); font-size: 13px; cursor: pointer; padding: 0; }
  .dash-widget-card table { font-size: 13px; }
  .dash-widget-card .empty { font-size: 13px; padding: var(--space-2) 0; }
  /* #251: each row is a shortcut straight to its own record (not just the
     card's "← הכל" link to the tab in general) - cursor + hover mark it
     clickable, same convention as row hovers elsewhere in the app. */
  .dash-widget-card tbody tr[data-id] { cursor: pointer; }
  .dash-widget-card tbody tr[data-id]:hover { background: var(--color-hover); }
  /* #dashWidgetSideInfo's plain figure rows (future-year forecast, undeposited
     checks) - no table, just label/value pairs, same 13px scale as the
     other widget cards' own table text. */
  .placeholder-row { display: flex; justify-content: space-between; align-items: center; font-size: 13px; padding: 6px 0; border-top: 1px solid var(--color-border); }
  .placeholder-row:first-of-type { border-top: none; }
  /* Upcoming-tasks and quick-actions sit side by side in the same merged
     half-card (not stacked) - same "same row" convention as everywhere else
     in the app - split exactly in half (a quarter of the whole dash-widgets
     row each). The divider is its own flex item, not a border/padding on
     one of the two columns: with flex-basis:0% (what "flex:1" resolves to),
     border-box padding on only one side still throws off the 50/50 split -
     empirically confirmed while building this. Quick-actions is the outer
     column since this card is itself already the outer half of the row.
     Only drops to stacked when the half-card is too narrow for 2 columns. */
  .vaad-tasks-actions-row { display: flex; gap: var(--space-3); }
  .vaad-tasks-col { flex: 1; min-width: 0; }
  .vaad-tasks-divider { flex: 0 0 1px; background: var(--color-border); align-self: stretch; }
  .vaad-actions-col { flex: 1; min-width: 0; }
  @media (max-width: 480px) {
    .vaad-tasks-actions-row { flex-direction: column; }
    .vaad-tasks-divider { display: none; }
    .vaad-actions-col { border-top: 1px solid var(--color-border); padding-top: var(--space-3); margin-top: var(--space-1); }
  }
  .vaad-tasks-list { display: flex; flex-direction: column; }
  .vaad-tasks-list .empty { font-size: 13px; padding: var(--space-2) 0; }
  /* Title + action share one line (room for it now that the column is a
     real quarter of the row, not the cramped width from an earlier pass);
     the sub-text runs full-width underneath. */
  .vaad-task-row {
    padding: 10px 0; border-top: 1px solid var(--color-border); cursor: pointer;
  }
  .vaad-task-row:first-child { border-top: none; }
  .vaad-task-row:hover { background: var(--color-hover); }
  .vaad-task-row-main { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
  .vaad-task-title { font-size: 14px; font-weight: 700; }
  .vaad-task-sub { font-size: 12px; color: var(--color-text-dim); margin-top: 2px; }
  .vaad-task-action {
    background: transparent; border: none; min-height: auto; color: var(--color-primary); font-size: 13px; font-weight: 600;
    cursor: pointer; padding: 0; white-space: nowrap; flex-shrink: 0;
  }
  .placeholder-row span:first-child { color: var(--color-text-dim); }
  .placeholder-row span:last-child { font-weight: 700; font-variant-numeric: tabular-nums; }
  /* Small anchored popover shown when marking a matrix cell paid, so the
     one-click "mark paid" stays fast - no full dialog just to pick cash vs
     check vs bank. Positioned in JS (position: fixed, near the clicked cell). */
  .pay-method-picker {
    position: fixed; z-index: 60; background: var(--color-card); border: 1px solid var(--color-border);
    border-radius: var(--radius); box-shadow: 0 8px 24px rgba(0,0,0,.18); padding: 6px; display: flex; gap: 4px;
  }
  .pay-method-picker button {
    border: none; background: transparent; color: var(--color-text); font-size: 13px; font-weight: 600;
    padding: 8px 12px; border-radius: calc(var(--radius) - 4px); cursor: pointer; white-space: nowrap; min-height: 36px;
  }
  .pay-method-picker button:hover, .pay-method-picker button:focus-visible { background: rgba(59,130,246,.12); }
  @media (max-width: 480px) {
    .pay-method-picker { flex-direction: column; }
  }
  .card.total { border-color: var(--color-accent); }
  .card.total .amount { color: var(--color-success); }
  /* A total that IS an expense stays red. .card.total .amount (0,3,0) outranks a
     bare .amount-out (0,1,0), which is why the expenses total rendered green
     despite carrying the class - this puts the outgoing colour back on top. */
  .card.total .amount.amount-out { color: #F87171; }
  [data-theme="light"] .card.total .amount.amount-out { color: #DC2626; }
  /* Future/not-yet-due collection forecast - neutral blue, deliberately distinct
     from the red "debt" card (nothing is overdue yet) and the green "collected"
     one (it hasn't been collected yet either). */
  .card.future { border-color: var(--color-secondary); }
  .card.future .amount { color: var(--color-secondary); }
  /* Expenses tab: the "סה"כ הוצאות" total sits above the sub-tabs, pinned to the
     left (RTL: flex-end is the visual left edge), as a compact card, not a full-width grid. */
  /* The expenses total rides on the same row as the sub-tabs (kept INSIDE the .tabs
     bar so the shared sub-tab switcher still sees the three panels as its direct
     siblings), pushed to the far RTL-left end and rendered as a compact one-line
     pill rather than a tall card. */
  #vaadfixed-subtabs, #vaadincome-subtabs { align-items: center; }
  #vaadfixed-subtabs > #vaadfixed-summary, #vaadincome-subtabs > #vaadincome-summary { margin-inline-start: auto; display: flex; }
  .vaadfixed-total-left .card { flex-direction: row; align-items: baseline; gap: 10px; min-width: auto; margin: 0; padding: 6px 14px; }
  .vaadfixed-total-left .card .cat-label { margin: 0; }
  .vaadfixed-total-left .card .amount { font-size: 20px; }
  .vaadfixed-total-left .card .sub { opacity: .7; font-size: 12px; }
  /* The expenses total now lives inside the sub-tab bar, which @media print hides
     wholesale (.tabs { display:none }). Keep the total on printouts while still
     dropping the tab buttons themselves. */
  @media print {
    #vaadfixed-subtabs, #vaadincome-subtabs { display: flex !important; }
    #vaadfixed-subtabs > .tab, #vaadincome-subtabs > .tab { display: none !important; }
  }

  /* Panels */
  .grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3); margin-bottom: var(--space-4); }
  @media (max-width: 900px) { .grid-2 { grid-template-columns: 1fr; } }
  .panel {
    background: var(--color-card); border: 1px solid var(--color-border);
    border-radius: var(--radius); padding: var(--space-3);
  }
  .panel h2 { font-size: 16px; font-weight: 500; margin-bottom: var(--space-2); color: var(--color-text-dim); }

  /* Form — one wrapping row: the fields, the notes box, and the add/clear buttons all
     flow together and pack into as few rows as possible, instead of forcing the notes
     field and the buttons each onto their own full-width row. On wide screens a short
     form (fields + notes + buttons) lands on a single line; a busy one wraps to just
     two. The buttons trail at the (RTL) left end and drop down only once the fields
     have already filled the row. */
  /* flex-direction:row is explicit, not the default left implicit - the generic
     `dialog form { flex-direction: column }` rule (below) otherwise wins for
     this property with nothing here to out-specificity it, since this rule
     never used to set flex-direction at all. Silent breakage the moment this
     form ends up nested inside ANY dialog (as vaadfixedAddDialog now does):
     every flex-basis above stops meaning "preferred width" and starts meaning
     "preferred height" instead, since column swaps the main/cross axes -
     which is exactly what turned this into a tall single-column stack. */
  form.add-form { display: flex; flex-direction: row; flex-wrap: wrap; align-items: stretch; gap: var(--space-2) var(--space-3); }
  /* min-width:0 lets a field - notably a native <input type="date">, whose intrinsic
     min-width is wide on some mobile browsers - shrink to fit instead of spilling out.
     A small flex-basis packs many fields per row (they grow to fill any slack), so even
     a six-field form keeps its add/clear buttons on the same row on a normal screen. */
  /* justify-content:flex-end (2026-08-01): align-items:stretch above equalizes
     every label's OUTER box to the row's tallest field, but a label's own text
     can still wrap to 2 lines (e.g. "Number of installments") while its
     neighbors stay 1 line - the input right after that text then sits a whole
     line lower than siblings even though the boxes are the same total height.
     Anchoring to the end packs the extra space ABOVE the label text instead,
     so every input in the row lands on the same baseline regardless of how
     many lines its own label wraps to. */
  form.add-form > label { flex: 1 1 104px; min-width: 0; justify-content: flex-end; }
  /* Notes is a plain single-line input; let it grow wider but keep it inline. */
  form.add-form > label.ff-notes { flex: 2 1 140px; }
  /* align-items:stretch (above) equalizes every field's invisible label box to
     the row's tallest field - but a textarea's rows="2" renders visibly taller
     (~67px) than its neighbours' 44px controls, so its bordered box sticks out
     below the row even though the labels line up. Every TOOLKIT-generated inline
     field textarea (.ff-textarea, emitted by fieldHTML) is pinned to the same
     44px as the inputs beside it - and never auto-grown (data-no-grow, baked in
     by fieldHTML too). Deliberately general, not per-form: this is the recurring
     "keep fields the same height / same row" issue (forum #69/#75), so a new
     record form can never re-introduce it. (Hand-written message composers, e.g.
     waMessageText, are NOT .ff-textarea and still grow to show the full text.) */
  textarea.ff-textarea { height: 44px; overflow-y: auto; resize: none; }
  /* A date field's input is width-capped (max-width:150px below); without
     matching its LABEL to that width the label keeps growing (flex:1 1 104px)
     and leaves a gap between the date and the next field. Size the label to the
     input so they align edge-to-edge like every other field. */
  form.add-form > label:has(input[type="date"]),
  form.add-form > label:has(.date-input-wrap) { flex: 0 1 150px; }
  /* QA (2026-08-02): a plain text/number input can absorb a too-narrow basis by
     just showing less of its typed value (still fully readable once focused/
     scrolled) - a <select> can't, its closed box permanently clips whatever
     the selected OPTION's translated text is. The shared 104px basis above was
     sized for Hebrew's short option words (e.g. "מזומן") and clipped es/fr's
     longer ones (e.g. "Cheque depositado", "Chèque déposé") behind the native
     arrow on every add-form select fed by a fixed option list (payment method,
     building-system check frequency, etc.) in both vaadfixed and vaadincome. */
  form.add-form > label:has(select) { flex: 1 1 160px; }
  /* #70: give description the room the fixed-height rule above doesn't - a
     cost in ILS never needs 6+ figures worth of width, and "in N months"
     only needs enough to keep its own three pieces (prefix/number/suffix)
     from wrapping onto their own line - so both shrink and description,
     the field visitors actually write real text into, grows instead. */
  form[data-add="buildingsys"] label.ff-description { flex: 2 1 200px; }
  form[data-add="buildingsys"] label.ff-cost { flex: 0 1 90px; }
  form[data-add="buildingsys"] label.ff-nextServiceDate { flex: 1 1 165px; }
  /* #69: same idea for the vendor-request form - the request text is the field
     that actually holds real content, so let it grow while the fixed-size date
     and vendor picker stay put. */
  form[data-add="vendorRequests"] label.ff-requestText { flex: 2 1 200px; }
  /* Buttons (a .path-row wrapper, or a bare submit on the hard-coded forms) trail the
     fields on the same row; the growing fields fill the slack so the buttons land at
     the (RTL) left end. They wrap down only when the fields truly can't fit the row. */
  form.add-form > .path-row { flex: 0 0 auto; align-self: end; }
  form.add-form > button[type="submit"] { flex: 0 0 auto; align-self: end; }
  form.add-form > .path-row button { white-space: nowrap; }
  .date-input-wrap, .date-input-wrap > input { min-width: 0; }
  /* Sectioned add-form (residents): 3 labelled boxes side by side, fields stacked in each. */
  form.add-form.form-sectioned { display: flex; flex-wrap: wrap; gap: 10px; align-items: stretch; }
  /* flex-grow:0 (not 1): a section left alone on the last row must stay the
     same width as its siblings, not stretch to fill the leftover space -
     residents' 3 sections (resident/apartment/extra) don't always divide
     evenly across rows at a dialog's width, and a stretched lone section
     made its fields visibly wider than the same fields in the other two. */
  form.add-form.form-sectioned .form-section { flex: 0 1 165px; display: grid; grid-template-columns: 1fr; gap: 6px; align-content: start; background: rgba(127,127,127,0.05); border: 1px solid rgba(127,127,127,0.16); border-radius: 9px; padding: 8px 10px; }
  form.add-form.form-sectioned .form-section-title { font-weight: 700; font-size: 11.5px; opacity: 0.62; letter-spacing: 0.3px; }
  form.add-form.form-sectioned .form-section label { font-size: 12px; gap: 2px; }
  form.add-form.form-sectioned .form-section input, form.add-form.form-sectioned .form-section select { padding: 5px 8px; font-size: 13px; }
  form.add-form.form-sectioned > button[type="submit"] { flex-basis: 100%; }
  label { display: flex; flex-direction: column; gap: 4px; font-size: 13px; color: var(--color-text-dim); }
  input, select, textarea {
    background: var(--color-muted); color: var(--color-fg);
    border: 1px solid var(--color-border); border-radius: 8px;
    padding: 10px 12px; font-family: inherit; font-size: 16px; min-height: 44px;
  }
  textarea { width: 100%; resize: vertical; line-height: 1.5; overflow-y: auto; }  /* auto-grows to fit its text (see autoGrowTextarea) so no scrollbar shows; overflow:auto is a safe fallback (a bar, never clipped text) if a box wasn't grown */
  /* Field-level validation errors (flagFieldError/clearFieldError): a visible
     red border for sighted users, alongside the aria-invalid/aria-describedby
     pair that tells screen-reader users WHICH field a toast was about. */
  input[aria-invalid="true"], select[aria-invalid="true"], textarea[aria-invalid="true"] {
    border-color: var(--color-destructive);
    outline: 1px solid var(--color-destructive);
  }
  .field-error {
    color: var(--color-destructive); font-size: 12px; margin-top: -2px;
  }
  .field-error:empty { display: none; }
  /* #77: 24h time is entered via two dropdowns (see upgradeTimeInput24h) instead
     of a native time input whose picker shows AM/PM per the device locale. */
  .time24-wrap { display: inline-flex; align-items: center; gap: 4px; direction: ltr; }
  .time24-wrap .time24-sel { min-width: 3.4em; width: auto; padding: 10px 8px; text-align: center; font-variant-numeric: tabular-nums; }
  .time24-colon { opacity: 0.7; font-weight: 600; }
  .time24-wrap.time24-disabled { opacity: 0.4; }
  /* Date/time inputs: the browser's native displayed text (both the
     mm/dd/yyyy-style placeholder and the chosen value) follows the
     visitor's own OS/browser locale, not the page's language, and the
     `lang` attribute trick to override this proved unreliable in practice
     across real browsers. Instead: the native input's own text is made
     invisible (kept fully functional - typing, the calendar/clock picker,
     keyboard nav all still work), and a plain-text overlay we fully
     control renders the value in guaranteed dd/mm/yyyy / 24h format on
     top of it. See upgradeDateTimeInput(). */
  .date-input-wrap {
    position: relative; display: block;
    inline-size: 100%; max-inline-size: 100%; min-inline-size: 0;
    overflow: hidden; box-sizing: border-box;
  }
  .date-input-wrap > input {
    inline-size: 100%; max-inline-size: 100%; min-inline-size: 0;
    box-sizing: border-box;
  }
  form.add-form > label:has(.date-input-wrap) { overflow: hidden; }
  .date-input-wrap > input:not(:focus) { color: transparent; }
  /* The gap goes on the side the picker icon is REALLY on. A date input computes
     as LTR even inside our RTL page, so Chrome draws ::-webkit-calendar-picker-
     indicator against the input's RIGHT edge (~24px) - which in RTL is this
     overlay's inline-START. Reserving the gap at inline-end (the left) instead
     let the icon sit on top of the last two digits: "16/07/2026" over "26". */
  .date-input-overlay {
    position: absolute; inset-inline-start: 30px; inset-inline-end: 12px; top: 0; bottom: 0;
    display: flex; align-items: center; pointer-events: none;
    font-family: inherit; font-size: 16px; color: var(--color-fg);
    font-variant-numeric: tabular-nums; white-space: nowrap; overflow: hidden;
  }
  .date-input-wrap > input:focus ~ .date-input-overlay { visibility: hidden; }
  .date-input-overlay.is-placeholder { color: var(--color-text-dim); }
  input:focus-visible, select:focus-visible, textarea:focus-visible, button:focus-visible, a:focus-visible, [role="button"]:focus-visible { outline: 2px solid var(--color-secondary); outline-offset: 1px; }
  button {
    cursor: pointer; border: none; border-radius: 8px; min-height: 44px;
    padding: 10px 20px; font-family: inherit; font-size: 15px; font-weight: 500;
    transition: background 200ms ease-out, transform 150ms ease-out;
  }
  button:active { transform: scale(0.97); }
  .btn-primary { background: var(--color-primary); color: #fff; }
  .btn-primary:hover { background: var(--color-secondary); }
  .btn-danger { background: transparent; color: var(--color-destructive); border: 1px solid var(--color-destructive); min-height: 36px; padding: 4px 12px; font-size: 13px; }
  .btn-danger:hover { background: rgba(220,38,38,0.15); }
  .btn-edit { background: transparent; color: var(--color-secondary); border: 1px solid var(--color-secondary); min-height: 36px; padding: 4px 12px; font-size: 13px; }
  .btn-edit:hover { background: rgba(59,130,246,0.15); }
  .icon-btn {
    background: var(--color-card); color: var(--color-fg);
    border: 1px solid var(--color-border);
    min-width: 44px; min-height: 44px; padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 10px;
    position: relative;   /* #119: anchors driveStatusDot's absolute position */
  }
  .icon-btn:hover { border-color: var(--color-secondary); color: var(--color-secondary); }
  /* #119: connected/disconnected/needs-reauth signal on the Drive header
     button - color set by updateDriveUI() via .dot-connected/.dot-stalled;
     hidden entirely while disconnected (the plain icon already reads as
     "not connected yet, click to connect"). */
  .drive-status-dot {
    position: absolute; top: 2px; left: 2px;
    width: 10px; height: 10px; border-radius: 50%;
    border: 2px solid var(--color-card);
    background: var(--color-text-dim);
  }
  .drive-status-dot.dot-connected { background: #22C55E; }
  .drive-status-dot.dot-stalled { background: #F59E0B; }
  .wa-hero-settings-btn { width: auto; padding: 0 14px; gap: 8px; font-size: 13px; font-weight: 600; font-family: inherit; white-space: nowrap; flex-shrink: 0; }
  [data-theme="light"] .icon-moon { display: none; }
  :root:not([data-theme="light"]) .icon-sun { display: none; }
  .lang-code { font-size: 12px; font-weight: 700; letter-spacing: 0.02em; }

  /* Brand + tool menu */
  .brand { display: flex; align-items: center; gap: var(--space-2); position: relative; }
  .home-btn svg { color: var(--color-secondary); }
  .help-btn svg { color: var(--color-accent); }
  .help-btn:hover { border-color: var(--color-accent); color: var(--color-accent); }
  /* RLAPP.net shortcut — links to the parent portal. Same .icon-btn base as
     every other header button; just a plain 4-square icon in accent blue. */
  .rlapp-icon-btn svg { color: var(--color-secondary); }
  #helpDialog { max-width: 640px; width: 92%; }
  /* #helpDialog is a flex column (title/tabs fixed, body fills remaining space)
     so .help-body is the ONLY scrollable region - previously both the native
     <dialog> itself (capped by the browser at ~viewport height) and this inner
     div had their own independent scrollbar, showing as two stacked bars.
     A fixed height (not max-height) keeps the dialog's own size constant when
     switching between the system/tool tabs instead of visibly resizing to
     match whichever tab's content happens to be shorter or taller. */
  #helpDialog { display: flex; flex-direction: column; height: 85vh; overflow: hidden; }
  #helpDialog:not([open]) { display: none; }
  #helpDialog > *:not(.help-body) { flex: 0 0 auto; }
  .help-body { flex: 1 1 auto; min-height: 0; font-size: 14px; line-height: 1.75; overflow-y: auto; padding-inline-end: 6px; overscroll-behavior-y: contain; }
  .help-body[hidden] { display: none; }
  .help-section { margin-bottom: 18px; }
  .help-section h4 { font-size: 15px; font-weight: 600; margin-bottom: 6px; color: var(--color-fg); display: flex; align-items: center; gap: 8px; }
  .help-ico { color: var(--color-accent); flex-shrink: 0; }
  .help-section.help-current { border-top: 1px solid var(--color-border); padding-top: 14px; }
  .help-section.help-current h4 { color: var(--color-secondary); }
  .help-body p { margin-bottom: 10px; color: var(--color-text-dim); }
  .help-body ul { margin: 8px 0; padding-inline-start: 20px; }
  .help-body li { margin-bottom: 7px; }
  .help-body strong { color: var(--color-fg); font-weight: 500; }
  .help-body .help-tag { display: inline-block; background: var(--color-muted); border: 1px solid var(--color-border); border-radius: 6px; padding: 1px 8px; font-size: 13px; }
  .tool-menu {
    position: absolute; top: calc(100% + 8px); inset-inline-start: 0; z-index: 1000;
    background: var(--color-card); border: 1px solid var(--color-border);
    border-radius: var(--radius); padding: var(--space-1);
    min-width: 280px; box-shadow: 0 12px 40px rgba(0,0,0,0.45);
    display: flex; flex-direction: column; gap: 2px;
  }
  .tool-menu[hidden] { display: none; }
  /* Language section reads as its own group, set off from the actions above it
     by a divider - previously just a smaller/dimmer label with no separation. */
  .tool-menu-head { font-size: 12px; color: var(--color-text-dim); padding: 8px 12px 4px; font-weight: 500; margin-top: 6px; border-top: 1px solid var(--color-border); padding-top: 10px; }
  .tool-item {
    display: flex; align-items: center; gap: var(--space-2);
    background: transparent; color: var(--color-fg); text-align: start;
    padding: 8px 12px; border-radius: 8px; min-height: 44px;
    transition: background 120ms ease;
  }
  /* Each icon sits in its own soft tinted "chip" instead of floating bare - the
     single change that reads as the most polished at a glance. */
  .tool-item svg { color: var(--color-secondary); flex-shrink: 0; background: rgba(59,130,246,0.12); border-radius: 8px; padding: 6px; box-sizing: content-box; }
  .tool-item span { display: flex; flex-direction: column; }
  .tool-item small { color: var(--color-text-dim); font-size: 12px; }
  .tool-item:hover { background: var(--color-muted); }
  .tool-item.active { background: rgba(59,130,246,0.15); }
  .tool-item[hidden] { display: none; }
  .tool-menu-showall {
    display: block; width: 100%; text-align: center; background: transparent; color: var(--color-secondary);
    font-size: 12.5px; font-weight: 600; padding: 9px 12px; border-radius: 8px; margin-top: 2px;
    border-top: 1px solid var(--color-border);
  }
  .tool-menu-showall:hover { background: var(--color-muted); }
  .tool-menu-showall[hidden] { display: none; }

  /* Mobile overflow ("more") menu — hidden on desktop; on phones it replaces the
     four global chrome buttons in the header. Reuses .tool-menu (position/shadow/
     width) and .tool-item/.lang-item; anchored to the header's END edge via logical
     props so it works in both RTL and LTR without a transform override. */
  .chrome-wrap { position: relative; display: none; align-items: center; }
  .chrome-menu { inset-inline-start: auto; inset-inline-end: 0; }
  @media (max-width: 600px) {
    .chrome-wrap { display: inline-flex; }
    /* .header-actions scope on .lang-wrap raises specificity above its base
       `.lang-wrap{display:inline-flex}` rule, which is defined LATER in source and
       would otherwise win at equal specificity. The IDs already outrank their bases. */
    /* themeToggle/lang-wrap moved out of .header-actions into #settingsDialog
       (#51) - scoped so this rule can't hide them there too on mobile. */
    #settingsBtn, .header-actions #themeToggle, .header-actions .lang-wrap, #helpBtn, #printBtn, .rlapp-icon-btn { display: none; }  /* fronted by the overflow menu on phones */
  }

  .lang-wrap { position: relative; display: inline-flex; align-items: center; }
  .lang-menu {
    position: absolute; top: calc(100% + 8px); inset-inline-end: 0; z-index: 1000;
    background: var(--color-card); border: 1px solid var(--color-border);
    border-radius: var(--radius); padding: var(--space-1);
    min-width: 160px; box-shadow: 0 12px 40px rgba(0,0,0,0.45);
    display: flex; flex-direction: column; gap: 2px;
  }
  .lang-menu[hidden] { display: none; }
  .lang-item {
    display: flex; align-items: center;
    background: transparent; color: var(--color-fg); text-align: start;
    padding: 10px 12px; border-radius: 8px; min-height: 40px; font-size: 15px;
  }
  .lang-item:hover { background: var(--color-muted); }
  .lang-item.active { background: rgba(59,130,246,0.15); font-weight: 600; }

  /* Views */
  .view[hidden] { display: none; }
  /* .tabs sets its own display:flex below, which (same specificity, later in
     source) would otherwise beat the browser's default [hidden]{display:none}
     and keep the tab bar visible even while hidden - e.g. expensesTabs staying
     shown with the "complex mode" checkbox off. */
  .tabs[hidden] { display: none; }
  /* Same trap, plain <label>: the generic `label { display:flex }` rule further down
     beats the UA [hidden]{display:none} for ANY hidden label - the "advanced mode"
     fields on the expenses add-form (#199) were always visible regardless of the
     toggle, crowding the layout on narrow/mobile widths. */
  label[hidden] { display: none; }
  /* Same inline-style-beats-[hidden] trap as .tabs - this bar was showing an empty
     "Signed in as: " + Disconnect button to every visitor, signed in or not. */
  .wa-account-bar { display: flex; align-items: center; gap: 10px; }
  .wa-account-bar[hidden] { display: none; }
  .wa-hero-signin { display: flex; flex-direction: column; align-items: center; gap: 6px; flex-shrink: 0; }
  .wa-hero-signin[hidden] { display: none; }
  .wa-hero-signin .file-hint { margin: 0; text-align: center; max-width: 240px; }
  .wa-unified-connect-btn { white-space: normal; }
  .wa-signin-or { margin-top: 6px !important; opacity: 0.85; }
  /* Once it wraps it must own the row, or it sits squeezed against one edge with
     the title stranded beside it. Google's widget is a fixed 220px and cannot be
     made narrower, so the row is given to it rather than fought over. */
  @media (max-width: 600px) {
    .wa-hero-signin { flex-basis: 100%; margin-inline: auto; }
  }

  /* Ledger amounts */
  .amount-in { color: var(--color-success); }
  .amount-out { color: #F87171; }
  [data-theme="light"] .amount-out { color: #DC2626; }
  .type-badge { display: inline-flex; align-items: center; gap: 6px; padding: 3px 10px; border-radius: 999px; font-size: 13px; }
  .type-in { background: rgba(5,150,105,0.18); color: var(--color-success); }
  .type-out { background: rgba(220,38,38,0.16); color: #F87171; }
  [data-theme="light"] .type-out { color: #DC2626; }
  .card .amount.neg { color: #F87171; }
  [data-theme="light"] .card .amount.neg { color: #DC2626; }

  /* Tabs (vaad hub) */
  /* padding-top leaves room for the focus ring: button:focus draws a 2px outline
     at 1px offset, i.e. 3px ABOVE the tab. A tabs row sitting flush at the top of
     a scrollable box (the settings dialog) had that ring clipped along its top
     edge, so a focused tab looked like a broken half-rectangle. */
  .tabs { display: flex; gap: 4px; padding-top: 4px; margin-bottom: 20px; border-bottom: 1px solid var(--color-border); flex-wrap: wrap; }
  /* #201: in light mode the top-level tool tabs (#vaad-tabs) and a sub-tab row
     directly below them (e.g. #vaadfixed-subtabs) both sit on the same plain
     background with identical active-tab styling, with nothing marking which
     level is which. A faint blue wash on just the top-level bar (dark mode's own
     contrast already makes this clear enough - left alone there) gives the outer
     tabs a distinct band without competing with the blue "active" underline. */
  /* #201 follow-up: this selector's specificity ([data-theme]+#id) beats the
     mobile drawer's plain #vaad-tabs rule below, regardless of source order -
     so without the width guard it was overriding that rule's OWN deliberately-
     opaque background (see its comment: "dense Hebrew tab labels need a solid
     surface to stay readable") with a translucent one, muddying the drawer
     against its own active-tab highlight. Desktop-only fixes that for real. */
  @media (min-width: 601px) {
    [data-theme="light"] #vaad-tabs {
      background: rgba(59, 130, 246, 0.06);
      margin-inline: calc(-1 * var(--space-3));
      padding-inline: var(--space-3);
      border-radius: var(--radius) var(--radius) 0 0;
    }
  }
  .tab { background: transparent; color: var(--color-text-dim); border: none; border-bottom: 2px solid transparent; border-radius: 8px 8px 0 0; padding: 10px 20px; min-height: 44px; font-size: 15px; }
  .tab:hover { color: var(--color-fg); background: var(--color-muted); }
  .tab.active { color: var(--color-secondary); border-bottom-color: var(--color-secondary); font-weight: 500; }
  .tab-panel[hidden] { display: none; }

  /* Message design has three navigation depths: vaad page tabs, message actions,
     and reminder type. Make the inner two visually distinct so nested tabs do not
     read as one long, confusing tab stack. */
  .wa-flow-nav {
    margin: 0 0 var(--space-3);
    padding: 10px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: rgba(59,130,246,0.06);
  }
  [data-theme="light"] .wa-flow-nav { background: rgba(59,130,246,0.05); }
  .wa-nav-label {
    margin: 0 2px 8px;
    font-size: 12px;
    font-weight: 700;
    color: var(--color-text-dim);
  }
  #waWizTabs {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(128px, 1fr));
    gap: 8px;
    margin: 0;
    padding: 0;
    border-bottom: 0;
  }
  #waWizTabs .tab {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    min-width: 0;
    min-height: 46px;
    padding: 8px 10px;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    background: var(--color-card);
    border-bottom-color: var(--color-border);
    white-space: normal;
    text-align: center;
    line-height: 1.25;
  }
  #waWizTabs .tab.active {
    background: rgba(59,130,246,0.16);
    border-color: rgba(59,130,246,0.55);
    color: var(--color-fg);
    box-shadow: inset 0 -3px 0 var(--color-secondary);
  }
  .wa-reminder-mode-shell {
    margin: 0 0 var(--space-3);
    padding: 10px;
    border: 1px dashed var(--color-border);
    border-radius: var(--radius);
    background: rgba(127,127,127,0.05);
  }
  #waCmReminderModeTabs {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 6px;
    margin: 0;
    padding: 4px;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    background: var(--color-card);
  }
  #waCmReminderModeTabs .tab {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 0;
    min-height: 40px;
    padding: 7px 8px;
    border: 1px solid transparent;
    border-radius: 6px;
    border-bottom-color: transparent;
    font-size: 13.5px;
    white-space: normal;
    text-align: center;
    line-height: 1.25;
  }
  #waCmReminderModeTabs .tab.active {
    background: rgba(37,211,102,0.13);
    border-color: rgba(37,211,102,0.45);
    color: var(--color-fg);
    box-shadow: none;
  }
  .wa-reminder-workspace {
    padding: var(--space-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: rgba(0,0,0,0.06);
  }
  [data-theme="light"] .wa-reminder-workspace { background: rgba(15,23,42,0.025); }
  .view-toggle { display: flex; gap: 4px; margin-bottom: 16px; border-bottom: none; }
  .view-toggle .tab { padding: 6px 16px; min-height: 36px; font-size: 13px; background: var(--color-muted); border-radius: 999px; border-bottom: none; }
  .view-toggle .tab.active { background: var(--color-secondary); color: #fff; }
  /* List/Kanban single-button toggle, pinned to the far end of the tabs row
     (visually the left side in the app's default RTL) instead of living as
     a separate row inside the Tasks panel. */
  .tasks-view-toggle-btn { margin-inline-start: auto; align-self: center; min-height: 36px; padding: 5px 16px; font-size: 13px; }
  .tasks-view-toggle-btn[hidden] { display: none; }

  /* Vaad tabs — mobile off-canvas drawer (<=600px only; desktop keeps the wrapped
     flex row above exactly as-is). #vaad-tabs is built once by vaadViewHTML() and
     never rebuilt - this only REPOSITIONS that same element via CSS into a fixed
     drawer; the existing delegated click handler on #vaad-tabs (in wireVaadView())
     keeps working untouched since it's attached to the element, not its position.
     Opened/closed by toggling the `tabs-drawer-open` class on <body> (see
     openTabsDrawer()/closeTabsDrawer() near homeBtn/closeMenu() in the script). */
  #vaadTabsCloseBtn { display: none; }
  @media (max-width: 600px) {
    #vaad-tabs {
      position: fixed; top: 0; bottom: 0; inset-inline-start: 0;
      width: min(78vw, 320px); z-index: 9997;
      flex-direction: column; flex-wrap: nowrap; align-items: stretch;
      overflow-y: auto; overscroll-behavior-y: contain;
      /* Reserve the status bar / gesture-nav bar on notched Android devices -
         this drawer is position:fixed so it escapes the body's own safe-area
         padding; without this its close button/last tab can sit under the bar. */
      padding: max(var(--space-2), env(safe-area-inset-top)) var(--space-2) max(var(--space-2), env(safe-area-inset-bottom));
      /* Opaque, NOT translucent: dense Hebrew tab labels need a solid surface to
         stay readable. The translucency lives on #vaadTabsBackdrop below (which
         dims the page behind the drawer) - that IS the requested transparency;
         the drawer panel itself must stay fully solid. */
      background: var(--color-card); border-bottom: none;
      border-inline-end: 1px solid var(--color-border);
      box-shadow: 0 0 24px rgba(0,0,0,.35);
      transform: translateX(100%); transition: transform .25s ease;
    }
    /* inset-inline-start:0 above resolves to right:0 in RTL, left:0 in LTR - so
       "hidden" must push the panel further in that SAME physical direction. A
       bare translateX(100%) only does that for RTL; in LTR (en/ru, switched via
       document.documentElement.dir) it left the panel ~82px onscreen at all
       times, tab buttons live and clickable through a "closed" drawer. Mirrors
       the existing [dir="ltr"] override convention used for .date-range-arrow. */
    [dir="ltr"] #vaad-tabs { transform: translateX(-100%); }
    body.tabs-drawer-open #vaad-tabs { transform: translateX(0); }
    #vaad-tabs .tab { width: 100%; text-align: start; border-radius: 8px; border-bottom: none; }
    #vaad-tabs .tab.active { background: rgba(59,130,246,0.15); border-bottom: none; border-inline-start: 3px solid var(--color-secondary); }
    #vaadTabsCloseBtn { display: flex; align-self: flex-end; margin-bottom: var(--space-2); flex-shrink: 0; }
    #vaadTabsBackdrop { display: none; }
    body.tabs-drawer-open #vaadTabsBackdrop { display: block; position: fixed; inset: 0; z-index: 9996; background: rgba(0,0,0,.5); }
  }

  /* Message-sending wizard (msgdesign): 1-2-3 stepper for the manual/auto flows. */
  .wa-stepper { display: flex; align-items: center; gap: 4px; margin: var(--space-2) 0 var(--space-3); }
  .wa-step { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--color-text-dim); }
  .wa-step-dot { width: 26px; height: 26px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-weight: 700; font-size: 13px; background: var(--color-muted); color: var(--color-text-dim); border: 1px solid var(--color-border); flex-shrink: 0; }
  .wa-step.active { color: var(--color-fg); font-weight: 600; }
  .wa-step.active .wa-step-dot { background: var(--color-primary); color: #fff; border-color: var(--color-primary); }
  .wa-step.done .wa-step-dot { background: var(--color-secondary); color: #fff; border-color: var(--color-secondary); }
  .wa-step-bar { flex: 1; height: 2px; background: var(--color-border); min-width: 12px; }
  .wa-step-bar.done { background: var(--color-secondary); }
  .wa-wiz-nav { display: flex; justify-content: space-between; gap: var(--space-2); margin-top: var(--space-3); flex-wrap: wrap; }
  .wa-step-action-row {
    justify-content: flex-start;
    direction: ltr;
  }
  .wa-step-action-row > button,
  .wa-wiz-nav.wa-final-action-left > button {
    direction: rtl;
  }
  .wa-wiz-nav.wa-final-action-left {
    justify-content: flex-start;
    direction: ltr;
  }
  .wa-wiz-nav.wa-final-action-left .btn-primary:not([hidden]) {
    order: -1;
  }
  .wa-wiz-review-warn { background: rgba(245,158,11,0.12); border: 1px solid rgba(245,158,11,0.4); border-radius: var(--radius); padding: 10px 12px; font-size: 13.5px; margin-bottom: var(--space-2); }
  /* Google refuses to sign in at all from inside WhatsApp/Instagram/Facebook's
     own in-app browser (its own anti-phishing policy, not something this site
     can work around) - warn BEFORE the visitor hits Google's own cryptic error,
     instead of leaving them stuck on accounts.google.com with no way back. */
  .wa-inapp-warn { background: rgba(245,158,11,0.12); border: 1px solid rgba(245,158,11,0.4); border-radius: var(--radius); padding: 10px 12px; font-size: 13.5px; margin-bottom: var(--space-3); }
  .wa-inapp-warn[hidden] { display: none; }
  /* #72: active-automatic-reminders list - one card per armed building-system reminder. */
  .wa-active-auto-card { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); flex-wrap: wrap; background: var(--color-card); border: 1px solid var(--color-border); border-radius: var(--radius); padding: 10px 14px; margin-bottom: var(--space-2); }
  .wa-active-auto-info { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
  @media (max-width: 600px) {
    .wa-msgdesign-panel { padding: 10px; }
    .wa-flow-nav,
    .wa-reminder-mode-shell,
    .wa-reminder-workspace { padding: 10px; }
    /* #310/#321: a traditional scrolling wheel/roller picker instead of a tall
       stack of 7 full-width buttons (owner's own request - the stacked list
       "isn't right", wanted the picker feel instead). Same buttons, same
       click handler, same waShowWtab() - only the mobile presentation
       changes; desktop's grid is untouched.
       Design-handoff pass (2026-08-04): #321's fade-only styling (opacity +
       scale, brand-blue band) read as "greyed-out text," not a wheel, and the
       14%-alpha blue band nearly vanished in the light theme against
       #F1F5F9. Replaced with a real iOS-style picker - rows rotate around the
       X axis by distance from centre (written per-frame by initIosWheel() in
       app.html, search WIZ_WHEEL_ROW_H there), and the selection slot uses
       Apple's own neutral fill instead of a brand tint, so it reads correctly
       in both themes.
       Geometry contract (do not break): ROW_H (40) × VISIBLE_ROWS (2) = wrap
       height (80) - half a row above, the selected row, half a row below;
       #waWizTabs padding-block = (80 − 40) / 2 = 20;
       .wa-wiz-tabs-wrap::before top/height must match. The JS reads the same
       three numbers - if a row height changes, all four values change together. */
    .wa-wiz-tabs-wrap {
      position: relative; height: 80px; perspective: 420px; overflow: hidden;
      border-radius: 12px; background: var(--color-card);
      border: 1px solid var(--color-border);
      /* Forces its own compositing layer - without it, some browsers (seen on
         mobile Safari/Chrome) fail to clip 3D-transformed children to the
         rounded corners and let the top/bottom half-rows visibly poke past
         the curve even though overflow:hidden is set. */
      transform: translateZ(0);
    }
    .wa-wiz-tabs-wrap::before {
      content: ''; position: absolute; left: 6px; right: 6px; top: 20px; height: 40px;
      border-radius: 9px; background: rgba(120,120,128,.12);
      pointer-events: none; z-index: 2;
    }
    #waWizTabs {
      position: relative; z-index: 1; height: 100%;
      display: block;
      grid-template-columns: none;
      overflow-y: scroll; overscroll-behavior: contain;
      scroll-snap-type: y mandatory;
      padding: 20px 0; margin: 0; gap: 0;
      scrollbar-width: none; -webkit-overflow-scrolling: touch;
      transform-style: preserve-3d;
    }
    #waWizTabs::-webkit-scrollbar { display: none; }
    #waWizTabs .tab {
      /* min-height overrides the generic .tab rule's 44px floor (styles.css:684)
         - min-height wins over a smaller height regardless of selector
         specificity, since they're different properties, not competing
         declarations of the same one. Left at 44px, every row rendered 46px
         tall instead of 40, throwing off scroll-snap's actual centre point
         and everything the geometry contract depends on. */
      height: 40px; min-height: 40px; scroll-snap-align: center;
      display: flex; align-items: center; justify-content: center; gap: 7px;
      width: 100%; padding: 0 14px; border: 0; border-radius: 0; background: transparent;
      font-size: 19px; color: var(--color-fg); white-space: nowrap;
      overflow: hidden; text-overflow: ellipsis;
      backface-visibility: hidden; transform-origin: center center;
      /* NO opacity/transform/transition here - JS writes them per frame. */
    }
    #waWizTabs .tab.active { background: transparent; box-shadow: none; }
    #waCmReminderModeTabs { grid-template-columns: 1fr; }
    #waCmReminderModeTabs .tab { justify-content: flex-start; text-align: start; }
    .wa-stepper {
      align-items: stretch;
      gap: 6px;
      margin: var(--space-2) 0;
    }
    .wa-step-bar { display: none; }
    .wa-step {
      flex: 1 1 0;
      min-width: 0;
      flex-direction: column;
      justify-content: flex-start;
      gap: 5px;
      text-align: center;
      font-size: 11.5px;
      line-height: 1.2;
    }
    .wa-step span:not(.wa-step-dot) {
      display: block;
      max-width: 100%;
      overflow-wrap: anywhere;
    }
    .wa-wiz-nav > button { flex: 1 1 120px; }
  }

  /* Compact-nav opt-in (Settings > עוד): use the phone-style hamburger (tabs
     drawer) + kebab (actions) on ANY width, e.g. a tablet. Mirrors the
     max-width:600px nav rules but keyed off body.compact-nav instead of viewport. */
  body.compact-nav .chrome-wrap { display: inline-flex; }
  body.compact-nav #vaadTabsToggle { display: flex; }
  body.compact-nav #settingsBtn,
  body.compact-nav .header-actions #themeToggle,
  body.compact-nav .header-actions .lang-wrap,
  body.compact-nav #helpBtn,
  body.compact-nav #printBtn,
  body.compact-nav .rlapp-icon-btn { display: none; }
  body.compact-nav #vaad-tabs {
    position: fixed; top: 0; bottom: 0; inset-inline-start: 0;
    width: min(78vw, 320px); z-index: 9997;
    flex-direction: column; flex-wrap: nowrap; align-items: stretch;
    overflow-y: auto; overscroll-behavior-y: contain;
    padding: max(var(--space-2), env(safe-area-inset-top)) var(--space-2) max(var(--space-2), env(safe-area-inset-bottom));
    /* frosted-glass transparency (requested) — solid fallback first for browsers
       without color-mix/backdrop-filter, then the translucent + blurred surface. */
    background: var(--color-card);
    background: color-mix(in srgb, var(--color-card) 84%, transparent);
    -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
    border-bottom: none; border-inline-end: 1px solid var(--color-border);
    box-shadow: 0 0 24px rgba(0,0,0,.35);
    transform: translateX(100%); transition: transform .25s ease;
  }
  [dir="ltr"] body.compact-nav #vaad-tabs { transform: translateX(-100%); }
  body.compact-nav.tabs-drawer-open #vaad-tabs { transform: translateX(0); }
  body.compact-nav #vaad-tabs .tab { width: 100%; text-align: start; border-radius: 8px; border-bottom: none; }
  body.compact-nav #vaad-tabs .tab.active { background: rgba(59,130,246,0.15); border-bottom: none; border-inline-start: 3px solid var(--color-secondary); }
  body.compact-nav #vaadTabsCloseBtn { display: flex; align-self: flex-end; margin-bottom: var(--space-2); flex-shrink: 0; }
  body.compact-nav #vaadTabsBackdrop { display: none; }
  body.compact-nav.tabs-drawer-open #vaadTabsBackdrop { display: block; position: fixed; inset: 0; z-index: 9996; background: rgba(0,0,0,.5); }

  /* QA (2026-08-02) follow-up: the auto-detected overflow fix above (switching
     the WHOLE bar to the compact-nav drawer) was too blunt - it hid tabs that
     still had plenty of room, just because 1-2 OTHERS didn't fit. Replaced
     with a standard responsive-toolbar pattern instead: keep every tab that
     fits inline, at full size and full label (no shrinking spacing or names),
     and move only the ones that don't fit into a small "More" menu appended
     to the end of the row - see updateNavTabsOverflow() in the script, which
     decides per-tab visibility instead of an all-or-nothing switch. */
  .tabs-more-wrap { position: relative; }
  .tabs-more-wrap[hidden] { display: none; }
  /* Deliberately NOT .tab - #vaad-tabs's delegated click handler matches any
     .tab via closest() and expects a real data-tab value; giving this button
     that class too made clicking it mis-fire as a tab switch to "undefined"
     and blank every panel. Mirrors .tab's look via its own declarations
     instead so it's visually indistinguishable from a real tab. */
  .tabs-more-btn {
    background: transparent; color: var(--color-text-dim); border: none;
    border-bottom: 2px solid transparent; border-radius: 8px 8px 0 0;
    padding: 10px 20px; min-height: 44px; font-size: 15px; white-space: nowrap;
  }
  .tabs-more-btn:hover { color: var(--color-fg); background: var(--color-muted); }
  .tabs-more-btn[aria-expanded="true"] { color: var(--color-secondary); }
  /* Marks which group (כספים/תפעול) the CURRENTLY ACTIVE tab lives in - same
     visual language as .tab.active, since a group button stands in for a real
     tab once one of its menu items is picked. Independent of [aria-expanded]
     above, which only reflects whether the dropdown happens to be open. */
  .tabs-more-btn.active { color: var(--color-secondary); border-bottom-color: var(--color-secondary); font-weight: 500; }
  .tabs-more-menu { min-width: 200px; }
  .tabs-more-menu[hidden] { display: none; }
  .tabs-more-menu .tool-item { width: 100%; }
  /* Positioning context for the finance/ops dropdowns' absolutely-positioned
     .tool-menu, same role .tabs-more-wrap plays for the "More" menu. */
  .vaad-tab-group { position: relative; }

  /* Vaad WhatsApp messaging tab */
  /* flex-wrap is load-bearing, not cosmetic. The Google button is a fixed 220px
     that Google's own widget refuses to shrink, so on a phone the row needed
     ~405px inside 343px - and with nowrap + overflow:hidden the button was
     pushed to left:-71px and CLIPPED AWAY. Not merely ugly: elementFromPoint at
     its centre returned the element behind it, i.e. sign-in was unreachable on
     mobile, and sign-in is the only door to the whole messaging module.
     overflow:hidden has to stay - it keeps the gradient inside the rounded
     corners - so wrapping is what gives the button somewhere to go. */
  .wa-hero {
    display: flex; align-items: center; flex-wrap: wrap; gap: 16px; padding: var(--space-4);
    background: linear-gradient(135deg, rgba(37,211,102,0.16), rgba(37,211,102,0.02) 60%);
    border: 1px solid rgba(37,211,102,0.28); border-radius: calc(var(--radius) + 4px);
    box-shadow: 0 10px 30px -18px rgba(37,211,102,0.55);
    margin-bottom: var(--space-3); position: relative; overflow: hidden;
  }
  .wa-hero-icon {
    flex-shrink: 0; width: 52px; height: 52px; border-radius: 16px;
    background: linear-gradient(150deg, #2be080, #1fa855);
    display: flex; align-items: center; justify-content: center;
    box-shadow: 0 6px 16px -4px rgba(37,211,102,0.65);
  }
  .wa-hero-icon svg { color: #fff; width: 27px; height: 27px; }
  /* #170: "how it works" button under the hero icon, opening the same
     explainer dialog as msgdesign's own trigger (#148) - not a new one.
     #188: was sitting almost flush against the icon and read as too small -
     more breathing room + a size closer to the app's normal control size. */
  .wa-hero-icon-col { display: flex; flex-direction: column; align-items: center; gap: 14px; flex-shrink: 0; }
  .wa-hero-help-btn { white-space: nowrap; min-height: 44px; padding: 9px 32px; font-size: 15px; }
  .wa-hero h2 { font-size: 20px; font-weight: 800; margin-bottom: 2px; letter-spacing: -0.2px; }
  .wa-hero p { color: var(--color-text-dim); font-size: 13.5px; line-height: 1.5; margin: 0; text-transform: uppercase; letter-spacing: 0.4px; font-weight: 600; }
  .wa-tiers-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: var(--space-3); margin: var(--space-3) 0; }
  .wa-tiers-grid[hidden] { display: none; }
  .wa-tier-card {
    background: linear-gradient(160deg, var(--color-card), rgba(37,211,102,0.03));
    border: 1px solid var(--color-border); border-radius: calc(var(--radius) + 2px);
    padding: var(--space-4) var(--space-3); text-align: center; position: relative;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
  }
  .wa-tier-card.current {
    border-color: #25D366; background: linear-gradient(160deg, rgba(37,211,102,0.14), var(--color-card) 65%);
    box-shadow: 0 14px 30px -18px rgba(37,211,102,0.75), 0 0 0 1px rgba(37,211,102,0.35) inset;
    transform: translateY(-2px);
  }
  .wa-tier-card .wa-tier-badge {
    position: absolute; top: -11px; inset-inline-start: 50%; transform: translateX(-50%);
    background: linear-gradient(120deg, #2be080, #1fa855); color: #fff; font-size: 11px; font-weight: 700;
    padding: 3px 12px; border-radius: 999px; white-space: nowrap; box-shadow: 0 4px 10px -3px rgba(37,211,102,0.7);
  }
  [dir="rtl"] .wa-tier-card .wa-tier-badge { transform: translateX(50%); }
  .wa-tier-dots { display: flex; align-items: center; justify-content: center; gap: 4px; margin-bottom: 8px; }
  .wa-tier-dots span { width: 6px; height: 6px; border-radius: 50%; background: var(--color-border); }
  .wa-tier-dots span.filled { background: #25D366; }
  .wa-tier-card .wa-tier-range { font-size: 12.5px; color: var(--color-text-dim); margin-bottom: 8px; font-weight: 600; }
  .wa-tier-card .wa-tier-price { font-size: 28px; font-weight: 800; letter-spacing: -0.5px; }
  .wa-tier-card .wa-tier-unit { font-size: 11.5px; color: var(--color-text-dim); margin-bottom: 4px; }
  .wa-tier-card .wa-tier-quota { font-size: 11px; color: var(--color-text-dim); margin-top: 8px; line-height: 1.4; padding-top: 8px; border-top: 1px dashed var(--color-border); }
  .wa-tier-card .wa-paypal-wrap { text-align: start; margin-inline: auto; }
  .wa-quota-badge {
    display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--color-text-dim);
    background: var(--color-muted); border-radius: 999px; padding: 6px 14px; margin-bottom: var(--space-2);
  }
  #wa-paypal-button-container { max-width: 320px; margin-top: var(--space-2); }
  .wa-recipients-note { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--color-text-dim); margin-bottom: var(--space-2); }
  .wa-agreement-box {
    background: var(--color-muted); border: 1px solid var(--color-border); border-radius: var(--radius);
    padding: var(--space-3); margin: var(--space-2) 0; display: flex; flex-direction: column; gap: 10px;
  }
  .wa-agreement-text {
    background: var(--color-card); border: 1px solid var(--color-border);
    border-radius: var(--radius); padding: var(--space-2);
  }
  .wa-agreement-text-body { white-space: pre-line; font-size: 12.5px; line-height: 1.6; color: var(--color-text-dim); }
  .wa-agreement-text .wa-agreement-check { margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--color-border); }
  .wa-agreement-check { display: flex; align-items: flex-start; gap: 8px; font-size: 13px; cursor: pointer; }
  .wa-agreement-check input { margin-top: 3px; accent-color: #25D366; }
  .wa-id-field { display: flex; flex-direction: column; gap: 4px; font-size: 13px; max-width: 220px; }
  .wa-paypal-wrap { position: relative; max-width: 320px; margin-top: var(--space-2); min-height: 48px; }
  .wa-settings-account { margin-bottom: var(--space-3); }
  .wa-gsi-custom-btn {
    display: flex; align-items: center; justify-content: center; gap: 10px;
    width: 220px; height: 42px; margin-top: 6px; border-radius: 8px; border: 1px solid var(--color-border);
    background: var(--color-card); color: var(--color-fg); font-family: inherit;
    font-size: 14px; font-weight: 600; cursor: pointer;
  }
  .wa-gsi-custom-btn:hover { background: var(--color-muted); }
  .wa-gsi-fallback { margin-top: 8px; }
  .wa-gsi-fallback[hidden] { display: none; }

  /* Signed-out CTA card */
  .wa-cta-card {
    display: flex; flex-direction: column; align-items: center; text-align: center; gap: 14px;
    padding: var(--space-5, 32px) var(--space-4); max-width: 460px; margin: 0 auto;
  }
  .wa-cta-card .wa-cta-icon {
    width: 56px; height: 56px; border-radius: 50%; background: rgba(37,211,102,0.14);
    display: flex; align-items: center; justify-content: center; color: #25D366;
  }
  .wa-cta-card .wa-cta-icon svg { width: 28px; height: 28px; }
  .wa-cta-card p { margin: 0; }

  /* Message design sandbox: recipient list + selection */
  /* No scrollbar, no fixed cap: the list always shows every resident at its
     natural height. To still end on the same line as the compose column, the
     message textarea (not the list) is the one that stretches/shrinks to
     match - see .wa-msg-field below. */
  .wa-design-grid { display: grid; grid-template-columns: 1.1fr 1fr; gap: var(--space-3); align-items: stretch; }
  @media (max-width: 720px) { .wa-design-grid { grid-template-columns: 1fr; } }
  /* Its own card boundary (background + border + radius), so the list column
     never reads as a continuation of the compose column even when their
     heights happen to line up. */
  .wa-design-list-col {
    background: var(--color-card); border: 1px solid var(--color-border);
    /* min-width:0 lets this grid item shrink below its table's min-content.
       Without it the 6-column resident table (the consent column alone is
       ~252px: a badge + a non-wrapping "בקש הסכמה" button) forced the whole
       page ~183px wider than the phone. Pairs with overflow-x on the wrap
       below - both are needed, neither alone fixes it. */
    border-radius: calc(var(--radius) + 4px); padding: var(--space-3); min-width: 0;
  }
  .wa-compose-form { display: flex; flex-direction: column; }
  .wa-msg-lang-field { flex: 0 0 auto; }
  .wa-msg-lang-field select { max-width: 130px; }
  /* #165: vendor names + the "choose a vendor"/"choose a committee contact"
     placeholders run longer than the 130px this class was sized for
     elsewhere (a short day-count/language field) - truncated the text
     mid-word. These selects get their own wider width instead of
     widening the shared class (which would affect its other, genuinely
     narrow, uses). #167: this was `flex: 1 1 180px` - the parent <label>
     is flex-direction:column, so that flex-basis set the select's HEIGHT
     to 180px, not its width. Plain width avoids the axis ambiguity.
     #167 (cont'd): same truncation hit the committee-reminder wizard's
     own vendor picker (waCmRemindVendor) - same .wa-msg-lang-field/pros-select
     combo, same fix. */
  /* QA (2026-08-02): a vendor's stored "name — profession" text is arbitrary
     user data (not a translated fixed string) - it can run to hundreds of px
     regardless of UI language, so no fixed width fully prevents overflow. The
     closed box previously just hard-clipped mid-word behind the native arrow
     (worst measured case: an 830px-wide option in a 200px box); text-overflow
     turns that into a clean "…" instead - modern browsers apply it to a
     <select>'s own displayed value even though the open dropdown list itself
     still renders each option at full width (unavoidable, native control). */
  #vendorReqConsolidateVendor, #vendorReqSenderPhone, #waCmRemindVendor {
    max-width: none; width: 220px; min-width: 160px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  #waDesignSelectedCount { font-size: 16px; font-weight: 600; color: var(--color-fg); }
  /* Recipient-list toolbar (select-unpaid / all / clear / refresh + count). Compact
     single-line chips that wrap to a new row when the column is narrow - white-space:
     nowrap stops a long Hebrew label from ever breaking mid-word into the old squeezed
     two-line box. margin-inline-end:auto on the count pushes it to the row's far edge. */
  .wa-design-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1); margin-bottom: var(--space-2); }
  /* #waDesignSelectAllToggle switched from .btn-ghost to .btn-primary (2026-08-01,
     see its own HTML comment) so its COLOR stands out from the narrower "לא שילמו"
     filter beside it - listed alongside .btn-ghost here so its SIZE still matches;
     .btn-primary/.btn-ghost only carry color, this toolbar's own rule carries size. */
  .wa-design-toolbar .btn-ghost, .wa-design-toolbar .btn-primary { white-space: nowrap; min-height: 34px; padding: 6px 12px; font-size: 13px; }
  /* #84: refresh enlarged to sit level with the recipients count, right beside it;
     the "select:" label + filter chips are pushed to the row's far end. */
  .wa-design-toolbar .wa-refresh-big { white-space: nowrap; min-height: 40px; padding: 6px 16px; font-size: 15px; font-weight: 600; }
  .wa-design-toolbar #waDesignSelectedCount { font-size: 16px; font-weight: 600; color: var(--color-fg); }
  .wa-design-toolbar .wa-toolbar-spacer { margin-inline-start: auto; }
  /* The selection buttons cluster together (right, in RTL); the refresh + count sit
     apart at the end - so the toolbar reads as two tidy groups, not four loose boxes. */
  .wa-toolbar-group { display: inline-flex; flex-wrap: wrap; gap: 4px; }
  .wa-toolbar-label { align-self: center; }
  /* Paid + consent are status columns whose content is a centred badge/button - centre
     the header text too so it sits over the middle of the column, not its right edge. */
  .wa-design-list th.wa-col-center, .wa-design-list td.wa-col-center { text-align: center; }
  .wa-auto-row { display: flex; align-items: center; gap: 10px; margin-bottom: var(--space-2); flex-wrap: wrap; }
  .wa-auto-row-label { font-size: 13.5px; font-weight: 600; min-width: 60px; }
  .wa-auto-day-input { width: 60px; }
  /* Auto-grows to fit its text (see waAutoGrow) so the multi-line reminder message
     never shows a side scrollbar - the owner wants as few scroll "bars" as possible.
     min-height keeps an empty box at a comfortable ~3 rows. */
  .wa-auto-message { width: 100%; margin-bottom: var(--space-3); resize: vertical; overflow-y: auto; min-height: 78px; box-sizing: border-box; }
  .wa-auto-active-toggle { min-height: auto; }
  .wa-auto-row.wa-auto-inactive { opacity: 0.5; }
  .wa-free-remind-time-row {
    display: grid;
    grid-template-columns: minmax(220px, 1fr) minmax(170px, 220px) minmax(128px, 148px) minmax(140px, 160px);
    gap: var(--space-2);
    align-items: start;
    margin-bottom: var(--space-2);
  }
  .wa-free-remind-time-row > label { min-width: 0; }
  .wa-free-remind-time-row input,
  .wa-free-remind-time-row select,
  .wa-free-remind-time-row .date-input-wrap,
  .wa-free-remind-time-row .time24-wrap { width: 100%; max-width: 100%; }
  .wa-free-remind-time-row .time24-wrap { justify-content: stretch; }
  .wa-free-remind-time-row .time24-sel { flex: 1 1 0; min-width: 0; }
  @media (max-width: 760px) {
    .wa-free-remind-time-row { grid-template-columns: 1fr 1fr; }
    .wa-free-remind-title-field { grid-column: 1 / -1; }
  }
  @media (max-width: 430px) {
    .wa-free-remind-time-row { grid-template-columns: 1fr; }
  }
  /* Visual-only "locked" state for the whatsapp tab button when not subscribed -
     still fully clickable, just signals "this needs a subscription" at a glance. */
  .tab.wa-tab-locked { opacity: 0.55; }
  .tab.wa-tab-locked #waTabLock { font-size: 12px; }
  #waUnifiedTabLock { font-size: 12px; }
  /* Dimmed, non-interactive teaser of the real message-design tool - visible but
     you can't click anything, on purpose (curiosity, not usability). */
  [data-panel="msgdesign"].wa-dimmed-preview { opacity: 0.45; pointer-events: none; filter: grayscale(30%); user-select: none; }
  /* #107: keep the wizard tab STRIP clickable even while the rest of the panel is
     dimmed behind the teaser, so the free-reminders tab (a local, non-paid feature)
     stays reachable. The tabs sit at full opacity; only the body below stays dimmed. */
  [data-panel="msgdesign"].wa-dimmed-preview #waWizTabs { pointer-events: auto; opacity: 1; filter: none; user-select: auto; }
  .wa-skip-bar { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-bottom: var(--space-2); }
  .wa-skip-bar[hidden] { display: none; }
  .wa-skip-bar .checkbox-row, .wa-connect-aside .checkbox-row { font-size: 13px; color: var(--color-text-dim); }
  /* Sign-in and the preview-skip setting, one row, no divider. align-items:start
     keeps both sides top-aligned so the row doesn't jump if one side is taller.
     gap is the only separation - the eye reads it as one header, not two cells. */
  .wa-connect-row { display: flex; align-items: flex-start; gap: clamp(16px, 5%, 40px); margin-bottom: var(--space-3); }
  .wa-connect-row[hidden] { display: none; }
  .wa-connect-main { flex: 0 0 auto; }               /* right (RTL): the Google button, natural width */
  .wa-connect-aside { flex: 1 1 0; min-width: 0; }   /* left: the skip setting, takes the rest */
  .wa-connect-aside .checkbox-row { align-items: center; gap: 8px; }
  .wa-connect-aside .checkbox-row input[type="checkbox"] { flex: 0 0 auto; }
  .wa-skip-hint { margin: 6px 0 0; max-width: 46ch; }
  @media (max-width: 640px) {   /* stack on a phone: side-by-side gets too cramped */
    .wa-connect-row { flex-direction: column; gap: var(--space-2); }
    .wa-connect-main, .wa-connect-aside { flex: 1 1 auto; width: 100%; }
  }
  .wa-dimmed { opacity: 0.45; pointer-events: none; }
  /* Dimmed but still clickable, so a locked click can explain why and offer to
     purchase instead of just doing nothing (see each one's own click handler).
     #waLaunchWizardBtn added 2026-08-01 - it used to ALSO get the native
     disabled attribute (blocking every click, not just pointer-events), so it
     needed no exception here; removing that left it caught by the pointer-
     events:none above like any other .wa-dimmed element, same silent-click
     bug this exception list exists to prevent. */
  [data-remind-system].wa-dimmed, [data-activate-vendor].wa-dimmed, #waLaunchWizardBtn.wa-dimmed { pointer-events: auto; cursor: pointer; }
  .add-form input[type="date"] { max-width: 150px; }
  /* #257/design-project-item-2 (2026-08-01): the category/system field used to be
     a free-text input PLUS a companion <select> picker, because native <datalist>
     is unusable on iOS (no dropdown, just ~3 options fed into the keyboard's
     QuickType bar) AND - on every platform, not just iOS - mixes the raw stored
     value into its popup alongside the translated label for a non-Hebrew UI (the
     picker was added specifically to dodge that, per its own now-removed comment
     history). Replaced with a real, custom combobox: ONE input plus a listbox we
     fully render ourselves (JS: the delegated .catsel-list handlers near
     populateCatDatalists), so it's keyboard-navigable, shows only translated
     labels on every platform/language, and never needs a second control kept in
     sync with the first. Typing a brand-new value still works exactly as before -
     the listbox is suggestions, not a constraint. */
  .catsel { position: relative; width: 100%; }
  .catsel > input { width: 100%; padding-inline-end: 2.1rem; box-sizing: border-box; }
  .catsel-toggle {
    position: absolute; inset-inline-end: 2px; top: 2px; bottom: 2px;
    width: 28px; display: flex; align-items: center; justify-content: center;
    background: transparent; border: none; color: var(--color-text-dim); cursor: pointer; padding: 0;
  }
  .catsel-toggle svg { width: 16px; height: 16px; }
  .catsel-list {
    position: absolute; top: calc(100% + 4px); inset-inline-start: 0; inset-inline-end: 0;
    z-index: 30; max-height: 240px; overflow-y: auto; margin: 0; padding: 4px;
    list-style: none; background: var(--color-card); border: 1px solid var(--color-border);
    border-radius: 8px; box-shadow: 0 8px 24px rgba(0,0,0,0.35);
  }
  .catsel-list li { padding: 8px 10px; border-radius: 6px; cursor: pointer; font-size: 14px; }
  .catsel-list li.active, .catsel-list li:hover { background: var(--color-muted); }
  .catsel-list li[hidden] { display: none; }
  /* "Choose another system" (#81/#245) - a shortcut to Settings, not a real
     suggestion, so it's visually separated from the real options above it. */
  .catsel-list li.catsel-add-option { border-top: 1px solid var(--color-border); margin-top: 4px; padding-top: 10px; color: var(--color-secondary); font-weight: 600; }
  /* The indicator ships as a near-black glyph: invert it for the dark theme, but
     NOT in light mode - inverting there paints it white on a white field, which
     is why the icon looked missing rather than merely faint. */
  input[type="date"]::-webkit-calendar-picker-indicator,
  input[type="time"]::-webkit-calendar-picker-indicator { filter: invert(0.85); opacity: 0.8; cursor: pointer; }
  [data-theme="light"] input[type="date"]::-webkit-calendar-picker-indicator,
  [data-theme="light"] input[type="time"]::-webkit-calendar-picker-indicator { filter: none; opacity: 0.75; }
  /* #70: every money field's up/down spinner, gone - see fieldHTML's noSpinner. */
  input.no-spinner { -moz-appearance: textfield; }
  input.no-spinner::-webkit-outer-spin-button, input.no-spinner::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
  #waDesignForm { display: flex; flex-direction: column; flex: 1; }
  #waDesignForm .wa-msg-field { display: flex; flex-direction: column; flex: 1; }
  #waDesignForm .wa-msg-field textarea { resize: vertical; }  /* no flex:1 — let autoGrowTextarea set the height so the whole message shows without a scrollbar; resize lets the user override that manually too */
  /* Entrance (כניסה) is only meaningful once the building actually has more than
     one - hidden everywhere it'd otherwise show as a column of dashes (table cells
     use .col-entrance, add-form fields use .ff-entrance). */
  .no-entrances .col-entrance, .no-entrances .ff-entrance { display: none; }
  /* List header with inline filters (residents). Title on one side, filters on
     the other; wraps to its own line on a narrow screen instead of squeezing. */
  .list-head-row { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 10px; margin-bottom: var(--space-2); }
  .list-head-row h2 { margin: 0; }
  .list-filters { display: flex; gap: 12px; flex-wrap: wrap; }
  .list-filter { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--color-text-dim); margin: 0; }
  .list-filter[hidden] { display: none; }
  .list-filter select { font-size: 16px; padding: 4px 8px; min-height: 34px; }
  /* The apartment picker only matters for דמי ועד (per-apartment, filed into the
     collection matrix); no other income category has an apartment. Toggled by the
     .dues-mode class rather than a CSS :has() on [value=...] - category is a
     text+datalist input, and typing never updates the value ATTRIBUTE, so an
     attribute selector would simply never match. */
  .add-form[data-add="vaadincome"]:not(.dues-mode) .ff-apartment { display: none; }
  /* Owner (בעל דירה) fields only matter for a rented-out apartment - hidden until
     "בשכירות?" is set to כן. Pure CSS via :has so it tracks the select reactively:
     the add-form default (לא), a user change, and edit-populate all just work. */
  .add-form:not(:has(select[data-f="rented"] option[value="כן"]:checked)) .ff-ownerName,
  .add-form:not(:has(select[data-f="rented"] option[value="כן"]:checked)) .ff-ownerPhone { display: none; }
  /* Per-resident message language only matters for automatic sending - the
     manual tab already has its own single message-language picker. */
  [data-mode="manual"] .col-msg-lang { display: none; }
  .wa-resident-lang-select { font-size: 12.5px; padding: 2px 4px; }
  .wa-design-list { width: 100%; border-collapse: collapse; font-size: 13.5px; }
  .wa-design-list th { position: sticky; top: 0; background: var(--color-muted); text-align: start; padding: 8px 10px; font-weight: 600; }
  .wa-design-list td { padding: 7px 10px; border-top: 1px solid var(--color-border); }
  /* The wide resident table scrolls sideways inside its own box instead of
     dragging the whole page wide. overflow-x, never hidden - nothing is clipped. */
  .wa-design-list-wrap { overflow-x: auto; }

  /* #277: faults and resident requests share the one tab. In "הכל" mode both
     tables are stacked, and a rule between them is what keeps the second one
     from reading as more rows of the first. Only when the first is actually
     showing - on its own, the requests table needs no separator above it. */
  #ticketsFaultsWrap:not([hidden]) + #ticketsRequestsWrap {
    margin-top: var(--space-4); padding-top: var(--space-3);
    border-top: 1px solid rgba(148, 163, 184, .28);
  }
  /* Message composer + live chat preview */
  .wa-compose-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); flex-wrap: wrap; margin-bottom: var(--space-2); }
  .wa-compose-head h2 { margin: 0; }
  /* Live status cell for an already-active automatic reminder - shown at the
     OTHER end of the header row from the h2 (space-between does the RTL/LTR
     placement automatically), so the committee never has to open the "אוטומטי"
     tab just to see/cancel a schedule that's already running. */
  .wa-auto-status-cell { display: flex; align-items: center; gap: var(--space-2); }
  /* An author display value beats the UA [hidden]{display:none} regardless of
     specificity - the same trap this file has already hit (and fixed) on
     .link-thumb, .view, .wa-account-bar, #reportDateFilters, etc. Missed here
     when the cell was added, so it stayed visibly flex on every load
     regardless of the hidden attribute updateAutoStatusCell() sets correctly. */
  .wa-auto-status-cell[hidden] { display: none; }
  .wa-auto-status-cell .btn-ghost { padding: 4px 10px; font-size: 12.5px; min-height: 28px; }
  .wa-compose-grid { display: grid; grid-template-columns: 1.15fr 1fr; gap: var(--space-3); align-items: start; }
  @media (max-width: 720px) { .wa-compose-grid { grid-template-columns: 1fr; } }
  .wa-compose-form { min-width: 0; }
  .wa-phone-mock {
    background: var(--color-card); border: 1px solid var(--color-border); border-radius: calc(var(--radius) + 4px);
    overflow: hidden; box-shadow: 0 16px 34px -22px rgba(0,0,0,0.6); position: sticky; top: var(--space-2);
  }
  .wa-phone-header {
    background: linear-gradient(120deg, #1f8f57, #1a7549); color: #fff; padding: 12px 14px;
    display: flex; align-items: center; gap: 10px;
  }
  .wa-phone-avatar {
    width: 34px; height: 34px; border-radius: 50%; background: rgba(255,255,255,0.22);
    display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 14px; flex-shrink: 0;
  }
  .wa-phone-name { font-size: 14px; font-weight: 700; }
  .wa-phone-sub { font-size: 11px; opacity: 0.85; }
  .wa-phone-body {
    background: repeating-linear-gradient(135deg, rgba(37,211,102,0.05) 0 2px, transparent 2px 26px), var(--color-bg, var(--color-muted));
    padding: 18px 14px; min-height: 220px; display: flex; flex-direction: column; justify-content: flex-end;
  }
  .wa-chat-bubble {
    background: #DCF8C6; color: #10240f; align-self: flex-end; max-width: 86%;
    padding: 9px 12px; border-radius: 12px 12px 2px 12px; font-size: 13.5px; line-height: 1.5;
    white-space: pre-wrap; word-break: break-word; box-shadow: 0 3px 8px -4px rgba(0,0,0,0.4);
  }
  [dir="rtl"] .wa-chat-bubble { border-radius: 12px 12px 12px 2px; }
  .wa-chat-bubble.placeholder { color: #5c6b57; font-style: italic; }
  .wa-chat-time { display: block; text-align: end; font-size: 10px; color: #5c6b57; margin-top: 4px; }

  /* Kanban board (project tasks) */
  .kanban-card.dragging { opacity: 0.4; }

  .gantt-bar.st-active { background: rgba(5,150,105,0.35); }
  .gantt-bar.st-planning { background: rgba(59,130,246,0.35); }
  .gantt-bar.st-paused { background: rgba(245,158,11,0.35); }
  .gantt-bar.st-completed { background: var(--color-muted); }

  .overdue-cell { color: #F87171; font-weight: 600; }
  [data-theme="light"] .overdue-cell { color: #DC2626; }
  .subtask-row.done span { text-decoration: line-through; color: var(--color-text-dim); }
  .group-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
  .group-chip { display: inline-flex; align-items: center; gap: 8px; background: var(--color-muted); border: 1px solid var(--color-border); border-radius: 999px; padding: 6px 12px; font-size: 14px; }
  .group-chip button { background: transparent; color: var(--color-destructive); border: none; min-height: auto; padding: 0 2px; font-size: 16px; line-height: 1; cursor: pointer; }
  .group-chips .empty-note { color: var(--color-text-dim); font-size: 13px; }
  /* Daily agenda timeline */

  /* Day-filter notice */

  /* Trip date bar & day squares */
  button.btn-small { min-height: 30px; padding: 3px 10px; font-size: 12px; }
  button.btn-small svg { width: 13px; height: 13px; }
  .day-strip.dragging { cursor: grabbing; scroll-snap-type: none; user-select: none; }
  .day-sq.active { background: rgba(59,130,246,0.18); border-color: var(--color-secondary); outline: 2px solid var(--color-secondary); outline-offset: -2px; }
  .day-sq .ddot { width: 6px; height: 6px; border-radius: 50%; background: var(--color-accent); visibility: hidden; }
  .day-sq.has-items .ddot { visibility: visible; }

  /* Project switcher strip (Projects tool) */
  .proj-strip.dragging { cursor: grabbing; user-select: none; }
  .proj-chip.active { background: rgba(59,130,246,0.18); border-color: var(--color-secondary); outline: 2px solid var(--color-secondary); outline-offset: -2px; }

  /* Mind map (Projects tool, sub-projects advanced mode) - rendered by the
     Mind Elixir library (read-only: no built-in drag/edit/toolbar - creating
     and editing links stays exclusively in our own right-click menu below). */
  /* Mind Elixir only fills the root node's background by default - every
     other node gets just a colored border, which against the map's own
     background reads as an unanchored outline "floating" near its
     connector line instead of a solid box. Force every node to a solid
     filled pill, so the visual hierarchy is "root = accent color, everyone
     else = same solid muted fill" instead of "root = filled, rest = void". */

  /* Address navigation links (Google Maps / Waze) */
  .nav-links { display: inline-flex; gap: 4px; margin-inline-start: 6px; vertical-align: middle; }
  .nav-link { display: inline-block; padding: 1px 8px; border-radius: 999px; font-size: 11px; text-decoration: none; border: 1px solid var(--color-border); }
  .nl-maps { color: #34A853; background: rgba(52,168,83,0.12); }
  .nl-waze { color: #33CCFF; background: rgba(51,204,255,0.12); }
  [data-theme="light"] .nl-maps { color: #1e7e34; }
  [data-theme="light"] .nl-waze { color: #0b7285; }
  .tel-link { color: var(--color-secondary); text-decoration: none; display: inline-flex; align-items: center; gap: 4px; }
  .tel-link:hover { text-decoration: underline; }
  .tel-link::before { content: '📞'; font-size: 12px; }

  /* Payment matrix */
  .matrix-head { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px; }
  .year-nav { display: flex; gap: 8px; }
  .matrix-table { border-collapse: collapse; width: 100%; font-size: 14px; }
  .matrix-table th, .matrix-table td { border: 1px solid var(--color-border); padding: 8px 6px; text-align: center; white-space: nowrap; }
  .matrix-table th { color: var(--color-text-dim); font-weight: 500; font-size: 13px; position: sticky; top: 0; background: var(--color-card); }
  .sticky-col { position: sticky; inset-inline-start: 0; background: var(--color-card); text-align: start !important; z-index: 1; min-width: 120px; }
  .apt-link { cursor: pointer; color: var(--color-secondary); font-weight: 500; }
  .apt-link:hover { text-decoration: underline; }
  .pay-cell { cursor: pointer; font-weight: 700; transition: background 150ms ease-out; }
  .pay-cell.paid { background: rgba(5,150,105,0.22); color: var(--color-success); }
  .pay-cell.unpaid { background: rgba(220,38,38,0.14); color: #F87171; }
  [data-theme="light"] .pay-cell.unpaid { color: #DC2626; }
  /* A future month that hasn't come due yet - blue, not red (nothing is overdue yet). */
  .pay-cell.future { background: rgba(59,130,246,0.16); color: #60A5FA; }
  [data-theme="light"] .pay-cell.future { color: var(--color-secondary); }
  .pay-cell:hover { filter: brightness(1.25); }
  .cat-row-label { display: flex; align-items: center; justify-content: space-between; gap: 6px; }
  /* A resident marked "עזב/ה" (moved out) - kept in the list (never deleted),
     just visually de-emphasized so it's obvious at a glance they're not a
     current resident, without hiding them entirely. */
  tr.resident-inactive, .matrix-card.resident-inactive { opacity: 0.55; }

  /* Card view (Settings → עוד): an alternative to the wide 12-month table for
     vaad-matrix and vaadfixed-matrix, one row/category per collapsible card -
     avoids the horizontal-scroll table on mobile. .matrix-card-month reuses
     .pay-cell + the same paid/unpaid/future classes so it picks up the exact
     same colors, and the same data-apt/data-month or data-cat/data-month
     attributes so the EXISTING delegated click handlers (mark paid, open the
     amount dialog) work unchanged - only the visual shape changes. */
  .matrix-cards { display: flex; flex-direction: column; gap: var(--space-2); }
  .matrix-card { background: var(--color-card); border: 1px solid var(--color-border); border-radius: var(--radius); overflow: hidden; }
  .matrix-card-head { display: flex; align-items: center; gap: 10px; padding: var(--space-3); }
  .matrix-card-chevron {
    background: transparent; border: none; color: var(--color-text-dim); cursor: pointer;
    font-size: 18px; line-height: 1; padding: 10px; margin: -10px; border-radius: 50%;
    display: flex; align-items: center; justify-content: center; flex-shrink: 0;
    transition: transform 200ms ease-out;
  }
  .matrix-card.expanded .matrix-card-chevron { transform: rotate(180deg); }
  .matrix-card-chevron:hover { background: rgba(255,255,255,0.06); }
  .matrix-card-title { font-weight: 600; }
  .matrix-card-summary { display: flex; align-items: center; gap: 10px; padding: 0 var(--space-3) var(--space-3); font-size: 13px; color: var(--color-text-dim); }
  .matrix-card-summary .progress-bar { flex: 1; height: 6px; border-radius: 3px; background: rgba(255,255,255,0.08); overflow: hidden; }
  .matrix-card-summary .progress-fill { height: 100%; background: var(--color-success); border-radius: 3px; }
  .matrix-card-body { border-top: 1px solid var(--color-border); padding: var(--space-3); }
  .matrix-card-months { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }
  @media (max-width: 480px) { .matrix-card-months { grid-template-columns: repeat(3, 1fr); } }
  .matrix-card-month {
    display: flex; flex-direction: column; align-items: center; gap: 4px;
    padding: 8px 4px; border-radius: calc(var(--radius) - 4px); min-height: 44px; justify-content: center;
  }
  .matrix-card-month .mcm-label { font-size: 12px; font-weight: 500; opacity: .85; }
  .matrix-card-month .mcm-value { font-size: 13px; }
  .matrix-card-body .btn-ghost { margin-top: var(--space-2); width: 100%; }

  /* Profit & loss table */
  .pnl-table { width: 100%; border-collapse: collapse; font-size: 15px; }
  .pnl-table td { padding: 10px 12px; border-bottom: 1px solid var(--color-border); }
  .pnl-table td.num { text-align: end; font-variant-numeric: tabular-nums; font-weight: 500; }
  .pnl-table tr.pnl-sub td { color: var(--color-text-dim); }
  .pnl-table tr.pnl-total td { font-size: 17px; font-weight: 700; border-top: 2px solid var(--color-border); border-bottom: none; }

  /* File location */
  .path-row { display: flex; gap: 8px; margin-top: 4px; }
  .path-row input, .path-row select { flex: 1; }
  .fs-path { font-family: monospace; font-size: 12px; word-break: break-all; color: var(--color-fg); margin-bottom: 4px; }
  .fs-meta { font-size: 13px; color: var(--color-text-dim); }
  .fs-chosen { color: var(--color-success); }
  .fs-default { color: var(--color-text-dim); }
  #aptInfoBody ul { margin: 10px 0; padding-inline-start: 18px; line-height: 1.8; }
  #aptInfoBody .owner-line { color: var(--color-secondary); }
  /* Ticket status / priority badges */
  .st-open { background: rgba(220,38,38,0.16); color: #F87171; }
  .st-progress { background: rgba(245,158,11,0.18); color: #F59E0B; }
  .st-done { background: rgba(5,150,105,0.18); color: var(--color-success); }
  .st-crit { background: rgba(220,38,38,0.22); color: #F87171; }
  .st-urgent { background: rgba(245,158,11,0.18); color: #F59E0B; }
  /* BUG-008: was a neutral gray, same as an unrecognized/fallback status -
     "רגילה" (normal urgency) already had a badge+color, just not one that
     visually read as "the calm end of a 3-tier scale" next to urgent/critical.
     Green completes the traffic-light convention those two already use. */
  .st-normal { background: rgba(5,150,105,0.16); color: var(--color-accent); }
  .st-planning { background: rgba(59,130,246,0.16); color: #60A5FA; }
  .st-active { background: rgba(5,150,105,0.18); color: var(--color-success); }
  .st-paused { background: rgba(245,158,11,0.18); color: #F59E0B; }
  .st-completed { background: var(--color-muted); color: var(--color-text-dim); }
  [data-theme="light"] .st-open, [data-theme="light"] .st-crit { color: #DC2626; }

  /* Work-hours clock panel */
  button:disabled { opacity: 0.45; cursor: not-allowed; }
  @keyframes livePulse { 0% { box-shadow: 0 0 0 0 rgba(52,211,153,0.5); } 70% { box-shadow: 0 0 0 8px rgba(52,211,153,0); } 100% { box-shadow: 0 0 0 0 rgba(52,211,153,0); } }
  @media (prefers-reduced-motion: reduce) {}

  /* Table */
  .table-wrap { overflow-x: auto; }
  table { width: 100%; border-collapse: collapse; font-size: 14px; }
  th, td { text-align: start; padding: 10px 12px; border-bottom: 1px solid var(--color-border); white-space: nowrap; }
  th { color: var(--color-text-dim); font-weight: 500; font-size: 13px; }
  td.num { font-variant-numeric: tabular-nums; font-weight: 500; }
  tr:hover td { background: rgba(255,255,255,0.03); }
  .cat-badge { display: inline-flex; align-items: center; gap: 6px; padding: 3px 10px; border-radius: 999px; font-size: 13px; background: var(--color-muted); }
  .actions-cell { display: flex; gap: 8px; }
  /* #98/#100: derived installment rows under a split expense/income parent. */
  .installment-child td { color: var(--color-text-dim); font-size: .92em; }
  .installment-child td:first-child { padding-inline-start: 1.8rem; }

  /* Filters */
  .filters { display: flex; gap: var(--space-2); flex-wrap: wrap; margin-bottom: var(--space-2); align-items: end; }
  .filters label { min-width: 120px; }

  .empty { text-align: center; color: var(--color-text-dim); padding: var(--space-5); }

  /* Account details */
  .details-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--space-2); }
  .details-footer { margin-top: var(--space-2); display: flex; align-items: center; gap: var(--space-2); }
  .card .id-line { font-size: 12px; color: var(--color-text-dim); direction: ltr; text-align: end; }

  /* Toast — a manual popover (not a plain fixed <div>) so it renders in the
     top layer and stays visible above open <dialog>s, which otherwise always
     paint above regular DOM content regardless of z-index. */
  #toast {
    /* Forum #292: on a real phone, a longer message (multi-part import
       summaries, warnings) grew past the viewport edge with nothing to stop
       it - real text sitting off-screen, not merely wrapped oddly. The
       original centering used `right: 50%` - #toast is a manual popover
       (top-layer, for stacking above open <dialog>s), and its browser-level
       overflow-avoidance repositioning for popovers measurably fought that
       specific property, computing an inset that still overflowed even on a
       WIDE desktop viewport where nothing should have needed correcting.
       `left: 50%` does not trigger the same override (confirmed by direct
       measurement) - centering from the other edge, with an explicit
       max-width so there's always a hard cap regardless, is what actually
       holds up on every screen size.
       audit fix: with only `left` set (`right: auto`), the browser's
       shrink-to-fit width algorithm for the default `width: fit-content`
       computes its available width from the `left` offset to the containing
       block's edge - on a 375px viewport that's ~50vw (~187px), HALF the
       intended max-width, before max-width is even applied as a cap. A long
       toast wrapped to nearly twice as many lines as it should, and even an
       ordinary one-line short toast got force-wrapped to two. `width:
       max-content` sizes from the text's own intrinsic width instead of that
       halved available-width calculation, so max-width finally acts as the
       real cap it's meant to be - confirmed by direct measurement at both
       375px and 1280px, short and long message, no overflow, no forced wrap. */
    position: fixed; bottom: max(24px, calc(env(safe-area-inset-bottom) + 12px)); left: 50%; right: auto; transform: translateX(-50%);
    /* QA (2026-08-02): inset-inline-start:auto used to sit here too, meant to
       reset the [popover] UA default `inset:0` alongside inset-block-start -
       but inset-inline-start maps to the PHYSICAL `left` in LTR documents and,
       being declared AFTER left:50% above, won and reset it straight back to
       auto - silently un-centering every toast in every LTR language (es/fr/
       en/ru), pinning it ~240px off the left edge with only the tail of the
       message visible. RTL was never affected (inset-inline-start maps to
       `right` there, which was already auto). left:50%/right:auto already
       reset the UA's own left:0/right:0 explicitly, so dropping this line
       loses nothing. */
    margin: 0; border: none; inset-block-start: auto;
    background: var(--color-accent); color: #fff; padding: 12px 24px;
    border-radius: 8px; font-weight: 500; opacity: 0; pointer-events: none;
    transition: opacity 250ms ease-out; z-index: 100;
    width: max-content; max-width: min(calc(100vw - 32px), 480px); box-sizing: border-box;
    white-space: pre-line; text-align: center; line-height: 1.5;
  }
  #toast.show { opacity: 1; }
  #toast.error { background: var(--color-destructive); }

  /* Feedback rows shown under an add form (residents, vaadfixed, vaadincome -
     see RECENT_ADD_TOOLS) after a successful save - each of those lists lives
     in a separate sub-tab, so without this the only sign anything happened is
     the toast that vanishes in a couple of seconds. FIFO, max 2 rows (see
     recentAddPush). */
  .resident-recent-adds { display: flex; flex-direction: column; gap: 8px; margin-top: var(--space-2); }
  .resident-recent-row {
    display: flex; align-items: center; gap: 10px; padding: 8px 12px; border-radius: 8px;
    background: var(--color-bg-alt, rgba(52,211,153,.08)); border: 1px solid var(--color-success, #16a34a);
    font-size: 13px; animation: residentRecentRowIn 200ms ease-out;
  }
  .resident-recent-check { flex: 0 0 auto; color: var(--color-success, #16a34a); font-weight: 700; }
  .resident-recent-info { flex: 1; font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .resident-recent-hint { flex: 0 0 auto; color: var(--color-text-dim); font-size: 12px; }
  @keyframes residentRecentRowIn { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: translateY(0); } }

  /* Edit dialog */
  dialog {
    background: var(--color-card); color: var(--color-fg);
    border: 1px solid var(--color-border); border-radius: var(--radius);
    padding: var(--space-4); max-width: 420px; width: 90%;
    margin: auto;
    /* Prevents an over-scroll inside a tall dialog (e.g. the cheque-entry form)
       from chaining into the page body, where it can trigger Chrome-for-Android's
       native pull-to-refresh and reload the page mid-entry, discarding unsaved
       field values. */
    overscroll-behavior-y: contain;
    /* Open/close animation (2026-08-01): every dialog used to pop instantly -
       no transition existed anywhere on the base `dialog` rule. @starting-style
       + transition-behavior:allow-discrete animates BOTH the show (native
       [open] toggling display:none->block) and the close (showModal()/close()
       removing it from the top layer) with pure CSS, no JS changes needed -
       an unsupported browser (pre-2024 Safari/Firefox) just silently ignores
       the unknown at-rule and keeps today's instant behavior, so this is a
       safe progressive enhancement. Already covered by the file's existing
       blanket prefers-reduced-motion override (`* { transition: none }`). */
    transition: opacity 0.18s ease, transform 0.18s ease, overlay 0.18s allow-discrete, display 0.18s allow-discrete;
    opacity: 0;
    transform: scale(0.96) translateY(6px);
  }
  /* QA (2026-08-03): was `transform: scale(1) translateY(0)` - visually a
     total no-op once settled, but ANY non-`none` transform on an element
     (even an identity one) makes it the containing block for `position:fixed`
     descendants instead of the true viewport. Every dialog[open] carried this
     silently - the guided tour tip (position:fixed, math based on
     window.visualViewport) docks itself INSIDE #settingsDialog for its
     building/systems steps (deliberately, to reuse the real Settings form),
     and got positioned relative to the DIALOG's box instead: measured live,
     positionTourTipDocked() computed top assuming a 900px-tall viewport, but
     the actual containing block (the dialog) was only 765px tall starting at
     y=67.5 - pushing the tip's bottom edge, and its "הבא"/Next button with it,
     ~60px past the real bottom of the screen. `transform: none` is the exact
     same visual rest-state (scale(1)/translateY(0) already looked identical)
     and does not establish a containing block - the entrance transition
     below still animates smoothly since CSS interpolates to/from `none` as
     the identity transform. */
  dialog[open] { opacity: 1; transform: none; }
  @starting-style { dialog[open] { opacity: 0; transform: scale(0.96) translateY(6px); } }
  /* The two auto-popping reminders open NON-modally (show(), not showModal) so
     their backdrop never sits over the tabs and swallows clicks. A non-modal
     dialog drops into page flow, so pin these fixed-centered like a modal would
     be — visible + dismissible, but never blocking interaction behind them. */
  #noBuildingInfoDialog[open], #backupReminderDialog[open] { position: fixed; inset: 0; margin: auto; z-index: 50; }
  dialog::backdrop {
    background: rgba(0,0,0,0.55);
    transition: opacity 0.18s ease, overlay 0.18s allow-discrete, display 0.18s allow-discrete;
    opacity: 0;
  }
  dialog[open]::backdrop { opacity: 1; }
  @starting-style { dialog[open]::backdrop { opacity: 0; } }
  dialog h3 { margin-bottom: var(--space-3); }
  .settings-header-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: var(--space-3); }
  .settings-header-row h3 { margin-bottom: 0; }
  .settings-header-actions { display: flex; flex-direction: column; gap: 6px; align-items: stretch; }
  #settingsDialog .settings-header-actions, #helpDialog .settings-header-actions { flex-direction: row; align-items: center; flex-wrap: wrap; }
  /* Theme/language/relaunch-tour buttons in the Settings and Help ("info")
     dialog headers already had a border (.icon-btn/.btn-ghost's own neutral
     one), but it's nearly invisible against the dark card background - reads
     as "no border" in practice. Brand-blue makes it an actual visible frame,
     matching .btn-close/.vaad-quick-btn's own outline treatment right next
     to it in the same row. */
  #settingsDialog .settings-header-actions .icon-btn,
  #helpDialog .settings-header-actions .icon-btn,
  #settingsDialog .settings-header-actions .btn-ghost,
  #helpDialog .settings-header-actions .btn-ghost { border-color: var(--color-primary); }
  #versionInfo { text-align: center; }
  /* Fixed height (not shrink-to-fit) so switching between settings tabs never
     visibly resizes/jumps the dialog - same reasoning and pattern as
     #helpDialog above. Only the currently-visible .settings-section (the
     rest are [hidden]) fills the remaining flex space and scrolls
     internally if its own content is taller than that. */
  #settingsDialog { max-width: 820px; height: 85vh; display: flex; flex-direction: column; overflow: hidden; }
  /* #83: the Settings and Help windows float (centered card) on desktop, but on a
     phone a small floating card wastes the screen and is fiddly - make them a
     full-screen sheet there instead (edge to edge, no rounded corners/margins). */
  @media (max-width: 600px) {
    #settingsDialog, #helpDialog {
      max-width: 100%; width: 100%; height: 100dvh; max-height: 100dvh;
      border: none; border-radius: 0; margin: 0;
    }
  }
  /* Without this, the unconditional display:flex above overrides the
     browser's own dialog:not([open]) { display: none } default, so the
     dialog renders inline in the page flow (pushed below the dashboard
     content) at all times instead of staying hidden until showModal() -
     same fix #helpDialog already needed for the same reason. */
  #settingsDialog:not([open]) { display: none; }
  #settingsDialog > *:not(.settings-section) { flex: 0 0 auto; }
  .settings-section { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior-y: contain; margin-bottom: var(--space-4); padding-inline-end: 6px; }
  .settings-section[hidden] { display: none; }
  /* #waSettingsTabs (מידע וחיבור/אנשי הוועד/קישורים לתשלום/תקנון/קבוצת הבניין)
     is a plain child of .settings-section, THE scroll container above - so it
     scrolled away with the rest of the WhatsApp panel's content instead of
     staying reachable. Pinned to the top of that same scroll container; the
     opaque background is required so scrolled-past content doesn't show
     through the now-fixed row. */
  /* #200: reported as "the bottom menu is semi-transparent, hard to read while
     scrolling" - iOS Safari has a known bug where a `position:sticky` element
     can render without its background during scroll unless it's forced onto
     its own GPU compositing layer. translateZ(0) + backface-visibility:hidden
     is the standard fix; background-color is repeated (not just `background`)
     as a second, shorthand-independent guarantee of full opacity. */
  #waSettingsTabs {
    position: sticky; top: 0; z-index: 2;
    background: var(--color-card); background-color: var(--color-card);
    transform: translateZ(0); -webkit-backface-visibility: hidden; backface-visibility: hidden;
  }
  /* Same light-mode "which tab row is which" confusion already fixed once for
     #vaad-tabs vs. the tool's own top nav - the primary Settings-dialog tabs
     (#settingsTabs) and this secondary WhatsApp sub-tab row read as one
     continuous row in light mode with no visual break between them.
     #200: this MUST be a fully opaque color, not the translucent rgba() a
     plain (non-sticky) tint would use - #waSettingsTabs is `position:sticky`
     (see above), so scrolled-past content sits directly underneath it and
     any alpha here reads as "the menu turned semi-transparent while
     scrolling". rgb(243,248,254) is rgba(59,130,246,0.06) pre-blended onto
     white (the light theme's --color-card) - same visible tint, zero alpha. */
  [data-theme="light"] #waSettingsTabs {
    background: rgb(243, 248, 254); background-color: rgb(243, 248, 254);
    margin-inline: calc(-1 * var(--space-3));
    padding-inline: var(--space-3);
    border-radius: var(--radius) var(--radius) 0 0;
  }
  /* QA (2026-08-02): inherits .tabs's flex-wrap:wrap, which stranded the last
     1-2 tabs alone on an orphan second row in es/fr (their translated tab
     labels run wider than #vaad-tabs's own already-fixed labels, e.g.
     "Configuración de la herramienta" / "Systèmes du bâtiment") - reproduced
     at full 1440px desktop width since the DIALOG itself caps this strip's
     width well below the viewport. #vaad-tabs's fix (an auto-detected
     hamburger+drawer) needs a fixed-position off-canvas panel and backdrop
     this modal dialog has none of - a simple horizontal scroll (a well-
     understood pattern for an in-dialog tab strip) fits here instead: always
     one row, scrolls when it doesn't fit, no orphan row. */
  .settings-tabs { margin-bottom: 16px; flex-wrap: nowrap; overflow-x: auto; scrollbar-width: thin; }
  .settings-tabs .tab { flex: 0 0 auto; }
  .settings-tabs .tab { padding: 8px 12px; font-size: 14px; min-height: 40px; }
  .settings-section h4 { font-size: 15px; font-weight: 500; color: var(--color-text-dim); margin-bottom: var(--space-2); padding-bottom: 6px; border-bottom: 1px solid var(--color-border); }
  .file-status { background: var(--color-muted); border: 1px solid var(--color-border); border-radius: 8px; padding: var(--space-2); font-size: 14px; margin-bottom: var(--space-2); }
  .file-status strong { font-variant-numeric: tabular-nums; }
  .file-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }
  .file-actions button { min-height: 40px; }
  .drive-files-list { display: flex; flex-direction: column; gap: 6px; }
  .drive-file-row {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    background: var(--color-muted); border: 1px solid var(--color-border); border-radius: 8px; padding: 8px 10px;
  }
  .drive-file-row .drive-file-meta { display: flex; flex-direction: column; min-width: 0; }
  .drive-file-row .drive-file-name { font-size: 13.5px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .drive-file-row .drive-file-time { font-size: 11.5px; color: var(--color-text-dim); }
  .drive-file-row button { flex-shrink: 0; min-height: 32px; padding: 4px 10px; font-size: 12.5px; }
  .drive-files-empty { font-size: 13px; color: var(--color-text-dim); }

  /* Work-hours calendar */
  .cal-cell.mini { min-height: 16px; width: 16px; padding: 0; border-radius: 4px; }
  /* Weekday-aligned calendar table */
  /* Day-type radio bar */
  .cal-swatch.d-rest { background: #8B5CF6; }
  .cal-cell.d-rest { background: rgba(139,92,246,0.30); }
  .checkbox-row { flex-direction: row !important; align-items: center; gap: 8px; font-size: 14px; color: var(--color-fg); cursor: pointer; min-height: 28px; }
  /* #131e: bulk-select checkbox column, first cell in the vendor-requests
     table (before the date column) - kept narrow so it doesn't compete with
     the real data columns for width. */
  .col-select { width: 32px; text-align: center; }
  .checkbox-row input[type="checkbox"] { width: 18px; height: 18px; min-height: auto; accent-color: var(--color-accent); cursor: pointer; }
  .detail-block.inactive { opacity: 0.55; }
  dialog form { display: flex; flex-direction: column; gap: var(--space-2); }
  /* #152: on a wide screen, checkDialog's single narrow column (7 stacked
     fields + the OCR panel) ran taller than the viewport and forced an
     internal scrollbar - a 2-column field grid on desktop/tablet keeps the
     same fields but roughly halves the height, closer to a square dialog.
     The OCR panel and the save/cancel row still span both columns. */
  @media (min-width: 700px) {
    #checkDialog { max-width: 640px; }
    #checkDialog form { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2) var(--space-3); align-items: start; }
    #checkDialog form > h3, #checkDialog form > div { grid-column: 1 / -1; }
  }
  .dialog-actions { display: flex; gap: var(--space-2); justify-content: flex-start; margin-top: var(--space-2); }
  /* The #expense-popup/#income-popup/#ops-popup add-dialogs (vaadfixed/
     vaadincome/tickets/pros/buildingsys) all get the same tighter padding
     than a generic dialog. */
  #vaadfixedAddDialog, #vaadincomeAddDialog, #ticketsAddDialog, #prosAddDialog, #buildingsysAddDialog { padding: var(--space-3); }
  #vaadfixedAddDialog h2, #vaadincomeAddDialog h2, #ticketsAddDialog h2, #prosAddDialog h2, #buildingsysAddDialog h2 { margin-bottom: var(--space-2); }
  /* addSectionHTML() (vaadfixed/vaadincome only - the RECENT_ADD_TOOLS pair
     that keeps a "recent adds" list; tickets/pros/buildingsys build their
     dialog markup directly, no .panel involved) wraps its form in a
     bordered/padded .panel, which reads fine inline in a tab but doubles up
     with the dialog's own border+padding here - two nested boxes and two
     paddings stacked for no reason. Strip the inner one; the dialog chrome
     already does that job. */
  #vaadfixedAddDialog .panel, #vaadincomeAddDialog .panel { padding: 0; border: none; background: transparent; }
  .btn-ghost { background: transparent; color: var(--color-text-dim); border: 1px solid var(--color-border); }
  /* #178: "close" (סגור) buttons shared plain .btn-ghost styling with wizard
     "back" (חזרה) buttons - visually identical, easy to misclick one for the
     other. Layered on top of .btn-ghost (keeps its sizing). Uses the site's
     brand blue (border/text only, background stays transparent) rather than
     .btn-primary's solid blue fill - outline vs. fill is what keeps "close"
     from reading as a primary action, not a different hue. */
  .btn-close { background: transparent; color: var(--color-primary); border: 1px solid var(--color-primary); }
  .btn-close:hover { background: rgba(30,64,175,0.12); }

  /* Alon brand logo, before the tool name — theme-matched logo image */
  .brand-logo { display: inline-flex; align-items: center; text-decoration: none; }
  .brand-logo .logo { height: 40px; width: auto; }
  /* Mobile (<=600px): the logo isn't hidden anymore - it's centered over the header,
     see the .brand-logo absolute-position rule in the mobile media query above. */
  /* Vaad tabs hamburger — inverse of .brand-logo above: hidden on desktop (the
     9-tab bar has room to wrap there), shown only <=600px where it opens the
     off-canvas tabs drawer (see the #vaad-tabs mobile rules near .tabs/.tab). */
  #vaadTabsToggle { display: none; }
  @media (max-width: 600px) { #vaadTabsToggle { display: flex; } }

  /* #283: reuses the same red pill look as .type-out (styles.css ~559-562)
     rather than inventing a second one. Sits beside the title on desktop,
     where the header row (auto 1fr) just widens for it - see .beta-strip
     below for the mobile equivalent, which this is hidden in favour of. */
  .beta-tag {
    display: inline-flex; align-items: center; flex: 0 0 auto;
    padding: 3px 10px; border-radius: 999px; font-size: 13px; font-weight: 600;
    white-space: nowrap; background: rgba(220,38,38,0.16); color: #F87171;
  }
  [data-theme="light"] .beta-tag { color: #DC2626; }
  /* Full-width strip under the header, mobile only - the inline tag above is
     hidden there instead. #279 (fixed in v1.27.287) already spent every pixel
     of slack in that header row - clamp() title down to 13px, logo down to
     32px - and it still ellipsizes by design at 320px, so adding an inline
     element there would immediately reopen it. */
  .beta-strip { display: none; }
  @media (max-width: 600px) {
    .beta-tag { display: none; }
    .beta-strip {
      display: block; text-align: center; padding: 4px 8px;
      font-size: 12px; font-weight: 600;
      background: rgba(220,38,38,0.16); color: #F87171;
      margin: 0 0 var(--space-3);
    }
    [data-theme="light"] .beta-strip { color: #DC2626; }
  }
  /* Show the logo that matches the active theme (default = dark) */
  .logo-light { display: none; }
  .logo-dark { display: block; }
  [data-theme="light"] .logo-light { display: block; }
  [data-theme="light"] .logo-dark { display: none; }

  /* Print-only elements (hidden on screen) */
  .print-only { display: none; }
  #printHeader { align-items: center; gap: 16px; margin-bottom: 20px; }
  #printHeader img { width: 64px; height: 64px; border-radius: 10px; }
  #printHeader .ph-title { font-size: 22px; font-weight: 700; }
  #printHeader .ph-date { font-size: 14px; color: #555; }

  /* ---- Responsive: tablets & phones (iPhone 11+, Android) ---- */
  @media (max-width: 768px) {
    header h1, #appTitle { font-size: 20px; }
    .cards { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }
    /* #196: auto-fit alone just fits however many 140px columns the width allows -
       at tablet widths that happens to be 3, wrapping a 4-card group as 3+1. Same
       fix as the 480px block below, at the width where it was actually reported. */
    .cards:has(> .card:nth-child(4)) { grid-template-columns: repeat(2, 1fr); }
    .panel { padding: var(--space-2); }
    dialog { padding: var(--space-3); }
    .details-grid { grid-template-columns: 1fr 1fr; }
  }
  @media (max-width: 480px) {
    header { gap: 8px; }
    /* #279: reported as "the logo hides the word בית". Measured: the logo does
       not overlap the title at all - the title is being CLIPPED by its own
       ellipsis, and the cut lands right where the logo starts, which is what
       makes it look like the logo is sitting on top of it. "ניהול וועד בית"
       needs 107px at 17px and the title column gave it 96px at 375 and 103px
       at 390 - so it clipped on every common iPhone except the Plus/Max.
       The column can't simply be widened: the logo is centred on the page by
       giving both side columns an equal minmax(0,1fr) share (see the header
       grid above, #272), so the title column is capped at whatever the icon
       cluster's side gets. The title has to fit that width instead.
       clamp() rather than one smaller fixed size: it stays 17px wherever there
       is room and shrinks smoothly as the viewport narrows, so this doesn't
       have to be re-tuned for a longer tool name or a different language. */
    #appTitle { font-size: clamp(13px, 3.6vw, 17px); }
    /* Both buy width for the title, on both sides of the centred logo. 32px is
       still a clearly readable brand mark; the hamburger's 42px tap target is
       deliberately left alone. */
    .brand-logo .logo { height: 32px; }
    .mobile-title-group { gap: 4px; }
    .brand { gap: 8px; }
    .icon-btn { min-width: 42px; min-height: 42px; }
    /* One row, however many cards there are. repeat(2,1fr) was wrong both ways:
       it broke the 3-card summaries into 2+1, which reads as a missing fourth
       card rather than a layout, and it stretched a lone card across half the
       screen. Every .cards group used to hold 3 or 1 - never 2, never 4 - so
       letting the columns follow the content is what the content wanted. That
       assumption broke once the dues-matrix summary grew a 4th card (#67):
       cramming 4 into one row squeezed each into an unreadably narrow sliver,
       so a 4+ card group now explicitly wraps into 2 columns instead. */
    .cards { grid-auto-flow: column; grid-auto-columns: 1fr; grid-template-columns: none; gap: 8px; }
    .cards:has(> .card:nth-child(4)) { grid-auto-flow: row; grid-template-columns: repeat(2, 1fr); grid-auto-columns: unset; }
    .card { padding: var(--space-2); min-width: 0; }
    .card .amount { font-size: 21px; }
    .tab, .tabs-more-btn { padding: 9px 12px; font-size: 14px; }
    th, td { padding: 8px 8px; font-size: 13px; }
    .details-grid, .cal-controls { grid-template-columns: 1fr; }
    .tool-menu { min-width: min(280px, calc(100vw - 32px)); }
    dialog { width: 94%; }
  }
  @media (max-width: 360px) {
    /* Still one row on the narrowest phones - the 480px rule's grid-auto-flow
       carries down, and this only shrinks what is inside so three cards fit
       instead of stacking. Stacking is what produced the 2+1 "missing card"
       look one breakpoint up. */
    .card { padding: 8px 6px; }
    .card .amount { font-size: 17px; }
    .card .cat-label, .card .sub { font-size: 10.5px; }
  }

  /* Splash screen */
  #splash {
    position: fixed; inset: 0; z-index: 5000;
    background: #0C1729;
    display: flex; align-items: center; justify-content: center;
    transition: opacity 500ms ease-out;
  }
  [data-theme="light"] #splash { background: #FFFFFF; }
  #splash.hide { opacity: 0; pointer-events: none; }
  #splash img { width: min(72vw, 620px); height: auto; animation: splashPop 700ms ease-out; }
  @keyframes splashPop { from { transform: scale(0.9); opacity: 0; } to { transform: scale(1); opacity: 1; } }

  @media (prefers-reduced-motion: reduce) {
    * { transition: none !important; animation: none !important; }
  }

  /* ---- Print: clean report of the active tool ---- */
  @media print {
    @page { margin: 1.2cm; }
    html, body { background: #fff !important; color: #000 !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
    #splash, header, #toast, dialog,
    .header-actions, .tool-menu, .add-form, form, .filters, .actions-cell,
    .year-nav, .clock-panel, .clock-buttons, .tabs, .file-hint, .empty, .details-footer,
    .beta-strip { display: none !important; }
    .container { max-width: 100% !important; padding: 0 !important; }
    .print-only { display: flex !important; }
    .view[hidden], .tab-panel[hidden] { display: none !important; }
    .panel, .card, .detail-block, .file-status {
      background: #fff !important; color: #000 !important;
      border: 1px solid #bbb !important; box-shadow: none !important;
      break-inside: avoid; page-break-inside: avoid; margin-bottom: 12px;
    }
    h2, h3, .cat-label, .sub, th, td, .amount, .id-line, li, p { color: #000 !important; }
    .amount-in, .card.total .amount { color: #067647 !important; }
    .amount-out, .amount.neg { color: #b42318 !important; }
    /* Same specificity trap as on screen: without this the expenses total prints
       green, because .card.total .amount outranks a bare .amount-out. */
    .card.total .amount.amount-out { color: #b42318 !important; }
    .table-wrap { overflow: visible !important; }
    table { width: 100% !important; }
    tr { page-break-inside: avoid; }
    .matrix-table, .matrix-table th, .matrix-table td, .cal-cell { font-size: 10px !important; }
    .sticky-col, .matrix-table th { position: static !important; background: #fff !important; }
    .pay-cell.paid { background: #d1fadf !important; color: #067647 !important; }
    .pay-cell.unpaid { background: #fee4e2 !important; color: #b42318 !important; }
    .pay-cell.future { background: #dbeafe !important; color: #1E40AF !important; }
    .type-badge, .cal-cell.d-eve, .cal-cell.d-hol, .cal-cell.d-rest, .cal-cell.d-vac, .cal-cell.d-sick { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
    canvas { max-width: 100% !important; height: auto !important; }
    /* When printing a report, show ONLY the report area */
    body.report-printing .container, body.report-printing dialog, body.report-printing #splash, body.report-printing #toast { display: none !important; }
    body.report-printing #reportPrintArea { display: block !important; }
    #reportPrintArea .rpt-table { font-size: 11px !important; }
  }

  /* ===== Welcome (first visit) ===== */
  #welcomeDialog { max-width: 480px; width: 92%; text-align: start; }
  .welcome-head { display: flex; flex-direction: column; align-items: center; gap: 10px; margin-bottom: 8px; }
  .welcome-logo { height: 88px; width: auto; }
  .wl-light { display: none; }
  [data-theme="light"] .wl-light { display: block; }
  [data-theme="light"] .wl-dark { display: none; }
  #welcomeDialog h3 { text-align: center; margin-bottom: 12px; }
  .welcome-body p { color: var(--color-text-dim); font-size: 14px; line-height: 1.7; margin-bottom: 10px; }
  .welcome-list { margin: 0 0 14px; padding-inline-start: 20px; font-size: 14px; line-height: 2; }
  .welcome-list strong { color: var(--color-secondary); }
  .welcome-tip { display: flex; align-items: flex-start; gap: 10px; background: rgba(59,130,246,0.12); border: 1px solid rgba(59,130,246,0.35); border-radius: 10px; padding: 10px 12px; font-size: 14px; margin-bottom: 14px; }
  .welcome-tip svg { margin-top: 1px; }
  .welcome-tip svg { color: var(--color-secondary); flex-shrink: 0; }
  .welcome-dontshow { margin-bottom: 4px; }

  /* ===== Report Center (JasperReports-inspired) ===== */
  #reportDialog { max-width: 900px; width: 94%; max-height: 90vh; }
  .report-controls-card { background: var(--color-muted); border: 1px solid var(--color-border); border-radius: 10px; padding: 14px 16px; margin-bottom: 16px; }
  .report-controls { display: flex; flex-wrap: wrap; gap: 10px; align-items: end; }
  .report-controls label { flex: 1 1 140px; }
  .report-select-label { flex: 1 1 200px; }
  .report-select-label select { font-size: 16px; font-weight: 600; }
  .report-controls .btn-primary { min-height: 44px; flex: 0 0 auto; }
  #reportDateFilters { display: flex; flex-wrap: wrap; gap: 10px; flex: 2 1 auto; }
  /* Same inline-style-beats-[hidden] trap as .tabs/.wa-account-bar elsewhere in this
     file: an id/class display:flex outranks the UA [hidden]{display:none}, so a
     list-type report (residents/tickets/pros/buildingsys) that hides these via
     .hidden=true would otherwise still show empty date-range controls. */
  #reportDateFilters[hidden] { display: none; }
  #reportDateFilters label { flex: 1 1 130px; }
  .quick-period-row { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 16px; }
  .quick-period-row[hidden] { display: none; }
  .qp-btn { background: var(--color-muted); border: none; border-radius: 999px; padding: 5px 14px; font-size: 13px; color: var(--color-fg); }
  .qp-btn:hover { background: var(--color-secondary); color: #fff; }
  .qp-btn.qp-year { background: var(--color-secondary); color: #fff; font-weight: 600; }
  .qp-btn.qp-year:hover { filter: brightness(1.15); }
  .report-preview { max-height: 60vh; overflow: auto; border: 1px solid var(--color-border); border-radius: 8px; padding: 16px; background: var(--color-muted); }
  .report-preview:has(> .file-hint:only-child) { display: flex; align-items: center; justify-content: center; min-height: 160px; }
  .report-preview > .file-hint:only-child { text-align: center; font-size: 14px; }
  #reportPrintArea { display: none; }
  /* Report document (on white, print-like) */
  .rpt { background: #fff; color: #111827; padding: 24px; border-radius: 6px; }
  .rpt-title-band { display: flex; align-items: center; gap: 14px; border-bottom: 3px solid #1E40AF; padding-bottom: 12px; margin-bottom: 12px; }
  .rpt-title-band img { height: 48px; }
  .rpt-title-band .rt-name { font-size: 22px; font-weight: 700; color: #0F172A; }
  .rpt-title-band .rt-sub { font-size: 13px; color: #6B7280; }
  .rpt-params { display: flex; flex-wrap: wrap; gap: 6px 20px; font-size: 13px; color: #374151; margin-bottom: 14px; }
  .rpt-params strong { color: #111827; }
  .rpt-table { width: 100%; border-collapse: collapse; font-size: 13px; }
  .rpt-table th { background: #1E40AF; color: #fff; text-align: start; padding: 7px 9px; font-weight: 600; }
  .rpt-table td { padding: 6px 9px; border-bottom: 1px solid #E5E7EB; text-align: start; }
  .rpt-table td.num { text-align: end; font-variant-numeric: tabular-nums; }
  .rpt-group td { background: #EEF2FF; font-weight: 700; color: #1E3A8A; border-top: 1px solid #C7D2FE; }
  .rpt-subtotal td { background: #F8FAFC; font-weight: 600; border-top: 1px solid #CBD5E1; }
  .rpt-grand td { background: #1E40AF; color: #fff; font-weight: 700; font-size: 14px; }
  .rpt-summary { margin-top: 16px; display: flex; flex-wrap: wrap; gap: 10px 28px; font-size: 14px; border-top: 2px solid #1E40AF; padding-top: 12px; }
  .rpt-summary b { color: #1E40AF; font-size: 16px; }
  .rpt-empty { padding: 24px; text-align: center; color: #6B7280; }
  .rpt-pos { color: #067647; }
  .rpt-neg { color: #b42318; }

  /* --- Guided tour (custom, self-contained; no external library) --- */
  /* #251b: fixed centered tip now (see positionTourTipCenter), like the
     WhatsApp setup wizard's <dialog> - no more spotlight cutout, corner-dock,
     or drag-to-reposition. pointer-events:none stays: the tip explains a
     REAL form behind it (Settings, still open underneath) that the user
     needs to actually type into - the backdrop must never eat that click. */
  #tourBackdrop { position: fixed; inset: 0; z-index: 9998; background: transparent; pointer-events: none; }
  #tourBackdrop.dim { background: rgba(0,0,0,0.55); }
  /* #273: the card CLIPPED its overflow instead of scrolling it - overflow:hidden
     plus a max-height. That was survivable while it only held a paragraph, but
     once the step's real form moved inside (#271) the content outgrew the cap,
     and what got cut was the step strip at the top and the הבא/דילוג row at the
     bottom - the two things the user needs to keep moving. Zooming in made it
     worse by shrinking the visual viewport the cap is derived from.
     Now a flex column: the strip and the button row hold their size, and only the
     middle scrolls. The navigation can never be cut off again regardless of zoom
     or how tall the borrowed form is. */
  #tourTip {
    position: fixed; z-index: 9999; box-sizing: border-box;
    width: min(720px, calc(100vw - 24px)); max-width: 720px;
    /* #320: the flex-column/scrolling-middle fix below this comment block was
       only ever applied under the 899px mobile media query further down -
       above that width (any normal desktop window, zoomed in or not) this
       rule set no cap at all, and positionTourTipCenter() actively CLEARS
       maxHeight on every reposition - so the exact "step strip and button
       row get cut off, not just the middle" failure the comment above
       describes was still fully reproducible on desktop, just at a higher
       zoom level than on mobile. One cap for every width fixes both -
       positionTourTipCenter()'s own maxHeight-clearing line was removed
       since an unset inline style just lets this rule apply anyway. */
    max-height: min(92dvh, 760px); overflow: hidden;
    background: var(--color-card); color: var(--color-fg);
    border: 1px solid var(--color-border); border-radius: var(--radius);
    box-shadow: 0 18px 50px rgba(0,0,0,0.48);
    padding: 0; text-align: start;
    display: flex; flex-direction: column;
  }
  #tourTip .tour-stepper { flex: 0 0 auto; }                 /* head stays put */
  #tourTip .tour-content { display: flex; flex-direction: column; min-height: 0; flex: 1 1 auto; }
  #tourTip .tour-step-card { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
  #tourTip .tour-row { flex: 0 0 auto; }                     /* buttons stay put */
  #tourTip .tour-stepper {
    display: flex; align-items: stretch; gap: 0;
    border-bottom: 1px solid var(--color-border);
    background: rgba(128,128,128,.04);
  }
  #tourTip .tour-step-dot {
    flex: 1 1 0; min-width: 0; min-height: 42px;
    display: flex; align-items: center; justify-content: center;
    padding: 8px 4px; border: 0; border-bottom: 3px solid transparent;
    background: transparent; color: var(--color-text-dim);
    font-weight: 700; cursor: pointer;
  }
  #tourTip .tour-step-dot.active {
    color: var(--color-primary);
    border-bottom-color: var(--color-primary);
  }
  #tourTip .tour-step-dot.done {
    color: var(--color-success);
    border-bottom-color: var(--color-success);
  }
  #tourTip .tour-content { padding: var(--space-3); }
  /* Visual alignment with the WhatsApp setup wizard's .ww-feature-card (same
     tint/border/radius) - the tour's own positioning/drag/spotlight logic
     underneath (.tour-head's grid + drag handle) is untouched, only wrapped. */
  #tourTip .tour-step-card {
    display: flex; flex-direction: column; gap: var(--space-2);
    padding: 10px 12px; border-radius: var(--radius);
    background: rgba(128,128,128,.06); border: 1px solid rgba(128,128,128,.12);
    margin-bottom: var(--space-2);
  }
  #tourTip .tour-head { display: grid; grid-template-columns: auto 1fr; align-items: center; gap: var(--space-2); margin-bottom: 0; }
  #tourTip .tour-avatar { display: none; }
  #tourTip .tour-icon {
    width: 48px; height: 48px; border-radius: 999px;
    display: inline-flex; align-items: center; justify-content: center;
    background: rgba(59,130,246,.12);
    border: 1px solid rgba(59,130,246,.28);
    font-size: 25px; line-height: 1;
  }
  #tourTip .tour-kicker { color: var(--color-text-dim); font-size: 12px; font-weight: 700; margin-bottom: 2px; }
  #tourTip h4 { margin: 0; font-size: 18px; line-height: 1.25; }
  #tourTip .tour-body { color: var(--color-text-dim); font-size: 14px; line-height: 1.5; }
  #tourTip .wizard-note {
    margin-top: var(--space-2); padding: var(--space-2);
    border: 1px solid var(--color-border); border-radius: calc(var(--radius) - 2px);
    background: rgba(128,128,128,.06); color: var(--color-text-dim);
    font-size: 12px; line-height: 1.45;
  }
  #tourTip .tour-row {
    display: flex; align-items: center; flex-wrap: wrap;
    gap: var(--space-1); margin-top: var(--space-3);
    padding-top: var(--space-2); border-top: 1px solid var(--color-border);
  }
  #tourTip .tour-counter { color: var(--color-text-dim); font-size: 13px; margin-inline-end: auto; }
  #tourTip .tour-row button { font-size: 14px; }
  /* #261: the collapse-to-bar affordance is NOT mobile-only any more. #253b
     assumed "on desktop the centered card and the settings form never fight for
     space" - they do: #251b made the tip a fixed CENTERED card, and the middle
     of the screen is exactly where the building-details and add-resident forms
     it explains sit, so the wizard covered the fields it had just asked the user
     to fill in. The bar, and the chevron that brings the card back, now exist on
     every width. */
  /* #271: the step's real form, moved into the card. It arrives styled as a
     settings section, so strip the chrome that only made sense in its own panel
     and let it scroll if the step is a tall one. */
  #tourTip .tour-host:empty { display: none; }
  /* #273: no max-height of its own any more. The card above is now the single
     scroll container; a second one nested inside it produced two competing
     scrollbars and let the total still exceed the viewport. */
  #tourTip .tour-host {
    margin-top: 10px;
    border-top: 1px solid var(--color-border); padding-top: 10px;
  }
  #tourTip .tour-host > .tour-borrowed { margin: 0; padding: 0; border: 0; background: none; box-shadow: none; }
  /* Its own heading duplicates the step title directly above it. */
  #tourTip .tour-host > .tour-borrowed > h3:first-child,
  #tourTip .tour-host > .tour-borrowed > h4:first-child { display: none; }
  #tourTip .tour-collapse {
    display: inline-flex; align-items: center; justify-content: center;
    min-height: 42px; font-size: 18px;
  }
  /* Collapsed = a one-row bar: counter + step title on one side, the SAME
     prev/next buttons on the other, same row and same size. Everything
     instructional hides until the chevron brings it back. */
  #tourTip.tour-collapsed .tour-stepper,
  #tourTip.tour-collapsed .tour-step-card,
  #tourTip.tour-collapsed .wizard-note,
  #tourTip.tour-collapsed .tour-skip { display: none; }
  #tourTip.tour-collapsed .tour-content { padding: 6px 10px; }
  #tourTip.tour-collapsed .tour-row {
    display: flex; flex-wrap: nowrap; align-items: center; gap: 6px;
    margin-top: 0; padding-top: 0; border-top: 0;
  }
  #tourTip.tour-collapsed .tour-counter {
    flex: 1 1 auto; min-width: 0; text-align: start; font-size: 12px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  #tourTip.tour-collapsed .tour-row button { width: auto; min-height: 44px; }
  @media (max-width: 899px) {
    #tourTip {
      width: calc(100vw - 16px);
      max-width: none;
      max-height: min(90dvh, 760px);
      overflow: auto;
    }
    #tourTip .tour-content { padding: 14px; }
    #tourTip .tour-head { grid-template-columns: auto 1fr; }
    #tourTip .tour-step-dot { min-height: 38px; font-size: 13px; }
    #tourTip .tour-icon { width: 42px; height: 42px; font-size: 22px; }
    #tourTip h4 { font-size: 16px; }
    #tourTip .tour-body { font-size: 13px; line-height: 1.45; }
    #tourTip .tour-row { display: grid; grid-template-columns: 1fr 1fr; align-items: stretch; }
    #tourTip .tour-counter { grid-column: 1; margin: 0; text-align: start; align-self: center; }
    /* Only the grid placement is mobile-specific now - the collapsed bar's own
       styling lives in the base rules above (#261) so desktop gets it too. */
    #tourTip .tour-collapse { grid-column: 2; }
    #tourTip .tour-row button { width: 100%; min-height: 42px; }
    #tourTip .tour-next { grid-column: 1 / -1; }
    /* #253b: while the tour rides on top of Settings on a phone, the 7-tab
       header row eats ~2 rows of a tiny screen - keep only the active tab. */
    #settingsDialog.tour-active #settingsTabs .tab:not(.active) { display: none; }
  }

  /* The guided tour lives inside Settings while it borrows the real form.
     That dialog clips its children by default, so let the tour escape the
     frame when it is active. */
  #settingsDialog.tour-active { overflow: visible; }

/* Checks tracker — danger card for bounced checks */
.card-danger { border-left: 3px solid var(--color-destructive) !important; }
.card-danger .card-value { color: var(--color-destructive); }

.check-actions-cell { min-width: 420px; white-space: normal; }
.check-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
  justify-content: flex-start;
}
.check-action-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 36px;
  padding: 6px 10px;
  border-radius: 8px;
  border: 1px solid var(--color-border);
  background: rgba(255,255,255,0.02);
  color: var(--color-fg);
  font-size: 12.5px;
  font-weight: 650;
  line-height: 1;
  white-space: nowrap;
}
.check-action-btn:hover { background: rgba(255,255,255,0.06); }
.check-action-btn:disabled {
  opacity: 0.42;
  background: transparent;
}
.check-action-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  min-width: 18px;
  height: 18px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 800;
}
.check-action-edit { border-color: rgba(96,165,250,0.55); color: #BFDBFE; }
.check-action-edit .check-action-icon { background: rgba(96,165,250,0.18); }
.check-action-deposit { border-color: rgba(245,158,11,0.7); color: #FCD34D; }
.check-action-deposit .check-action-icon { background: rgba(245,158,11,0.2); }
.check-action-clear { border-color: rgba(5,150,105,0.72); color: #86EFAC; }
.check-action-clear .check-action-icon { background: rgba(5,150,105,0.22); }
.check-action-bounce,
.check-action-delete { border-color: rgba(220,38,38,0.72); color: #FCA5A5; }
.check-action-bounce .check-action-icon,
.check-action-delete .check-action-icon { background: rgba(220,38,38,0.22); }
.check-action-reminder { border-color: rgba(59,130,246,0.72); color: #93C5FD; }
.check-action-reminder .check-action-icon { background: rgba(59,130,246,0.2); }
[data-theme="light"] .check-action-btn { background: #fff; }
[data-theme="light"] .check-action-edit { color: #1D4ED8; }
[data-theme="light"] .check-action-deposit { color: #92400E; }
[data-theme="light"] .check-action-clear { color: #047857; }
[data-theme="light"] .check-action-bounce,
[data-theme="light"] .check-action-delete { color: #B91C1C; }
[data-theme="light"] .check-action-reminder { color: #2563EB; }
@media (max-width: 640px) {
  .check-actions-cell { min-width: 300px; }
  .check-actions {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
  }
  .check-action-btn {
    width: 100%;
    min-height: 44px;
    padding: 8px 10px;
    font-size: 13px;
  }
}

/* #280: cheque card view (mobile, <=600px - see isMatrixCardView()). Reuses
   .matrix-card/-head/-summary/-body as-is (styles.css:1255-1270); only the
   body's field list and pushing the status badge to the end of the head are
   specific to cheques. */
.chk-card .matrix-card-head > span:last-child { margin-inline-start: auto; }
.chk-card-fields { display: grid; gap: 6px; font-size: 13px; margin-bottom: var(--space-2); }
.chk-card-fields .chk-card-key { color: var(--color-text-dim); }

/* Generic mobile card view for the renderList()/TOOLKIT record-list tables
   (tickets first; pros/buildingsys/residents/vendorRequests/vaadfixed/
   vaadincome share the identical shape once each is converted). Same base
   classes as the cheque cards above - .list-card only adds what's actually
   list-specific: badge pushed to the end of the head, and the expanded
   body's label:value field grid. */
.list-card .matrix-card-head > span:last-child { margin-inline-start: auto; }
.list-card-fields { display: grid; gap: 6px; font-size: 13px; margin-bottom: var(--space-2); }
.list-card-fields .list-card-key { color: var(--color-text-dim); }
/* Derived installment rows inside a splitDisplay card's body (vaadfixed/
   vaadincome) - the card equivalent of .installment-child's dimmed/indented
   table rows. Not real records (no edit/delete), so no interaction styling. */
.list-card-installments { display: flex; flex-direction: column; gap: 4px; margin-bottom: var(--space-2); padding-inline-start: 1rem; border-inline-start: 2px solid var(--color-border); }
.list-card-installment-child { display: flex; justify-content: space-between; gap: 8px; font-size: 12.5px; color: var(--color-text-dim); }
.list-card-body .actions-cell { display: flex; gap: 8px; flex-wrap: wrap; }
/* The 2-column action grid above (max-width:640px) already covers mobile
   card mode (<=600px) with 44px targets, so the card body's actions reuse
   .check-actions as-is - no separate rule needed here. */

/* Check dialog */
#checkDialog { width: min(500px, 95vw); border-radius: var(--radius); border: 1px solid var(--color-border); background: var(--color-card); color: var(--color-fg); padding: var(--space-4); }
#checkDialog::backdrop { background: rgba(0,0,0,0.5); }

/* ============================================================
   WELCOME DIALOG — improved layout (2026-07)
   ============================================================ */
#welcomeDialog {
  width: min(540px, 95vw);
  max-height: 90vh;
  overflow-y: auto;
  border-radius: var(--radius-lg, 12px);
  border: 1px solid var(--color-border);
  background: var(--color-card);
  color: var(--color-fg);
  padding: var(--space-5, 24px);
}

.welcome-headline {
  font-size: 22px;
  font-weight: 700;
  margin: 0 0 var(--space-1, 4px) 0;
}

.welcome-head {
  display: flex;
  align-items: center;
  gap: var(--space-3, 12px);
  margin-bottom: var(--space-4, 16px);
}

.welcome-tagline {
  color: var(--color-text-dim);
  font-size: 14px;
  margin-bottom: var(--space-3, 12px);
}

/* The mascot is here to support the promo line, not compete with it - kept
   moderate-sized and secondary; the text carries the actual message. */
.welcome-promo {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-2, 8px);
  margin: 0 0 var(--space-4, 16px) 0;
  padding: var(--space-3, 12px);
  border-radius: var(--radius, 8px);
  background: var(--color-bg, var(--color-surface));
  border: 1px solid var(--color-border);
}

.welcome-mascot {
  width: 120px;
  height: 120px;
  object-fit: contain;
}

.welcome-promo-copy {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.welcome-promo-copy strong {
  font-size: 16px;
  font-weight: 700;
  color: var(--color-secondary);
}

.welcome-promo-copy span {
  font-size: 13px;
  color: var(--color-text-dim);
}

.welcome-actions {
  margin-top: var(--space-4, 16px);
  gap: var(--space-2, 8px);
}
/* Defensive: if a button's text is ever abnormally long (a missing i18n key
   falling back to showing its own raw name, a long translation, etc.), the
   row wraps to a second line and/or the button's own text wraps internally -
   it never forces the dialog wider and creates a horizontal scrollbar. */
.welcome-actions {
  flex-wrap: wrap;
}
.welcome-actions button {
  min-width: 0;
  flex: 1 1 auto;
  white-space: normal;
  word-break: break-word;
}

.welcome-btn-tour {
  flex: 1;
  justify-content: center;
}

@media (max-width: 480px) {
  #welcomeDialog {
    padding: 16px;
    width: calc(100vw - 16px);
    margin: 8px;
  }

  .welcome-head {
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
  }

  .welcome-headline {
    font-size: 18px;
  }

  .welcome-actions {
    flex-direction: column;
  }

  .welcome-btn-tour {
    width: 100%;
  }

  .welcome-mascot {
    width: 90px;
    height: 90px;
  }
}

/* ============================================================
   EXCEL IMPORT WIZARD — styles
   alon.rlapp.net — 2026-07
   ============================================================ */

/* [open] guard is required, not cosmetic: a bare #residentImportDialog{display:flex}
   is author CSS, which beats the browser's own dialog:not([open]){display:none}
   default regardless of source order - without it, this dialog was ALWAYS visible,
   rendered inline whatever the page's own scroll position happened to be (it's a
   direct child of <body>), never actually hidden even though .showModal() was
   never called. Same trap already fixed elsewhere in this file for [hidden]. */
#residentImportDialog[open] {
  width: min(680px, 96vw);
  max-height: 90vh;
  overflow-y: auto;
  border-radius: var(--radius-lg, 12px);
  border: 1px solid var(--color-border);
  background: var(--color-card);
  color: var(--color-fg);
  padding: 0;
  display: flex;
  flex-direction: column;
}

/* Progress dots */
.wiz-progress {
  display: flex;
  justify-content: center;
  gap: 8px;
  padding: 14px 20px 0;
}
.wiz-dot {
  width: 10px; height: 10px;
  border-radius: 50%;
  background: var(--color-border);
  transition: background .2s, transform .2s;
}
.wiz-dot.active { background: var(--color-primary, #4a90d9); transform: scale(1.3); }
.wiz-dot.done   { background: var(--color-success, #22c55e); }

/* Header */
.wiz-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 20px;
  border-bottom: 1px solid var(--color-border);
}
.wiz-title { margin: 0; font-size: 17px; font-weight: 700; }
.wiz-restart-btn {
  background: none; border: 1px solid var(--color-border);
  border-radius: var(--radius, 8px); padding: 4px 10px;
  cursor: pointer; font-size: 13px; color: var(--color-fg);
  white-space: nowrap;
}
.wiz-restart-btn:hover { background: var(--color-hover); }

/* Panels */
.wiz-panel { padding: 18px 20px 20px; }

/* Dropzone */
.wiz-dropzone {
  border: 2px dashed var(--color-border);
  border-radius: var(--radius, 8px);
  padding: 32px 16px;
  text-align: center;
  cursor: pointer;
  transition: border-color .2s, background .2s;
  margin-bottom: 14px;
}
.wiz-dropzone.dragover {
  border-color: var(--color-primary, #4a90d9);
  background: color-mix(in srgb, var(--color-primary, #4a90d9) 8%, transparent);
}
.wiz-drop-icon { font-size: 36px; display: block; margin-bottom: 8px; }
.wiz-drop-inner p { margin: 0 0 10px; color: var(--color-text-dim); font-size: 14px; }
.wiz-drop-inner small { display: block; margin-top: 8px; color: var(--color-text-dim); font-size: 12px; }

/* File info after load */
.wiz-file-info {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 14px;
  background: var(--color-bg, var(--color-surface));
  border: 1px solid var(--color-border);
  border-radius: var(--radius, 8px);
  margin-bottom: 10px;
}
.wiz-file-icon { font-size: 26px; }
.wiz-file-info strong { display: block; font-size: 14px; }
.wiz-file-info small  { color: var(--color-text-dim); font-size: 12px; }

#wizSheetRow { margin: 10px 0; font-size: 14px; }
#wizSheetRow select { margin-inline-start: 8px; }

/* Loading / error */
.wiz-loading { color: var(--color-text-dim); font-size: 14px; }
.wiz-error   { color: var(--color-danger, #ef4444); font-size: 14px; }

/* Step nav buttons */
.wiz-step-nav {
  display: flex; gap: 10px; justify-content: flex-end;
  margin-top: 16px; padding-top: 12px;
  border-top: 1px solid var(--color-border);
}

/* Preview table */
.wiz-preview-wrap { overflow-x: auto; max-height: 220px; overflow-y: auto; overscroll-behavior: contain; margin-bottom: 14px; border: 1px solid var(--color-border); border-radius: var(--radius, 8px); }
.wiz-preview-table { border-collapse: collapse; font-size: 12px; min-width: 100%; }
.wiz-preview-table th, .wiz-preview-table td { padding: 5px 8px; border-bottom: 1px solid var(--color-border); white-space: nowrap; text-align: start; }
.wiz-preview-table th { background: var(--color-bg, var(--color-surface)); font-weight: 600; position: sticky; top: 0; }

/* Column detection badges */
.wiz-badge { display: block; font-size: 10px; font-weight: 600; border-radius: 4px; padding: 1px 5px; margin-top: 3px; white-space: nowrap; }
.wiz-badge.hi  { background: color-mix(in srgb, var(--color-success,#22c55e) 20%, transparent); color: var(--color-success,#16a34a); }
.wiz-badge.med { background: color-mix(in srgb, var(--color-warning,#f59e0b) 20%, transparent); color: var(--color-warning,#d97706); }

/* Detection summary */
.wiz-summary { font-size: 14px; }
.wiz-summary ul { margin: 6px 0; padding-inline-start: 18px; }
.wiz-summary li { margin: 3px 0; }
.wiz-warn { color: var(--color-warning, #d97706); font-weight: 600; }
.wiz-pay-hint { color: var(--color-success, #16a34a); font-weight: 600; }
.wiz-info { color: var(--color-text-dim); font-style: italic; }

/* Mapping progress bar */
.wiz-map-progress { margin-bottom: 14px; }
.wiz-map-bar-wrap { height: 6px; background: var(--color-border); border-radius: 3px; overflow: hidden; margin-bottom: 4px; }
.wiz-map-bar { height: 100%; background: var(--color-primary, #4a90d9); transition: width .3s; }
#wizMapBarTxt { font-size: 12px; color: var(--color-text-dim); }

/* Mapping field box */
.wiz-detected-box, .wiz-not-detected {
  padding: 12px 14px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius, 8px);
  background: var(--color-bg, var(--color-surface));
  margin-bottom: 12px;
}
.wiz-detected-box p, .wiz-not-detected p { margin: 0 0 8px; font-size: 14px; }
.wiz-map-btns { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.wiz-samples { display: flex; gap: 6px; flex-wrap: wrap; margin: 6px 0; }
.wiz-sample { background: var(--color-border); border-radius: 4px; padding: 2px 7px; font-size: 12px; }
.wiz-req  { font-size: 11px; color: var(--color-danger, #ef4444); font-weight: 400; }
.wiz-opt  { font-size: 11px; color: var(--color-text-dim); font-weight: 400; }

/* Column picker grid */
.wiz-col-picker { margin-top: 12px; }
.wiz-col-picker p { font-size: 13px; margin-bottom: 8px; }
.wiz-col-grid { display: flex; flex-wrap: wrap; gap: 8px; }
.wiz-col-btn {
  flex: 0 1 calc(33% - 8px);
  min-width: 120px;
  display: flex; flex-direction: column; align-items: flex-start;
  padding: 8px 10px;
  border: 2px solid var(--color-border);
  border-radius: var(--radius, 8px);
  background: var(--color-card);
  cursor: pointer; font-size: 13px; text-align: start;
  transition: border-color .15s, background .15s;
}
.wiz-col-btn:hover { border-color: var(--color-primary, #4a90d9); background: var(--color-hover); }
.wiz-col-btn strong { font-size: 13px; }
.wiz-col-btn small  { font-size: 11px; color: var(--color-text-dim); margin-top: 2px; }
.wiz-col-taken { opacity: .65; }
.wiz-taken-lbl { color: var(--color-warning, #d97706); }
.wiz-col-none  { border-style: dashed; color: var(--color-text-dim); }

/* Row preview */
.wiz-row-sample { font-size: 12px; margin-top: 12px; color: var(--color-text-dim); }
.wiz-chip { display: inline-block; background: var(--color-border); border-radius: 4px; padding: 2px 7px; margin: 2px; font-size: 12px; }
.wiz-chip em { font-style: normal; color: var(--color-text-dim); }

/* Payment step */
.wiz-pay-sheets { display: flex; flex-direction: column; gap: 8px; margin: 14px 0; }
.wiz-pay-card {
  padding: 10px 14px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius, 8px);
  background: var(--color-bg, var(--color-surface));
}
.wiz-pay-card label { display: flex; align-items: center; gap: 8px; cursor: pointer; font-size: 14px; margin-bottom: 4px; }
.wiz-pay-card small { font-size: 12px; color: var(--color-text-dim); padding-inline-start: 22px; }
.wiz-pay-acts { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 14px; }

/* Confirm table */
.wiz-prev-hdr { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; font-size: 14px; flex-wrap: wrap; }
.wiz-prev-hdr label { display: flex; align-items: center; gap: 6px; cursor: pointer; margin-inline-start: auto; }
.wiz-warn-badge { background: color-mix(in srgb, var(--color-warning,#f59e0b) 20%, transparent); color: var(--color-warning,#d97706); font-size: 12px; font-weight: 600; padding: 2px 8px; border-radius: 4px; }
.wiz-confirm-tbl .wiz-row-issue td { background: color-mix(in srgb, var(--color-warning,#f59e0b) 8%, transparent); }
.wiz-issue { font-size: 11px; background: color-mix(in srgb, var(--color-warning,#f59e0b) 20%, transparent); color: var(--color-warning,#d97706); border-radius: 3px; padding: 1px 5px; }
.wiz-issue-cell { white-space: normal; min-width: 80px; }
.wiz-import-acts { display: flex; gap: 10px; margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--color-border); flex-wrap: wrap; }

/* Result */
.wiz-result { text-align: center; padding: 20px 0; }
.wiz-result-icon { font-size: 52px; margin-bottom: 8px; }
.wiz-result h3 { font-size: 20px; margin: 0 0 14px; }
.wiz-result-list { list-style: none; padding: 0; margin: 0 0 20px; font-size: 15px; display: flex; flex-direction: column; gap: 6px; align-items: center; }
.wiz-result-acts { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }

/* Mobile */
@media (max-width: 600px) {
  #residentImportDialog { width: 100%; max-height: 100dvh; border-radius: 0; margin: 0; }
  .wiz-col-btn { flex: 0 1 calc(50% - 8px); }
  .wiz-step-nav, .wiz-import-acts, .wiz-result-acts { flex-direction: column; }
  .wiz-step-nav button, .wiz-import-acts button, .wiz-result-acts button { width: 100%; }
}

/* ═══ WhatsApp Setup Wizard (v1.27.194) ═══ */
#waSetupWizard[open] {
  display: block;
  width: min(760px, 95vw);
  max-height: min(94dvh, calc(100dvh - 24px), 860px);
  margin: auto;
  padding: 0;
  overflow: auto;
}

.material-symbols-rounded {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: 'Material Symbols Rounded';
  font-variation-settings: 'FILL' 1, 'wght' 500, 'GRAD' 0, 'opsz' 24;
  line-height: 1;
  font-size: 1em;
}

#waSetupWizard .ww-step {
  padding: 20px 24px 18px;
}

#waSetupWizard .ww-step + .ww-step {
  margin-top: 2px;
}

#waSetupWizard .ww-hero {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  padding: 16px 18px;
  border-radius: 18px;
  background: linear-gradient(180deg, rgba(37,99,235,.14), rgba(37,99,235,.05));
  border: 1px solid rgba(37,99,235,.14);
  box-shadow: 0 10px 28px rgba(12,23,41,.08);
}

#waSetupWizard .ww-hero-icon {
  width: 56px;
  height: 56px;
  border-radius: 18px;
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  background: rgba(37,99,235,.12);
  color: var(--color-primary, #2563eb);
  box-shadow: inset 0 0 0 1px rgba(37,99,235,.18);
}

#waSetupWizard .ww-hero-copy {
  min-width: 0;
}

#waSetupWizard .ww-hero-copy h4 {
  margin: 0 0 8px;
}

#waSetupWizard .ww-hero-copy .file-hint {
  margin: 0;
  line-height: 1.55;
}

#waSetupWizard .ww-feature-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 12px;
  margin-top: 14px;
}

.ww-step-dot {
  flex: 1;
  text-align: center;
  padding: 10px 6px 11px;
  font-size: 13px;
  font-weight: 700;
  color: rgba(128,128,128,.58);
  background: rgba(128,128,128,.04);
  border-bottom: 3px solid transparent;
  transition: all .2s;
}
.ww-step-dot.active {
  color: var(--color-primary, #2563eb);
  border-bottom-color: var(--color-primary, #2563eb);
  background: rgba(37,99,235,.06);
}
.ww-step-dot.done {
  color: var(--color-success, #16a34a);
  border-bottom-color: var(--color-success, #16a34a);
  background: rgba(22,163,74,.06);
}
.ww-step { animation: ww-in .18s ease-out; }
@keyframes ww-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
.ww-feature-card {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  padding: 14px 16px;
  border-radius: 16px;
  background: rgba(128,128,128,.05);
  border: 1px solid rgba(128,128,128,.12);
  box-shadow: 0 1px 0 rgba(12,23,41,.03);
}
#waSetupWizard .ww-feature-card > div {
  min-width: 0;
}
#waSetupWizard .ww-feature-card strong {
  display: block;
  margin-bottom: 4px;
}
#waSetupWizard .ww-feature-icon {
  width: 40px;
  height: 40px;
  border-radius: 14px;
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  background: rgba(37,99,235,.1);
  color: var(--color-primary, #2563eb);
}
.ww-success-badge {
  display: inline-block;
  padding: 6px 14px;
  border-radius: 20px;
  background: rgba(22,163,74,.1);
  color: var(--color-success, #16a34a);
  font-weight: 600;
  font-size: 14px;
}

/* Compact WhatsApp onboarding: one action, one scroll region, no nested form. */
#waSetupWizard.wa-setup-dialog[open] {
  display: flex;
  flex-direction: column;
  width: min(620px, calc(100vw - 24px));
  height: min(560px, calc(100dvh - 24px));
  max-height: calc(100dvh - 24px);
  margin: auto;
  padding: 0;
  overflow: hidden;
}
.wa-wizard-form {
  display: flex;
  flex-direction: column;
  min-height: 0;
  height: 100%;
  margin: 0;
}
.wa-wizard-header,
.wa-wizard-footer {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 16px 20px;
  border-bottom: 1px solid rgba(128,128,128,.15);
}
.wa-wizard-header h3 { margin: 0; font-size: 18px; }
.wa-wizard-header p { margin: 4px 0 0; }
.wa-wizard-close { flex: 0 0 auto; min-width: 42px; padding: 7px 10px; font-size: 18px; }
.wa-wizard-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: clamp(18px, 4vw, 30px) clamp(16px, 5vw, 34px);
}
.ww-wizard-state { max-width: 540px; margin: 0 auto; text-align: center; }
.ww-wizard-state h4 { margin: 12px 0 8px; font-size: 20px; }
.ww-wizard-state > .file-hint { line-height: 1.6; }
.ww-wizard-icon,
.ww-add-card-icon,
.ww-status-icon,
.ww-wizard-context-icon {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
}
.ww-wizard-icon {
  width: 64px;
  height: 64px;
  margin: 0 auto;
  border-radius: 20px;
  background: rgba(37,99,235,.12);
  font-size: 30px;
}
.ww-wizard-icon-success { background: rgba(22,163,74,.14); }
.ww-wizard-state > button { margin-top: 14px; }
.ww-wizard-state > button + button { margin-inline-start: 8px; }
.ww-wizard-context {
  display: flex;
  align-items: center;
  gap: 10px;
  max-width: 540px;
  margin: 0 auto 14px;
  padding: 10px 12px;
  text-align: start;
  border: 1px solid var(--color-border);
  border-radius: 14px;
  background: var(--color-card);
}
.ww-wizard-context-icon { width: 34px; height: 34px; border-radius: 10px; background: rgba(37,99,235,.1); }
.ww-wizard-context strong { display: block; margin-top: 2px; overflow-wrap: anywhere; }
.ww-status-card,
.ww-add-card {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  max-width: 540px;
  margin: 0 auto 14px;
  padding: 16px;
  text-align: start;
  border: 1px solid var(--color-border);
  border-radius: 16px;
  background: var(--color-card);
}
.ww-status-card { border-color: rgba(37,99,235,.35); background: rgba(37,99,235,.07); }
.ww-status-card h4,
.ww-add-card h4 { margin: 1px 0 5px; font-size: 16px; }
.ww-status-card p,
.ww-add-card p { margin: 0; line-height: 1.5; }
.ww-status-icon,
.ww-add-card-icon { width: 42px; height: 42px; border-radius: 13px; font-size: 22px; background: rgba(37,99,235,.12); }
.ww-add-card-icon { background: rgba(37,99,235,.1); }
.ww-add-card strong { font-family: ui-monospace, SFMono-Regular, Consolas, monospace; direction: ltr; unicode-bidi: isolate; }
.ww-add-card .btn-primary { display: inline-block; margin-top: 12px; text-decoration: none; }
.ww-wizard-note { max-width: 540px; margin: 12px auto 0; text-align: center; }
.wa-wizard-footer {
  border-top: 1px solid rgba(128,128,128,.15);
  border-bottom: 0;
  min-height: 58px;
}
.wa-wizard-footer .file-hint { margin: 0; }
@media (max-width: 600px) {
  #waSetupWizard.wa-setup-dialog[open] { width: calc(100vw - 16px); height: calc(100dvh - 16px); max-height: calc(100dvh - 16px); }
  .wa-wizard-header { padding: 13px 14px; }
  .wa-wizard-body { padding: 18px 14px; }
  .wa-wizard-footer { align-items: flex-start; padding: 11px 14px; }
  .wa-wizard-footer .file-hint { font-size: 12px; }
  .ww-wizard-state h4 { font-size: 18px; }
  .ww-status-card, .ww-add-card { padding: 13px; gap: 10px; }
  .ww-wizard-state > button + button { display: block; margin: 8px auto 0; }
}

/* Final responsive hardening for the one-action WhatsApp connection flow. */
#waSetupWizard.wa-setup-dialog[open] {
  width: min(680px, calc(100vw - 24px));
  height: min(720px, calc(100dvh - 24px));
  max-height: calc(100dvh - 24px);
  overflow: hidden;
}
.wa-wizard-heading,
.wa-wizard-header > div,
.ww-status-card > div,
.ww-add-card > div,
.ww-wizard-context > div,
.ww-flow-heading > div { min-width: 0; }
.wa-wizard-heading { flex: 1 1 auto; }
.wa-wizard-kicker {
  display: block;
  margin-bottom: 2px;
  color: var(--color-secondary);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.wa-wizard-header h3,
.wa-wizard-header p,
.ww-wizard-state h4,
.ww-status-card h4,
.ww-add-card h4,
.ww-flow h4 { overflow-wrap: anywhere; }
.wa-wizard-header p { line-height: 1.45; }
.wa-wizard-body {
  overscroll-behavior: contain;
  scrollbar-gutter: stable;
}
.wa-wizard-footer { flex-wrap: wrap; }
.wa-wizard-footer .file-hint {
  flex: 1 1 240px;
  min-width: 0;
  overflow-wrap: anywhere;
  line-height: 1.45;
}
.ww-add-card,
.ww-status-card,
.ww-flow { width: 100%; }
.ww-add-card .btn-primary {
  max-width: 100%;
  white-space: normal;
  overflow-wrap: anywhere;
  text-align: center;
}
.ww-flow {
  max-width: 540px;
  margin: 0 auto 14px;
  padding: 15px 16px;
  text-align: start;
  border: 1px solid var(--color-border);
  border-radius: 16px;
  background: color-mix(in srgb, var(--color-card) 82%, transparent);
}
.ww-flow-heading {
  display: flex;
  align-items: flex-start;
  gap: 12px;
}
.ww-flow-heading h4 { margin: 1px 0 4px; font-size: 16px; }
.ww-flow-heading p { margin: 0; line-height: 1.45; }
.ww-flow-icon {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  border-radius: 11px;
  background: rgba(5,150,105,.13);
  color: var(--color-success);
  font-weight: 800;
}
.ww-flow-list {
  display: grid;
  gap: 10px;
  margin: 14px 0 0;
  padding: 0;
  list-style: none;
}
.ww-flow-list li {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  min-width: 0;
}
.ww-flow-list li > span {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: rgba(37,99,235,.12);
  color: var(--color-primary);
  font-size: 12px;
  font-weight: 800;
}
.ww-flow-list li > div { min-width: 0; flex: 1 1 auto; }
.ww-flow-list strong { display: block; margin-bottom: 1px; font-size: 14px; }
.ww-flow-list p { margin: 0; line-height: 1.45; }
.ww-wizard-note { overflow-wrap: anywhere; }
@media (max-width: 600px) {
  #waSetupWizard.wa-setup-dialog[open] {
    width: calc(100vw - 16px);
    height: calc(100dvh - 16px);
    max-height: calc(100dvh - 16px);
  }
  .ww-flow { padding: 13px; }
  .ww-flow-list { gap: 9px; }
  .wa-wizard-footer .file-hint { flex-basis: 100%; }
}
