/* ═══════════════════════════════════════════════════════════════════
   Mocca — Shell panels & modals
   Filter (slide-in panel), Sort (centered modal), Alerts (centered
   modal), Search (full-overlay modal). Layouts mirror the V7 reference
   in /Inspiration/Mocca (Old)/V7.html and the Conditions Mockup PNG.
   ═══════════════════════════════════════════════════════════════════ */

/* ── shared backdrop ──────────────────────────────────────────── */
.panel-scrim{
  position:fixed;inset:0;background:var(--scrim);
  opacity:0;pointer-events:none;z-index:240;
  transition:opacity 200ms var(--mk-ease);
  backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px);
}
.panel-scrim.open{opacity:1;pointer-events:auto}
/* B58 (Pablo, with the Create-zone panel open over the map: "the background
   doesn't have the usual blur") — the scrim WAS open, with its blur, at z-index
   240; the map was simply painting over it. `.leaflet-container` is
   `position:relative` with NO z-index, so it is not a stacking context and
   Leaflet's internal panes (overlays 400, markers 600, popups 700, controls
   1000) were competing with app chrome in the ROOT context — every zone
   polygon, pin and zoom control sat ABOVE the 240 scrim and read unblurred.
   `z-index:0` confines them to the map's own box, which is where they belong. */
.leaflet-container{ z-index:0; }

/* ── shared overlay container for centered modals ─────────────── */
.modal-overlay{
  position:fixed;inset:0;z-index:250;
  display:none;align-items:center;justify-content:center;
  padding:24px;
  background:transparent;
}
.modal-overlay.open{display:flex}
/* When opened as a stacked sub-modal on top of a base panel (e.g. the
   condition builder over the filter panel), bump z-index above the
   filter panel (z:260) so the card paints on top while the panel
   stays visible underneath. */
.modal-overlay.sub-open{z-index:270;background:color-mix(in srgb, var(--scrim) 60%, transparent)}
/* Panel-confined sub-modal — when a discard / confirm is triggered FROM
   inside the filter panel (a slide-stack back button, a Cancel button),
   the modal anchors over the panel's column instead of floating in
   viewport centre. Reads as a continuation of the slide it's protecting
   instead of a disconnected, floating warning. The overlay matches the
   filter panel's right-column geometry exactly so the backdrop dims
   only the panel itself; outside the panel the rest of the viewport
   stays interactive. The card sits near the top of the column so it
   visibly hovers over the slide it's protecting. */
/* B39 C7 (Pablo) — panel-triggered sub-modals (discard / delete confirm,
   rename, etc.) now center on the SCREEN, not over the panel column. */
.modal-overlay.is-panel-confined{
  inset:0;
  width:auto;
  min-width:0;
  padding:24px 20px;
  align-items:center;justify-content:center;
  background:color-mix(in srgb, var(--scrim) 55%, transparent);
}
@media (max-width: 600px){
  .modal-overlay.is-panel-confined{inset:0;width:auto;min-width:0;padding:16px}
}
.modal-overlay.is-panel-confined .panel-card{
  width:min(420px, 100%);max-height:none;
  align-self:center;
  margin:0;
  box-shadow:0 14px 32px rgba(0,0,0,.32);
}

/* Common card shell for centered modals */
.panel-card{
  background:var(--bg-1);border:1px solid var(--border);
  border-radius:14px;box-shadow:var(--shadow-lg);
  width:min(440px, 100%);
  max-height:min(720px, calc(100dvh - 48px));
  display:flex;flex-direction:column;overflow:hidden;
}
.panel-card.wide{width:min(560px, 100%)}

.panel-hd{
  display:flex;align-items:center;justify-content:space-between;gap:8px;
  padding:14px 16px;border-bottom:1px solid var(--border);flex-shrink:0;
}
.panel-hd-l{display:flex;align-items:center;gap:8px;min-width:0;flex:1 1 auto}
.panel-hd-l .mi{font-size:20px;color:var(--accent);flex:0 0 auto}
/* B41 torture sweep — panel titles carry USER DATA (expense/trip/game names):
   hard limit + ellipsis; tooltip.js auto-reveals the full text on hover. */
.panel-hd-l .panel-title{font:700 14px var(--mk-font-ui);color:var(--fg-1);letter-spacing:-.005em;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* B67 R67-068 — a Latin record name as a panel title ("One Hundred Years of Solitude") truncated at its start in Arabic (R67-014) */
html[dir="rtl"] .panel-hd-l .panel-title{unicode-bidi:plaintext;text-align:right}

/* B39 C5 — View panel tab strip (Filter / Sort) at top of the root slide. */
.fp-view-tabs{display:flex;gap:4px;padding:8px 12px 0;flex-shrink:0}
/* B64-06 — on Dashboard the pill reads "Filter" and there is nothing to sort
   (the widgets arrive pre-sorted), so the Filter/Sort switch is not offered:
   a one-option tab strip would be a dead control. */
body.route-dash .fp-view-tabs{display:none}
.fp-view-tab{
  display:flex;align-items:center;gap:6px;flex:1;justify-content:center;
  padding:9px 10px;border:0;border-radius:10px 10px 0 0;cursor:pointer;
  background:transparent;color:var(--fg-3);
  font:600 12px var(--mk-font-ui);letter-spacing:-.005em;
  border-bottom:2px solid transparent;transition:color .12s,background .12s,border-color .12s;
}
.fp-view-tab .mi{font-size:17px}
.fp-view-tab:hover{color:var(--fg-1);background:color-mix(in srgb,var(--accent) 7%,transparent)}
.fp-view-tab.on{color:var(--accent);border-bottom-color:var(--accent)}
.fp-vt-ct{
  min-width:16px;height:16px;padding:0 4px;border-radius:8px;
  display:inline-flex;align-items:center;justify-content:center;
  background:var(--accent);color:#fff;font:700 10px var(--mk-font-ui);
}
.fp-view-tab:not(.on) .fp-vt-ct{background:var(--fg-3)}

/* Inline rename pencil for the QF edit panel — sits to the right of
   the title so the user can rename without leaving the panel. */
.qf-rename-btn{
  display:inline-flex;align-items:center;justify-content:center;
  width:26px;height:26px;border-radius:6px;
  background:transparent;border:1px solid transparent;
  color:var(--fg-3);cursor:pointer;
  transition:background var(--mk-t-fast),color var(--mk-t-fast),border-color var(--mk-t-fast);
}
.qf-rename-btn .mi{font-size:14px;color:inherit}
.qf-rename-btn:hover{background:var(--bg-2);color:var(--accent);border-color:var(--border)}
.panel-close{
  width:32px;height:32px;border-radius:8px;
  border:1px solid var(--border);background:var(--bg-input);
  color:var(--fg-2);cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center;
  transition:border-color var(--mk-t-fast),color var(--mk-t-fast);
}
.panel-close:hover{border-color:var(--accent);color:var(--accent)}
.panel-close .mi{font-size:18px}
/* ═══ 44px HIT-TARGET FLOOR (Pablo, 2026-08-26 — "yes do those changes") ══════
   These are shared app-wide primitives, so the floor is raised the way that
   does NOT redesign every header and section: the VISUAL box keeps its size and
   an invisible ::after extends the tap area to 44px. 36 + 4px on each side = 44.
   The expansion is inset inside the header's own padding, so it never overlaps a
   neighbouring control (which would silently steal its clicks). */
.panel-close{position:relative;width:36px;height:36px}
.panel-close::after{content:'';position:absolute;inset:-4px}

.panel-body{flex:1;min-height:0;overflow-y:auto;padding:16px}
.panel-ft{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:12px 16px;border-top:1px solid var(--border);flex-shrink:0;
  flex-wrap:wrap;
}
/* B57 (Pablo, on the games' Start/Cancel pair: "These start and cancel buttons
   look weird, let's not invent so much different styles for essentially the same
   buttons we already had") — a panel footer's two actions ARE the same button in
   two states, so in a footer the app's shared secondary/primary pair
   (`.wl-chip` / `.wl-close-btn`, which every panel already emits) takes the
   anatomy of the app's ONE real button component: the `.btn` / `.btn.primary`
   metrics, radius, weight and hover from shell.css. Nothing is re-styled outside
   a footer, and no call site changed — the two invented shapes (a 999px pill
   beside a chunky accent block) simply stop existing where they sat together. */
.panel-ft .wl-chip,.panel-ft .wl-close-btn{
  display:inline-flex;align-items:center;justify-content:center;gap:6px;
  padding:9px 14px;min-height:38px;border-radius:10px;
  font:600 13px var(--mk-font-ui);white-space:nowrap;cursor:pointer;
  transition:all var(--mk-t-fast);
}
.panel-ft .wl-chip{ border:1px solid var(--border);background:var(--bg-input);color:var(--fg-1) }
.panel-ft .wl-chip:hover{ border-color:var(--accent);color:var(--accent);background:var(--bg-input) }
.panel-ft .wl-chip .mi,.panel-ft .wl-close-btn .mi{ font-size:16px;color:inherit }
.panel-ft .wl-close-btn{
  border:1px solid var(--accent);background:var(--accent);color:var(--accent-fg);
  font-weight:600;box-shadow:0 1px 2px rgba(13,37,48,.10);
}
.panel-ft .wl-close-btn:hover{
  filter:none;border-color:transparent;color:var(--accent-fg);
  background:color-mix(in srgb, var(--accent) 90%, #000);
}
.panel-ft .wl-close-btn[disabled],.panel-ft .wl-close-btn[disabled]:hover{
  opacity:.5;cursor:not-allowed;background:var(--accent);border-color:var(--accent);
}
/* a lone primary action still belongs on the trailing edge */
.panel-ft > .wl-close-btn:only-child{ margin-inline-start:auto }

/* Footer buttons (reused across panels) */
.panel-btn{
  display:inline-flex;align-items:center;justify-content:center;gap:6px;
  height:36px;padding:0 14px;border-radius:9px;
  font:600 12px var(--mk-font-ui);cursor:pointer;white-space:nowrap;
  transition:all var(--mk-t-fast);
}
.panel-btn-clear{
  background:transparent;border:1px solid var(--border);color:var(--fg-2);
}
.panel-btn-clear:hover{border-color:var(--mk-danger);color:var(--mk-danger)}
.panel-btn-primary{
  background:var(--accent);border:1px solid var(--accent);color:var(--accent-fg);
  box-shadow:0 1px 2px rgba(13,37,48,.10);
}
.panel-btn-primary:hover{
  background:color-mix(in srgb, var(--accent) 90%, #000);border-color:transparent;
  transform:translateY(-1px);
  box-shadow:0 7px 18px color-mix(in srgb, var(--accent) 42%, transparent);
}
.panel-btn-primary:active{transform:translateY(0);
  box-shadow:0 2px 8px color-mix(in srgb, var(--accent) 34%, transparent)}
/* Disabled primary action (e.g. Sort → Apply while a row's field path is
   still incomplete). Muted + non-interactive; no hover lift. */
.panel-btn:disabled,
.panel-btn.is-disabled{
  opacity:.45;cursor:not-allowed;
  transform:none !important;box-shadow:none !important;
  background:var(--accent);border-color:var(--accent);
}
.panel-btn:disabled:hover,
.panel-btn.is-disabled:hover{
  transform:none;
  background:var(--accent);border-color:var(--accent);
  filter:none;
}
.panel-btn-ghost{
  background:transparent;border:1px solid var(--border);color:var(--fg-1);
}
.panel-btn-ghost:hover{border-color:var(--accent);color:var(--accent)}
.panel-btn-danger{
  background:var(--mk-danger);border:1px solid var(--mk-danger);color:#fff;
}
.panel-btn-danger:hover{filter:brightness(1.06)}

/* Delete-condition confirmation modal — narrow centred card, prose
   body, accent-danger primary action. */
#condDeleteModal .panel-card{width:min(440px, calc(100vw - 32px))}
#condDeleteModal .cd-msg{
  margin:0;font:500 13px/1.55 var(--mk-font-ui);color:var(--fg-2);
}

/* B63-011 — accessRequestModal is a real form (a mandatory textarea, not a
   yes/no confirm), so it gets the standard bottom-sheet/side-panel mobile
   pair (same as #alertsModal) instead of staying a centred card. */
@media (max-width:600px) and (orientation:portrait){
  #accessRequestModal{align-items:flex-end;justify-content:stretch;padding:0}
  #accessRequestModal .panel-card{
    width:100%;max-width:100%;max-height:86dvh;
    border-radius:18px 18px 0 0;border-inline-width:0;border-bottom:0;
    transform:translateY(100%);transition:transform 260ms var(--mk-ease);
  }
  #accessRequestModal.open .panel-card{transform:none}
}
@media (max-height:599px) and (orientation:landscape){
  #accessRequestModal{align-items:stretch;justify-content:flex-end;padding:0}
  #accessRequestModal .panel-card{
    height:100%;max-height:100%;width:min(420px, 92vw);
    border-radius:0;border-block-width:0;border-inline-end:0;
    transform:translateX(100%);transition:transform 260ms var(--mk-ease);
  }
  #accessRequestModal.open .panel-card{transform:none}
  html[dir="rtl"] #accessRequestModal .panel-card{transform:translateX(-100%)}
  html[dir="rtl"] #accessRequestModal.open .panel-card{transform:none}
}
#condDeleteModal .panel-hd-l .mi{color:var(--mk-danger)}

/* ─────────────────────────────────────────────────────────────────
   FILTER PANEL — slides in from the right (or top on small screens).
   Two sections: Quick filters (chips) and Conditions (tree).
   Matches the Conditions Mockup layout from /Inspiration.
   ───────────────────────────────────────────────────────────────── */
.filter-panel{
  position:fixed;top:0;bottom:0;inset-inline-end:0;
  /* Conditions can grow long (deep nesting + per-row sibling buttons +
     the conjunction column), and the panel hosts nested slide views
     (edit-condition, edit-scope-filter) that benefit from a wider
     surface. Sizing is responsive: 50vw on desktop, 80vw on tablet,
     full width on mobile (handled by the media queries further below).
     A 720 px hard floor keeps things readable even on wide laptops. */
  width:min(var(--mk-panel-w, 560px), 100vw);
  min-width:min(var(--mk-panel-w, 560px), 100vw);
  background:var(--bg-1);
  border-inline-start:1px solid var(--border);
  box-shadow:var(--shadow-lg);
  z-index:260;
  display:flex;flex-direction:column;
  transform:translateX(110%);
  transition:transform 280ms var(--mk-ease);
}
/* W673-R1 (Pablo 2026-07-23, visual-check form pick "full-width below tablet"):
   below tablet, ALL detail panels go full-width to MATCH .cl-panel
   (components-lab.css:284, already full-width across this same band). The old
   80vw side-panel left a ~135px page-peek next to the full-width Component-Lab /
   marketplace panels — the inconsistency Pablo flagged. Now every detail panel
   (wallet / ticket / entity / filter / cl) reads identically edge-to-edge here.
   The mobile-V and landscape-short rules further down already do this for
   filter-panel; this makes the tablet + mobile-landscape-tall band match. */
/* ── B59 — ONE responsive grammar for a panel ──────────────────────────────
   Pablo: "On tablet, a Panel should look like a bottom sheet but big obviously. So
   on desktop it would be a side panel, on mobile it would be a full screen panel and
   on tablet it would be a bottom sheet (same as how a modal on tablet/desktop would
   be a bottom sheet in mobile portrait and a side panel in mobile landscape) it's all
   about proportional scaling of visual components and steps."

   The grammar, stated once, in the four bands this file already uses:

     surface   desktop (≥1025 & tall)   tablet (601-1024 & tall)   mobile portrait   mobile landscape
     PANEL     side panel               BIG bottom sheet           full screen       side panel
     MODAL     centred card             centred card               bottom sheet      side panel

   Panel and modal MEET in the middle: whatever one is at a given size, the other is
   one step "smaller", which is what "proportional scaling" means here. The two
   mobile rows already existed for modals (`#alertsModal`, `#condBuilderModal`,
   `.cb-date-pop` all carry exactly this pair); what was missing was the panel side —
   W673-R1 made this band edge-to-edge FULL SCREEN, which on a tablet throws away the
   context behind the sheet for no gain.

   Two mechanical notes for whoever edits this next: the sheet has to beat
   `.filter-panel.open{transform:translateX(0) !important}` (base rule, line ~330),
   so the open state is re-declared with `translateY` and its own `!important`; and
   the band now carries `min-height`, because without it a SHORT landscape phone
   matched here too and got a bottom sheet before the landscape rule could speak. */
@media (max-width: 1024px) and (min-width: 601px) and (min-height: 600px){
  .filter-panel{
    inset-inline:0;top:auto;bottom:0;
    width:100%;min-width:0;
    /* "but big obviously" — nearly the whole fold, with just enough of the page
       showing above it to keep the user's place. */
    height:min(92dvh, calc(100dvh - 44px));
    border-inline-start:0;
    border-top:1px solid var(--border);
    border-radius:20px 20px 0 0;
    box-shadow:0 -18px 48px color-mix(in srgb, var(--scrim, #0d2530) 22%, transparent);
    transform:translateY(102%);
    /* B66 W1 (066-072) — panel-host.js sets the height from the content; this eases it */
    transition:transform var(--mk-t-base, .28s), height .22s cubic-bezier(.2,.8,.2,1);
  }
  html[dir="rtl"] .filter-panel{transform:translateY(102%)}
  .filter-panel.open{transform:translateY(0) !important}
  /* the sheet's own grab affordance, drawn on the header, not added to the markup */
  .filter-panel > .panel-hd{position:relative;padding-top:18px}
  .filter-panel > .panel-hd::after{
    content:'';position:absolute;top:7px;inset-inline-start:50%;transform:translateX(-50%);
    width:38px;height:4px;border-radius:999px;background:var(--border);
  }
  /* a slide inside the sheet inherits the rounded top, or its corners show through */
  .filter-panel .fp-slide > .panel-hd,
  .filter-panel .ent-slide > .panel-hd{border-radius:20px 20px 0 0}
}

/* Slide stack — the filter panel's contents live in a stack of slides.
   Each .fp-slide is positioned absolutely over the panel; newer
   slides slide in from the inline-end edge over the previous one and
   pop back when the user goes back. The root slide (filter list) is
   always present at z:0; pushed slides increment z so they paint on
   top. Slides claim the full panel area so they can carry their own
   header + footer (mirroring the root slide's chrome). */
.fp-slide-stack{
  position:relative;flex:1;min-height:0;
  display:flex;flex-direction:column;
  overflow:hidden;
  /* B63-034 — the panel (`.filter-panel`) carries the rounded-top-corner
     radius at tablet width (B59, above), but its own background is
     invisible; a slide's OWN `--bg-1` fill painted square corners right
     over it, so the sheet read as square regardless of the panel's radius.
     `inherit` tracks whatever radius the panel has at any breakpoint (0 on
     desktop/mobile-V, 20px 20px 0 0 on tablet) and the stack's own
     `overflow:hidden` clips the slide to match. */
  border-radius:inherit;
}
.fp-slide{
  position:absolute;inset:0;
  display:flex;flex-direction:column;
  background:var(--bg-1);
  transform:translateX(0);
  transition:transform 280ms var(--mk-ease);
}
.fp-slide-root{
  position:relative;inset:auto;
  transform:none;flex:1;min-height:0;
  display:flex;flex-direction:column;
}
/* Pushed slides start off-screen on the inline-end edge and slide in
   when .open is added. The previous slide stays mounted (no DOM
   teardown) so any in-flight inputs preserve their state. */
.fp-slide-pushed{
  transform:translateX(110%);
  z-index:5;
}
html[dir="rtl"] .fp-slide-pushed{transform:translateX(-110%)}
.fp-slide-pushed.open{transform:translateX(0)}
/* RTL needs its own .open rule: `html[dir="rtl"] .fp-slide-pushed`
   (specificity 0,2,1) otherwise out-specifies `.fp-slide-pushed.open`
   (0,2,0), pinning the opened slide off-screen left in Arabic. Pre-Wave-B
   bug surfaced during Wave B ar verification (2026-06-03). */
html[dir="rtl"] .fp-slide-pushed.open{transform:translateX(0)}
/* Back arrow on a pushed slide's header. */
.fp-back-btn{
  width:32px;height:32px;border-radius:8px;
  border:1px solid var(--border);background:var(--bg-input);
  color:var(--fg-2);cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center;
  transition:border-color var(--mk-t-fast),color var(--mk-t-fast);
  margin-inline-end:8px;
}
.fp-back-btn:hover{border-color:var(--accent);color:var(--accent)}
.fp-back-btn .mi{font-size:18px}
/* RTL: mirror the glyph with a transform instead of injecting a second
   ligature via ::before — the span already contains the "arrow_back"
   ligature text, so adding ::before content rendered TWO arrows in
   Arabic (Pablo 2026-06-11). */
html[dir="rtl"] .fp-back-btn .mi{transform:scaleX(-1)}
.fp-slide .panel-body{flex:1;min-height:0;overflow-y:auto;padding:16px}
.fp-slide .panel-ft{
  display:flex;align-items:center;justify-content:flex-end;gap:10px;
  /* Bumped vertical padding from 12 → 16 so the Save/Cancel buttons
     read as proper actions, not crammed pills, on the panel's default
     360px width. Buttons themselves also get a touch-friendlier 40px
     min-height via the rule below. */
  padding:16px;border-top:1px solid var(--border);flex-shrink:0;
}
.fp-slide .panel-ft .panel-btn{min-height:40px;padding:0 18px}
html[dir="rtl"] .filter-panel{transform:translateX(-110%)}
.filter-panel.open{transform:translateX(0) !important}

/* B53-14 — the SHARED panel host (panel-host.js). It borrows the panel shell and
   the entity panel's `.ent-slide*` grammar wholesale; all it needs of its own is
   a column layout and a clipping stack. Every "why is this a modal?" surface
   (content title, spoiler chat, new address) lives in here now. */
.mp-panel{display:flex;flex-direction:column}
.mp-panel .mp-stack{position:relative;flex:1;min-height:0;overflow:hidden;display:flex;flex-direction:column}
.mp-panel .ent-slide-root{position:relative;inset:auto;flex:1;min-height:0}
.mp-panel .ent-panel-body{flex:1;min-height:0;overflow-y:auto;padding:14px 16px 20px}

/* Date popover escape — when ANY .cb-date-wrap is open, the slide
   stack drops its transform AND the transition so the popover
   (position:fixed) immediately escapes to the viewport instead of
   being clipped to the slide's transform-containing-block. Without
   `transition:none`, the slide animates from translateX(0) to none
   over 280ms — during that interpolation the containing block stays
   active for fixed children, so the popover paints inside the panel
   column for the duration of the animation. */
body.cb-date-popover-open .filter-panel.open,
body.cb-date-popover-open .fp-slide-pushed.open,
body.cb-date-popover-open .fp-slide-root,
body.cb-date-popover-open .ent-slide-pushed.open,
body.cb-date-popover-open .ent-slide-root,
body.cb-date-popover-open .ent-slide-pushed,
body.cb-date-popover-open .fp-slide-pushed{
  transform:none !important;
  transition:none !important;
}

/* B28 C8 next-round (Pablo: "the first selector doesn't show anything when
   I open it — closes it, shows for an instant, then disappears"): the SAME
   containing-block problem as the date popover above, just for the plain
   field-picker/step dropdowns. `.fp-slide-pushed`/`.ent-slide-pushed` carry
   a `transform` (the slide-in animation) which — per spec — becomes the
   CONTAINING BLOCK for any `position:fixed` descendant instead of the true
   viewport. portalCbMenu() computes top/left as if relative to the real
   viewport, so the menu rendered thousands of px off to the side (still
   technically "open", opacity:1 — just invisible, off-screen). Reuse the
   proven fix: drop the transform (and its transition) while any such menu
   is open, so position:fixed resolves against the true viewport again. */
body.cb-menu-escape-open .filter-panel.open,
body.cb-menu-escape-open .fp-slide-pushed.open,
body.cb-menu-escape-open .fp-slide-root,
body.cb-menu-escape-open .ent-slide-pushed.open,
body.cb-menu-escape-open .ent-slide-root{
  transform:none !important;
  transition:none !important;
}

/* Searchable menus — kill the sliver where scrolled rows peeked through
   the menu's top padding ABOVE the sticky search bar (Pablo 2026-06-01,
   repeat). The search is `position:sticky;top:0`, but the .cs-menu's 6px
   top padding sat ABOVE its stuck position, leaving a gap. Dropping the
   menu's top padding makes the search flush at the very top so rows scroll
   cleanly UNDER its opaque background. Covers BOTH search structures:
   the markup search on value pickers (items wrapped in .cs-search-target)
   and the shell.js-injected search on field/relation menus (items as the
   menu's direct children). */
.cb-field-seg > .cs-menu:has(> .cs-search),
.cb-step > .cs-menu:has(> .cs-search),
.cs-menu:has(> .cs-search){
  padding-top:0;
}
/* Full-bleed the sticky search over the menu's side padding so its
   opaque fill spans edge-to-edge — no item corner shows past it. The
   menu's overflow clip rounds the search's top corners to match.
   C26 (Pablo B34): generalized to EVERY searchable cs-menu (entity
   type picker, profile pickers, etc.) — not only the cb ones — so an
   item can never peek above the sticky search bar. */
.cb-field-seg > .cs-menu > .cs-search,
.cb-step > .cs-menu > .cs-search,
.cs-menu > .cs-search{
  margin-inline:-6px;
  padding-inline:14px;
  z-index:3;
}
/* C26 — the searchable menu is its own scroll container so the sticky
   search actually sticks and rows scroll cleanly under it. */
.cs-menu:has(> .cs-search){ overflow-y:auto; }

/* The filter panel is a column of sections; only the conditions section
   scrolls. The footer ALWAYS stays pinned at the bottom (flex-shrink:0),
   even when the user scrolls deep into a long conditions tree. */
.fp-section{
  display:flex;flex-direction:column;gap:10px;
  padding:14px 16px;border-bottom:1px solid var(--divider);
  flex-shrink:0;
}
.fp-section-conditions{
  flex:1;min-height:0;overflow:hidden;
  border-bottom:0;
}
.fp-section-hd{
  display:flex;align-items:center;justify-content:space-between;
  font:700 11px var(--mk-font-ui);text-transform:none;letter-spacing:.08em;color:var(--fg-3);
  flex-shrink:0;
}

/* Quick-filter chips — also draggable: drop them into the conditions
   tree to add a chip-based condition. Each chip carries inline edit /
   delete buttons so the user can rename or remove a saved filter without
   leaving the filter panel. */
.fp-chips{display:flex;flex-wrap:wrap;gap:6px}
.fp-chip{
  display:inline-flex;align-items:center;gap:6px;
  padding:6px 6px 6px 10px;border-radius:999px;
  background:var(--bg-input);border:1px solid var(--border);
  font:600 11px var(--mk-font-mono);color:var(--fg-2);
  cursor:grab;white-space:nowrap;user-select:none;
  /* Cap chip width so long QF labels ("Has Refrigerated Products") stop
     forcing one chip per row. Label ellipsises inside the cap; the chip
     keeps its full label in a `title` tooltip for discoverability. */
  max-width:180px;
  transition:all var(--mk-t-fast);
}
.fp-chip:active{cursor:grabbing}
.fp-chip:hover{border-color:var(--accent);color:var(--accent)}
.fp-chip.on{
  background:color-mix(in srgb, var(--accent) 12%, transparent);
  border-color:var(--accent);
  color:var(--accent);
}
.fp-chip.dragging{opacity:.4}
.fp-chip .fp-chip-tag{font-size:13px;color:inherit;flex:0 0 auto}
.fp-chip .fp-chip-l{
  line-height:1;min-width:0;flex:1 1 auto;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.fp-chip-edit, .fp-chip-del{
  /* RESERVED slot — the actions always occupy their 18px footprint so
     the chip's overall width never changes between hover/no-hover. The
     buttons themselves fade in via opacity. Without the width reservation
     the chip would grow ~36px on hover, can reflow into a new row, and
     the cursor then leaves the chip — re-collapsing it, re-flowing back,
     hovering again, in an endless flicker loop (Pablo feedback 2026-05-29).
     The label flex-shrinks further to make room when actions are shown. */
  width:18px;height:18px;border-radius:999px;flex-shrink:0;
  background:transparent;border:0;color:inherit;opacity:0;
  display:inline-flex;align-items:center;justify-content:center;
  overflow:hidden;padding:0;
  cursor:pointer;pointer-events:none;
  transition:background var(--mk-t-fast),opacity var(--mk-t-fast),color var(--mk-t-fast);
}
.fp-chip-edit .mi, .fp-chip-del .mi{font-size:12px}
.fp-chip:hover .fp-chip-edit, .fp-chip:hover .fp-chip-del,
.fp-chip:focus-within .fp-chip-edit, .fp-chip:focus-within .fp-chip-del{
  opacity:1;pointer-events:auto;
}
/* Touch / no-hover devices get the actions pinned-visible since there's
   no hover gesture to reveal them. */
@media (hover: none){
  .fp-chip-edit, .fp-chip-del{opacity:.7;pointer-events:auto}
}
.fp-chip-edit:hover{background:color-mix(in srgb, var(--accent) 20%, transparent);color:var(--accent)}
.fp-chip-del:hover{background:color-mix(in srgb, var(--mk-danger) 20%, transparent);color:var(--mk-danger)}

/* The tree itself owns the scroll so the footer stays anchored.
   `container-type: inline-size` lets the per-row +AND/+OR sibling
   placeholders collapse to icon-only when the tree's available width
   gets tight — see the `@container fp-tree` block farther down. */
.fp-tree{
  container-type:inline-size;
  container-name:fp-tree;
  display:flex;flex-direction:column;gap:0;
  flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;
  padding-bottom:4px;
  /* Indent step + column widths shared by rows, placeholder buttons,
     and per-row rail segments so every layer aligns perfectly. The
     step bakes in: conj_w (40) + bar (2) + gap (6) = 48. The conj
     column reserves 8px of trailing padding before the rail so the
     AND / OR label has breathing room from the vertical bar. */
  --fp-step:48px;
  --fp-conj-w:40px;
  --fp-gap:6px;
  --fp-bar:2px;
  --fp-conj-pad:8px;
}

/* Each group draws ITS rail as a single continuous vertical line via a
   ::before pseudo. Per-row conj-out borders break across deeper rows
   (a level-1 row's conj-out sits at a different x than its parent's
   level-0 conj-out, so the level-0 bar dies at the nested row). One
   absolutely-positioned rail per group sidesteps that — it spans the
   full group height regardless of what levels its descendants render
   at. Trailing +AND/+OR placeholders are rendered OUTSIDE the group
   (see renderTree → trailingPlaceholders) so the rail naturally stops
   above them. */
.fp-group{
  display:flex;flex-direction:column;
  position:relative;
}
.fp-group::before{
  content:"";
  position:absolute;
  top:0;bottom:0;
  /* Rail position = level * step + (conj_w - bar). Sits flush against
     the inline-end edge of the conj column at this group's level. */
  /* level 0 default; deeper levels override inset-inline-start below */
  inset-inline-start:calc(var(--fp-conj-w) - var(--fp-bar));
  width:var(--fp-bar);
  background:color-mix(in srgb, var(--accent) 55%, transparent);
  pointer-events:none;
}
.fp-group[data-level="1"]::before{inset-inline-start:calc(1 * var(--fp-step) + var(--fp-conj-w) - var(--fp-bar))}
.fp-group[data-level="2"]::before{inset-inline-start:calc(2 * var(--fp-step) + var(--fp-conj-w) - var(--fp-bar))}
.fp-group[data-level="3"]::before{inset-inline-start:calc(3 * var(--fp-step) + var(--fp-conj-w) - var(--fp-bar))}
/* Single-condition tree (no level-0 conj rows): root rail collapses so
   the lone `currency` row reads flush left — conditions_mockup-single. */
.fp-tree:not(.has-level0-conj) > .fp-group[data-level="0"]::before{display:none}

/* Each tree line is an .fp-row wrapping a conjunction slot (outside
   the pill), the .fp-cond pill, and a single + sibling button on the
   trailing edge. The conjunction slot has a fixed width so AND / Y / و
   all consume the same column. The slot ALSO carries the vertical bar
   (border-inline-end) — consecutive same-level rows have bars at the
   same x so they stack into a continuous rail. Rows ladder right one
   step per nesting level via padding-inline-start so the column model
   stays consistent for every depth.
   Vertical padding lives on the row so adjacent rows touch (no gap on
   the parent tree) and the bars connect seamlessly. */
.fp-row{
  display:flex;align-items:center;gap:var(--fp-gap);
  padding:3px 0;
  padding-inline-start:0; /* level 0 default; deeper levels override below */
}
.fp-row[data-level="1"]{padding-inline-start:calc(1 * var(--fp-step))}
.fp-row[data-level="2"]{padding-inline-start:calc(2 * var(--fp-step))}
.fp-row[data-level="3"]{padding-inline-start:calc(3 * var(--fp-step))}

.fp-conj-out{
  flex-shrink:0;
  width:var(--fp-conj-w);
  box-sizing:border-box;
  /* Inline-end padding pushes the AND/OR label away from the rail so
     the label reads as its own column with breathing room before the
     vertical bar drawn by the enclosing .fp-group. */
  padding-inline-end:var(--fp-conj-pad);
  align-self:stretch;
  display:inline-flex;align-items:center;justify-content:flex-end;
  font:700 11px var(--mk-font-mono);
  letter-spacing:.06em;
  /* AND/OR boolean labels carry meaning — use the AA-safe accent text so
     they stay legible on light surfaces (VisualQA F1, 2026-06-08). */
  color:var(--accent-text);
}
/* First-position rows have no conjunction. The slot collapses entirely
   only when the tree has NO conjunction rows at level 0 (the
   conditions_mockup-single case — lone `currency != 'USD'` flush left).
   In every other case (mockup-first_or / first_and, nested groups), the
   slot stays as a blank-but-reserved column so all rows at the same
   level line up under the same x. The rail itself is drawn by the
   group, not the slot, so we just need the column visible — no
   visibility:hidden, since the slot is text-empty anyway. */
.fp-conj-out.empty{display:none}
.fp-row[data-level="0"] .fp-conj-out.empty + .fp-cond{margin-inline-start:0}
.fp-row:not([data-level="0"]) .fp-conj-out.empty{display:inline-flex}
.fp-row.has-and-child .fp-conj-out.empty{display:inline-flex}
.fp-tree.has-level0-conj .fp-row[data-level="0"] .fp-conj-out.empty{display:inline-flex}

/* Condition pill: expression + edit/remove. No conjunction inside any
   more — that lives in the gutter (.fp-conj-out) so the pill width is
   driven by the expression alone. */
.fp-cond{
  flex:1;min-width:0;
  display:flex;align-items:center;gap:8px;
  padding:6px 10px;border-radius:8px;
  background:var(--bg-2);
  font:500 12px var(--mk-font-ui);color:var(--fg-1);
  cursor:grab;user-select:none;
  /* Width should always match the surrounding rows. flex:1 already gives
     the basis room to grow, but at deeper indent levels a level-2 row
     can render wider than its siblings if anything inside (a long path
     name, an unwrapped chip) pushes the basis past the natural width.
     Cap with min-width:0 so flex shrinkage actually triggers. */
  min-width:0;
  transition:background var(--mk-t-fast),box-shadow var(--mk-t-fast),transform var(--mk-t-fast);
}
.fp-cond:hover{background:color-mix(in srgb, var(--accent) 4%, var(--bg-2))}
.fp-cond:active{cursor:grabbing}
.fp-cond.dragging{opacity:.4;background:var(--bg-3)}
.fp-cond.drop-target{box-shadow:inset 0 -2px 0 0 var(--accent)}
/* `flex:1 0 auto` (basis:auto + shrink:0) so the expr's hypothetical
   size is its full content and it never shrinks below that — when a
   scope chip sits on the same flex row (audit B2, 2026-05-22), the
   chip is the one that absorbs all the shrinkage instead of the
   expression. Non-scope rows still fill the pill because flex-grow:1
   absorbs the remaining space when no other grow:1 sibling competes.
   `min-width:0` + `overflow:hidden` still let the expr ellipsise if
   its content is genuinely longer than the pill (so we don't blow
   the pill width on, say, a very long field path on a deeply nested
   row); the chip's much higher shrink ratio just means the chip is
   the FIRST thing to take the hit. */
.fp-cond .fp-expr{
  /* shrink:1 (was 0) so a long expression ellipsises inside the row
     instead of overflowing past it onto the "+ AND" button — a field-
     source value can now be a multi-reference concat that's genuinely
     long (Pablo 2026-06-01). When a scope chip shares the row its
     flex-shrink:99 still absorbs ~99× more, so the expr stays at/near
     its content size in that case, preserving the audit-B2 behaviour. */
  flex:1 1 auto;min-width:0;
  font:500 12px var(--mk-font-ui);color:var(--fg-1);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.fp-cond .fp-expr .fp-expr-op{
  font:700 11px var(--mk-font-mono);color:var(--accent-text);
  /* Generous symmetric breathing room so the operator reads as its own
     token rather than sliding into the field name on the left. The pre-
     space lives in the field span (`margin-inline-end: 10px`) and the
     post-space here, matching by visual weight in every condition row. */
  margin-inline:10px 8px;letter-spacing:.04em;
}
.fp-cond .fp-expr .fp-expr-field{margin-inline-end:0}
/* Inline +N bubble inside a compacted saved-condition path label (Pablo #51). */
.fp-cond .fp-expr .fp-expr-field .fp-expr-more{
  display:inline-flex;align-items:center;justify-content:center;
  min-width:18px;height:16px;padding:0 4px;margin:0 1px;border-radius:5px;
  font:700 10px var(--mk-font-mono);vertical-align:1px;
  background:color-mix(in srgb, var(--accent) 12%, transparent);
  color:var(--accent-text);
}
.fp-cond .fp-expr .fp-expr-val{font:500 12px var(--mk-font-mono);color:var(--fg-2)}
/* Inline tag for relation values that carry a flag or icon — keeps the
   row scannable when several record IDs would otherwise look identical
   (the same applies to country flags or user avatars). */
.fp-cond .fp-expr .fp-expr-val-tag{
  display:inline-flex;align-items:center;gap:4px;
  vertical-align:middle;
  margin-inline-end:4px;
}
.fp-cond .fp-expr .fp-expr-flag{
  width:14px;height:14px;border-radius:50%;
  object-fit:cover;
  background:var(--bg-2);
  box-shadow:0 0 0 1px color-mix(in srgb, var(--border) 70%, transparent) inset;
}
.fp-cond .fp-expr .fp-expr-icon{font-size:14px;color:var(--accent-text)}
/* Range-step header — appears at the top of the date popup when the
   user is editing a date range. Shows which side they're on (Start /
   End) and a pair of step dots. The footer carries Next/Back. */
.cb-range-step-hd{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:6px 10px 8px;
  border-bottom:1px solid color-mix(in srgb, var(--border) 50%, transparent);
}
.cb-range-step-pill{
  display:inline-flex;align-items:center;gap:6px;
  height:26px;padding:0 10px;border-radius:999px;
  background:color-mix(in srgb, var(--accent) 16%, transparent);
  border:1px solid color-mix(in srgb, var(--accent) 30%, transparent);
  color:var(--accent);font:700 11px var(--mk-font-ui);
  letter-spacing:.04em;text-transform:none;
  /* Never wrap the pill — when the popover squeezes (~600–720px), the
     label text ellipsises instead of breaking onto a second line that
     would push the dots off the header strip. The min-width:0 + flex
     constraints on the inner span let the ellipsis actually engage. */
  white-space:nowrap;max-width:100%;min-width:0;
  flex:0 1 auto;overflow:hidden;
}
.cb-range-step-pill .mi{font-size:14px;flex:0 0 auto}
.cb-range-step-pill > span:not(.mi){
  overflow:hidden;text-overflow:ellipsis;min-width:0;
}
/* At very narrow widths (mobile-V bottom sheet, narrow popover), hide
   the pill's text label entirely so only the phase icon remains — the
   icon alone is enough to convey what step the user is on, and the dots
   carry the position context. */
@media (max-width: 380px){
  .cb-range-step-pill > span:not(.mi){display:none}
  .cb-range-step-pill{padding:0 8px}
}
.cb-range-step-dots{display:inline-flex;align-items:center;gap:6px}
.cb-range-dot{
  width:8px;height:8px;border-radius:999px;
  background:color-mix(in srgb, var(--border) 80%, transparent);
}
.cb-range-dot.on{background:var(--accent)}

/* Color picker — value input for `color` field type.
   Teardrop swatch button + a popover with a native color input, a
   hex text field and a format dropdown. The popover anchors below
   the button; clicking outside closes (handled in JS). */
.cb-color-wrap{ position:relative; display:flex; }
.cb-color-btn{
  flex:1;min-width:0;
  display:flex;align-items:center;gap:10px;
  height:40px;padding:0 12px;border-radius:9px;
  background:var(--bg-input);border:1px solid var(--border);
  color:var(--fg-1);font:500 13px var(--mk-font-ui);
  cursor:pointer;
  transition:border-color var(--mk-t-fast);
}
.cb-color-btn:hover{ border-color:color-mix(in srgb, var(--accent) 35%, var(--border)) }
.cb-color-wrap.open .cb-color-btn{ border-color:var(--accent) }
.cb-color-tear{
  width:18px;height:18px;border-radius:50% 50% 50% 0;
  transform:rotate(-45deg);
  background:transparent;
  box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--border) 80%, transparent);
  flex-shrink:0;
}
.cb-color-val{flex:1;text-align:start;font-variant-numeric:tabular-nums}
.cb-color-val.empty{color:var(--fg-3);font-style:italic}
.cb-color-btn .cs-arrow{color:var(--fg-3)}
.cb-color-pop{
  position:absolute;top:calc(100% + 6px);inset-inline-start:0;
  min-width:260px;z-index:20;
  background:var(--bg-1);border:1px solid var(--border);border-radius:10px;
  box-shadow:var(--shadow-lg);
  padding:10px;
  display:none;flex-direction:column;gap:8px;
}
.cb-color-wrap.open .cb-color-pop{display:flex}
.cb-color-pop-row{
  display:flex;align-items:center;gap:8px;
}
.cb-color-native{
  width:36px;height:30px;border:0;background:transparent;cursor:pointer;
  padding:0;
}
.cb-color-text{
  flex:1;min-width:0;
  height:30px;padding:0 8px;border-radius:7px;
  background:var(--bg-input);border:1px solid var(--border);
  color:var(--fg-1);font:600 12px var(--mk-font-mono);
  text-transform:none;
  font-variant-numeric:tabular-nums;
}
.cb-color-text:focus{outline:none;border-color:var(--accent)}
.cb-color-lbl{
  font:600 10px var(--mk-font-mono);color:var(--fg-3);
  letter-spacing:.08em;text-transform:none;
}
.cb-color-fmt{position:relative;flex:1;min-width:0}
.cb-color-fmt > .cs-btn{
  display:flex;align-items:center;gap:6px;
  height:30px;padding:0 10px;border-radius:7px;
  background:transparent;border:1px solid var(--border);
  color:var(--fg-1);font:600 11px var(--mk-font-mono);
  cursor:pointer;justify-content:space-between;
}
.cb-color-fmt > .cs-btn:hover{border-color:var(--accent)}
.cb-color-fmt > .cs-menu{ min-width:140px }
.cb-color-fmt .cs-item{
  padding:6px 10px;border-radius:6px;cursor:pointer;
  font:600 11px var(--mk-font-mono);
}
.cb-color-fmt .cs-item:hover{background:color-mix(in srgb, var(--accent) 10%, transparent)}
.cb-color-fmt .cs-item.on{background:color-mix(in srgb, var(--accent) 14%, transparent);color:var(--accent)}

/* Map input button + shared spatial-input map modal. */
.cb-map-btn{
  flex:1;min-width:0;
  display:flex;align-items:center;gap:10px;
  height:40px;padding:0 12px;border-radius:9px;
  background:var(--bg-input);border:1px dashed color-mix(in srgb, var(--accent) 36%, var(--border));
  color:var(--fg-1);font:500 13px var(--mk-font-ui);
  cursor:pointer;text-align:start;
  transition:border-color var(--mk-t-fast),background var(--mk-t-fast);
}
.cb-map-btn:hover{
  background:color-mix(in srgb, var(--accent) 6%, transparent);
  border-color:var(--accent);
}
.cb-map-btn .cb-map-i{color:var(--accent);font-size:18px;flex-shrink:0}
.cb-map-btn .cb-map-l{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cb-map-btn .cb-map-l.empty{color:var(--fg-3);font-style:italic}

#mapModal .panel-card-map{
  width:min(720px, calc(100vw - 32px));
  max-height:min(720px, calc(100dvh - 32px));
}
.map-modal-body{display:flex;flex-direction:column;gap:10px;padding:12px}
/* ── B59 — the place search inside the spatial input ──────────────────────
   Pablo: "When I'm in a modal defining a location or zone, I should also have a
   search bar that would check against google maps and help the user find the place
   much more easily." It is an ordinary field + results list, in the app's own field
   grammar; the geocoder behind it is OSM's (the same source as the tiles). */
.map-search{position:relative;display:flex;align-items:center;gap:8px}
.map-search-ic{position:absolute;inset-inline-start:10px;font-size:18px;color:var(--fg-3);pointer-events:none}
.map-search-in{
  flex:1;min-width:0;height:38px;padding-inline:34px 10px;
  border:1px solid var(--border);border-radius:10px;background:var(--bg-1);color:var(--fg-1);
  font:500 13px var(--mk-font-ui);
}
.map-search-in:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px color-mix(in srgb,var(--accent) 18%,transparent)}
.map-search-in::-webkit-search-cancel-button{cursor:pointer}
.map-search-go{
  flex:0 0 auto;height:38px;padding:0 14px;border-radius:10px;cursor:pointer;
  border:1px solid var(--accent);background:var(--accent);color:var(--accent-contrast,#fff);
  font:700 12.5px var(--mk-font-ui);
}
.map-search-go:hover{filter:brightness(1.06)}
/* the results float over the canvas — the map must not jump while you choose */
.map-search-out{
  position:absolute;inset-inline:0;top:calc(100% + 6px);z-index:5;
  max-height:232px;overflow:auto;padding:4px;
  border:1px solid var(--border);border-radius:11px;background:var(--bg-1);
  box-shadow:var(--shadow-lg,0 18px 48px rgba(13,37,48,.24));
}
.map-search-hit{
  display:flex;align-items:center;gap:9px;width:100%;padding:9px 10px;
  border:0;border-radius:8px;background:none;cursor:pointer;text-align:start;
  font:500 12.5px/1.35 var(--mk-font-ui);color:var(--fg-1);
}
.map-search-hit:hover{background:var(--accent-soft);color:var(--accent-text)}
.map-search-hit .mi{font-size:17px;color:var(--fg-3);flex:0 0 auto}
.map-search-hit:hover .mi{color:var(--accent-text)}
.map-search-hit > span:last-child{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.map-search-msg{padding:8px 10px;font:600 11.5px/1.4 var(--mk-font-ui);color:var(--fg-3)}
.map-modal-tools{
  display:flex;flex-wrap:wrap;align-items:center;gap:10px;
}
.map-tool-group{display:inline-flex;align-items:center;gap:6px;padding:4px;border-radius:9px;background:var(--bg-2);border:1px solid var(--border)}
.map-tool-btn{
  display:inline-flex;align-items:center;gap:4px;
  height:30px;padding:0 10px;border-radius:7px;
  background:transparent;border:0;cursor:pointer;
  font:600 11px var(--mk-font-ui);color:var(--fg-2);
  transition:background var(--mk-t-fast),color var(--mk-t-fast);
}
.map-tool-btn .mi{font-size:14px}
.map-tool-btn:hover{background:color-mix(in srgb, var(--accent) 8%, transparent);color:var(--accent)}
.map-tool-btn.on{background:var(--accent);color:var(--accent-fg)}
.map-tool-l{font:600 10px var(--mk-font-mono);color:var(--fg-3);letter-spacing:.08em;text-transform:none}
.map-tool-num{
  width:80px;height:28px;padding:0 8px;border-radius:6px;
  background:var(--bg-input);border:1px solid var(--border);
  color:var(--fg-1);font:600 12px var(--mk-font-mono);
}
.map-tool-num:focus{outline:none;border-color:var(--accent)}
.map-tool-unit{
  height:28px;padding:0 8px;border-radius:6px;
  background:var(--bg-input);border:1px solid var(--border);
  color:var(--fg-1);font:600 11px var(--mk-font-mono);
}
/* B21 C4 — the unit picker is the shared .cs dropdown now */
.map-tool-unit-cs{position:relative;flex:none}
.map-tool-unit-cs > .cs-btn{
  height:28px;padding:0 8px;border-radius:6px;gap:4px;
  background:var(--bg-input);border:1px solid var(--border);
  color:var(--fg-1);font:600 11px var(--mk-font-mono);
}
.map-tool-unit-cs > .cs-btn .cs-arrow{font-size:14px}
.map-tool-unit-cs > .cs-menu{min-width:74px}
.map-tool-clear{
  margin-inline-start:auto;
}
/* B57 (Pablo: "The map we're using for creating polygons is not using the same
   layout as the map outside. Please let's be consistent there will only be one map
   frame component in the whole app") — the frame IS MapView's `.mk-map-canvas` now
   (map-input.js renders it), styled by Components/MapView/map.css. All that is left
   here is the one thing the MODAL decides and the component cannot: how tall the
   frame is inside this dialog. The old border / radius / background declarations
   were the second frame, so they are gone. */
.map-modal-canvas{
  flex:1;min-height:380px;height:380px;
}
/* the ring's first vertex while a polygon is open: the close-the-loop handle.
   MapView's own `.mk-map-leaflet.mk-drawing .leaflet-interactive{cursor:crosshair
   !important}` is (0,2,0) and would otherwise win over this — which is exactly
   wrong on the ONE element in a drawing pane that is a button rather than a
   surface to draw on, so this selector matches its specificity. */
.mk-map-leaflet.mk-drawing .leaflet-interactive.mk-close-handle{ cursor:pointer !important; }
.map-modal-canvas .leaflet-container{
  width:100%;height:100%;background:#0f1620;
}
.map-modal-hint{
  font:500 11px var(--mk-font-ui);color:var(--fg-3);font-style:italic;
  padding:0 2px;
}
.map-modal-fallback{
  display:flex;align-items:center;justify-content:center;height:100%;
  color:var(--fg-3);font:500 12px var(--mk-font-ui);
}

/* WHERE prefix + scope-filter chips in the outer condition row.
   `.fp-expr-where` and `.fp-expr-scope` live as SIBLINGS of `.fp-expr`
   inside `.fp-cond` (see `renderCondRow` in panels.js) so they
   participate in the same flex row as the expression + actions. That
   lets the `· WHERE` keyword pin to a non-shrinking column while only
   the chip's label gets ellipsised when the pill runs out of room
   (audit item B2, fixed 2026-05-22). */
.fp-cond .fp-expr-where{
  flex-shrink:0;
  font:700 10px var(--mk-font-mono);color:var(--fg-3);
  margin-inline:6px 4px;letter-spacing:.06em;
  text-transform:none;
  white-space:nowrap;
}
/* High flex-shrink so the scope chip absorbs nearly all the shrinkage
   when the pill is tight, leaving `.fp-expr` (field/op/value) at or
   near its content size. The chip's inner `.fp-expr-scope-l` handles
   the actual text clipping with `text-overflow:ellipsis`. */
.fp-cond .fp-expr-scope{
  display:inline-flex;align-items:center;
  flex:0 99 auto;min-width:0;
  padding:1px 7px;border-radius:999px;
  background:color-mix(in srgb, var(--accent-2) 16%, transparent);
  border:1px solid color-mix(in srgb, var(--accent-2) 30%, transparent);
  color:color-mix(in srgb, var(--accent-2) 70%, var(--fg-1));
  font:600 10px var(--mk-font-ui);
  margin-inline-end:4px;
}
/* Inner label takes the shrink hit so the chip's pill border stays
   intact even when the text inside is clipped to "…". */
.fp-cond .fp-expr-scope .fp-expr-scope-l{
  min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}

/* Action cluster inside the pill: edit · remove only. The sibling
   add-button moved OUTSIDE the pill (see .fp-act-sib below).
   On desktop (hover-capable), the buttons stay hidden until the row
   is hovered or focused — same pattern as the QF chip kebab, so the
   pill reads as content first and reveals chrome on intent. On touch
   devices (`@media (hover: none)`), they pin visible because there's
   no hover gesture to surface them. */
.fp-cond .fp-acts{display:inline-flex;gap:4px;align-items:center;color:var(--fg-3);flex-shrink:0}
.fp-cond .fp-acts > button{
  background:transparent;border:0;cursor:pointer;
  color:inherit;
  transition:background var(--mk-t-fast),color var(--mk-t-fast),border-color var(--mk-t-fast),opacity var(--mk-t-fast),width var(--mk-t-fast);
}
.fp-cond .fp-acts .fp-act-icon{
  width:0;height:24px;border-radius:6px;
  opacity:0;overflow:hidden;padding:0;
  display:inline-flex;align-items:center;justify-content:center;
}
.fp-cond:hover .fp-acts .fp-act-icon,
.fp-cond:focus-within .fp-acts .fp-act-icon{width:24px;opacity:1}
.fp-cond .fp-acts .fp-act-icon .mi{font-size:14px}
.fp-cond .fp-acts .fp-act-icon:hover{background:var(--bg-3);color:var(--fg-1)}
.fp-cond .fp-acts .fp-act-x:hover{color:var(--mk-danger)}
/* Touch / no-hover devices: pin the action buttons visible so users
   without a hover gesture still see them at rest. */
@media (hover: none){
  .fp-cond .fp-acts .fp-act-icon{width:24px;opacity:.7}
}

/* Per-row single sibling add button — sits to the trailing edge of the
   row, outside the pill. Per the conditions_mockup rule, exactly ONE
   such button shows per row (the renderer picks AND vs OR based on
   children + this row's own conjunction). Inner label is wrapped in
   .fp-sib-l with a fixed width so "AND" / "Y" / "و" all consume the
   same horizontal space, keeping the button column aligned across rows
   in every language. */
.fp-row .fp-act-sib{
  display:inline-flex;align-items:center;justify-content:center;gap:3px;
  height:24px;padding:0 8px;border-radius:6px;
  background:transparent;
  border:1px dashed color-mix(in srgb, var(--accent-text) 45%, transparent);
  color:var(--accent-text);font:600 9px var(--mk-font-mono);letter-spacing:.06em;
  white-space:nowrap;cursor:pointer;flex-shrink:0;
  transition:
    background var(--mk-t-fast),
    border-color var(--mk-t-fast),
    border-style var(--mk-t-fast),
    color var(--mk-t-fast),
    transform var(--mk-t-fast),
    box-shadow var(--mk-t-fast);
}
.fp-row .fp-act-sib .mi{font-size:11px}
/* Venn-diagram conjunction glyph (Pablo 2026-06-21). currentColor; OR shades
   both lobes, AND only the lens. Sits inline before the AND/OR label. */
.fp-venn{flex-shrink:0;display:inline-block;vertical-align:middle}
.fp-conj-out .fp-venn{height:13px;width:auto;color:var(--accent-text)}
.fp-conj-out .fp-conj-t{margin-inline-start:5px}
/* C31 (Pablo 2026-06-22): inside an AND-parent row the AND/OR word labels
   crowded/clipped against the nested children — show ONLY the venn icons
   here (the icon already encodes AND vs OR; title/aria keep it accessible). */
/* Pablo 2026-06-22 (B8-28/B8-29): the +AND/+OR sibling label was hidden ONLY
   on rows that have an AND child, so some sibling buttons showed "AND"/"OR"
   text and others were glyph-only — "some items have labels, some don't… this
   looks extremely misaligned." Keep the conjunction COLUMN text hidden there
   (the rail conveys nesting) but ALWAYS show the sibling-button label so every
   .fp-act-sib and .fp-add reads identically and the button column stays
   aligned across rows. */
/* C31 + B9-26 (Pablo 2026-06-22): the AND/OR WORD label to the left of the
   indentation rail showed on some rows (plain siblings) but not others
   (has-and-child) — visibly inconsistent. Hide the word label on EVERY row so
   the gutter shows the venn icon only, uniformly. The +AND/+OR sibling/add
   buttons keep their labels (.fp-sib-l), unaffected. */
.fp-row .fp-conj-out .fp-conj-t{display:none}
.fp-act-sib .fp-venn,.fp-add .fp-venn{height:12px;width:auto}
.fp-row .fp-act-sib .fp-sib-l{min-width:22px;text-align:start}
.fp-row .fp-act-sib:hover{background:color-mix(in srgb, var(--accent) 10%, transparent)}
.fp-row .fp-act-sib.drag-over{
  background:color-mix(in srgb, var(--accent) 26%, transparent);
  border-style:solid;border-color:var(--accent);color:var(--accent);
  transform:scale(1.06);
  box-shadow:0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}

/* End-of-group add button: appears at the tail of a group to add a
   sibling at the SAME level the group represents. Lands at the START
   of the condition box column for that level — that's the conj-out
   width + gap past the level's indent, so the dashed +AND/+OR pill
   lines up under the leftmost edge of the conditions it would join.
   For a flush-left level-0 tree (no conj rows), the button sits at
   x=0 instead — see .fp-tree:not(.has-level0-conj) override below.
   Inner label uses .fp-sib-l for the same equal-width treatment as
   the per-row buttons, keeping the +AND / +OR column aligned in
   every language. */
.fp-add{
  display:inline-flex;align-items:center;justify-content:center;gap:4px;
  padding:4px 10px;border-radius:6px;
  background:transparent;border:1px dashed color-mix(in srgb, var(--accent-text) 50%, transparent);
  color:var(--accent-text);font:600 10px var(--mk-font-mono);letter-spacing:.06em;
  white-space:nowrap;cursor:pointer;align-self:flex-start;
  transition:
    background var(--mk-t-fast),
    border-color var(--mk-t-fast),
    border-style var(--mk-t-fast),
    color var(--mk-t-fast),
    transform var(--mk-t-fast),
    box-shadow var(--mk-t-fast);
  /* level 0 default; deeper levels override margin-inline-start below */
  margin-inline-start:calc(var(--fp-conj-w) + var(--fp-gap));
}
.fp-add[data-level="1"]{margin-inline-start:calc(1 * var(--fp-step) + var(--fp-conj-w) + var(--fp-gap))}
.fp-add[data-level="2"]{margin-inline-start:calc(2 * var(--fp-step) + var(--fp-conj-w) + var(--fp-gap))}
.fp-add[data-level="3"]{margin-inline-start:calc(3 * var(--fp-step) + var(--fp-conj-w) + var(--fp-gap))}
/* Single-condition tree (no level-0 conj rows): the lone +OR/+AND sits
   flush left so it lines up with the condition above. Mirrors the
   conditions_mockup-single layout. */
.fp-tree:not(.has-level0-conj) .fp-add[data-level="0"]{margin-inline-start:0}
.fp-add:hover{background:color-mix(in srgb, var(--accent) 8%, transparent)}
.fp-add .mi{font-size:13px}
.fp-add .fp-sib-l{min-width:22px;text-align:start}
.fp-add.drag-over{
  background:color-mix(in srgb, var(--accent) 26%, transparent);
  border-style:solid;border-color:var(--accent);color:var(--accent);
  transform:scale(1.06);
  box-shadow:0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}

/* Compact mode for the per-row +AND / +OR sibling button: the button
   sits on the trailing edge of every saved row and competes with the
   `.fp-cond` pill for horizontal space, so it collapses to icon-only
   well before the rest of the layout starts to feel tight. The dashed
   border + accent colour + the `add` material icon still read as
   "create a sibling", and the `title` / aria-label preserve the AND
   vs OR intent for hover + a11y. The hidden `.fp-sib-l` keeps its
   place in the DOM so a wider re-render restores the label without
   any state churn. */
/* Container-narrow tweaks (≤640px) — the AND/OR label STAYS visible
   at every viewport (Pablo confirmed) and the edit/delete actions
   STAY visible too. Truncation moves into the .fp-expr instead — the
   field name + operator + value ellipsise when the row is tight,
   while the row chrome (conj, actions) never disappears.
   The base rule's `min-width:22px` on `.fp-sib-l` stays in force here
   too — without it, "AND" (≈18px) and "OR" (≈12px) render at different
   natural widths, which shifts each pill's trailing edge by ~6px
   row-to-row. The label column has to consume the same horizontal
   space for the pill column to stay flush right (Pablo audit
   2026-05-27). */
@container fp-tree (max-width: 640px){
  .fp-row .fp-act-sib{padding:0 7px;gap:3px}
  .fp-row .fp-act-sib .mi{font-size:12px}

  /* Actions cluster always pinned to the row's trailing edge; the
     expression takes the hit when space is tight. */
  .fp-cond{flex-wrap:nowrap}
  .fp-cond .fp-actions{flex-shrink:0;margin-inline-start:auto}
  .fp-cond .fp-expr{
    flex:1 1 0;min-width:0;
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  }
}

/* End-of-group +AND / +OR placeholders sit on their own row below the
   group, so they don't compete with a saved row's expression. They
   only need to collapse when the tree is genuinely narrow (mobile /
   tightly stacked nesting). */
/* Container-narrow tweaks — the AND/OR label STAYS visible at every
   viewport, including the trailing +Add button (Pablo audit 2026-05-26
   confirmed this should be invariant). Only padding/gap/icon size
   tighten as the row gutter shrinks. */
@container fp-tree (max-width: 520px){
  .fp-add{padding:4px 8px;gap:4px}
  .fp-add .mi{font-size:14px}
  .fp-add .fp-sib-l{font-size:11px;letter-spacing:.02em}
}

/* At narrow tree widths the saved-row pill itself runs out of room
   for `Field op value` on a single line. Switch the pill to a wrapping
   flex row and allow the expression to wrap so the operator + value
   drop to a second line instead of getting clipped with an ellipsis.
   The icon column (edit / remove) anchors to the top of the now-multi-
   line pill so it doesn't drift to the middle of the row.
   `flex: 1 1 0` overrides the wider rule's `flex: 1 0 auto` so the
   expr is allowed to shrink AND wrap (basis 0 makes width depend on
   available space, not content max-width). For scope rows the WHERE
   prefix + scope chip wrap onto a separate line below the expr. */
@container fp-tree (max-width: 460px){
  /* Row-level alignment also flips to flex-start so the surrounding
     items (OR/AND conjunction label, +AND/+OR sibling button) anchor
     to the TOP of the row, matching the pill's first line. Without
     this, a multi-line pill would push its OR-gutter label and
     trailing sibling button to the row's vertical centre — visually,
     the right column then reads as a zigzag because each row's
     button sits at a different y-offset depending on pill height.
     `padding-top: 8px` nudges the label/button down to align with
     the FIRST line of the pill (accounting for the pill's own 6px
     top padding + half line-height) so single-line rows still feel
     centred. */
  .fp-row{align-items:flex-start;padding-top:8px}
  .fp-conj-out{align-self:flex-start;align-items:flex-start;padding-top:8px}
  .fp-row .fp-act-sib{align-self:flex-start;margin-top:8px}
  /* Pull the end-of-group +AND/+OR placeholder back into the same
     vertical rhythm — without this, it'd sit at the row's flex-start
     edge (no padding-top) above the actual row content. */
  .fp-add{margin-top:0}
  .fp-cond{align-items:flex-start;flex-wrap:wrap}
  .fp-cond .fp-expr{
    flex:1 1 0;
    white-space:normal;
    overflow:visible;
    text-overflow:clip;
    line-height:1.45;
    overflow-wrap:break-word;
  }
  /* Operator and value never break mid-word — "TRUE" / "BETWEEN" / "10.00"
     stay intact even when the parent expression is narrow enough to need
     overflow-wrap. They'll just drop to a fresh line as a whole. */
  .fp-cond .fp-expr .fp-expr-op,
  .fp-cond .fp-expr .fp-expr-val{
    white-space:nowrap;
    overflow-wrap:normal;
    word-break:keep-all;
  }
  /* Once the row wraps, the WHERE prefix + scope chip drop to a
     dedicated wrap line below the expression. Pull them to the start
     of that line so they sit under the expression rather than under
     the action cluster. */
  .fp-cond .fp-expr-where{flex-basis:100%;margin-inline-start:0;margin-top:2px}
  .fp-cond .fp-acts{align-self:flex-start;margin-top:1px;margin-inline-start:auto}
}

/* During a drag, the +AND/+OR placeholders (.fp-add and per-row
   .fp-act-sib) are the ONLY drop targets — between-row drop zones
   were noisy and ambiguous about which group a drop joined, so the
   add buttons now own the affordance. Highlighted by their existing
   .drag-over rule when a draggable is hovered over them. */
.fp-tree.dragging .fp-add,
.fp-tree.dragging .fp-act-sib{
  border-style:solid;
  background:color-mix(in srgb, var(--accent) 4%, transparent);
}

/* Hide the per-row edit / X buttons on the source row AND every row
   in its dragging subtree — they're not interactable mid-drag and
   showing them just adds visual noise to the floating ghost. The chip
   strip in the quick-filters section gets the same treatment. */
.fp-cond.dragging .fp-acts,
.fp-row.subtree-dragging .fp-cond .fp-acts,
.fp-chip.dragging .fp-chip-edit,
.fp-chip.dragging .fp-chip-del{
  display:none !important;
}

/* Just-dropped flash — a brief glow around the row(s) that just moved
   so the user can spot where the drop landed without having to scan
   the tree. Animation self-removes (animationend in panels.js). */
.fp-row.just-dropped .fp-cond{
  animation: drop-glow 1.4s var(--mk-ease);
}
@keyframes drop-glow {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 70%, transparent), 0 0 0 0 color-mix(in srgb, var(--accent) 30%, transparent); }
  18%  { box-shadow: 0 0 0 2px var(--accent), 0 0 0 8px color-mix(in srgb, var(--accent) 28%, transparent); }
  50%  { box-shadow: 0 0 0 2px var(--accent), 0 0 0 12px color-mix(in srgb, var(--accent) 18%, transparent); }
  100% { box-shadow: 0 0 0 0 transparent, 0 0 0 0 transparent; }
}

/* Subtree bubble — inserted into a dragged row's pill when the row has
   descendants, so the floating ghost carries a "+N children" tag and
   the user understands they're moving the whole block, not just one
   condition. Sits between the expression and the action cluster. */
.fp-cond .fp-subtree-bubble{
  display:inline-flex;align-items:center;gap:4px;
  height:20px;padding:0 8px;border-radius:999px;
  background:color-mix(in srgb, var(--accent) 22%, transparent);
  color:var(--accent);
  font:700 11px var(--mk-font-mono);
  flex-shrink:0;
  margin-inline-start:6px;
}
.fp-cond .fp-subtree-bubble .mi{font-size:13px}

/* The dragged head row's own sibling button is invalid (would mean
   "make myself my own sibling"); fade + freeze it the same way the
   descendant siblings are. The :has() selector targets the row that
   holds the currently-dragged .fp-cond. */
.fp-row:has(.fp-cond.dragging) .fp-act-sib{
  opacity:.35;
  pointer-events:none;
  filter:grayscale(.4);
}
/* +AND/+OR placeholders flagged at dragstart as landing INSIDE the
   dragged subtree — circular drop targets. Pointer-events suppression
   stops the drag-over visual; the dim + cross cursor reads as "not
   here". */
.fp-tree.dragging .fp-add.drag-disabled{
  opacity:.3;
  pointer-events:none;
  filter:grayscale(.4);
  cursor:not-allowed;
}

/* Descendant rows of a dragged subtree — locked out of drop targeting
   and visually demoted so the user can see "these come along, you
   can't drop on them". The conj label fades with the rest. */
.fp-row.subtree-dragging .fp-cond,
.fp-row.subtree-dragging .fp-conj-out,
.fp-row.subtree-dragging .fp-act-sib{
  opacity:.35;
  pointer-events:none;
  filter:grayscale(.4);
  transition:opacity var(--mk-t-fast), filter var(--mk-t-fast);
}

/* ─────────────────────────────────────────────────────────────────
   CONDITION BUILDER MODAL — typed drill-down.
   - .cb-section is one logical block (Field / Operator / Value).
   - .cb-path is the breadcrumb of picked steps; each .cb-crumb shows
     a type icon + label + X to remove this step and everything after.
   - .cb-step is a .cs custom-select used for "what's next?" — fields
     picker, sub-part picker, aggregator picker, operator picker, and
     the single-select value picker. Reusing .cs keeps the entire
     modal consistent with the rest of the shell (no native <select>).
   - .cb-multi is the chip-grid value picker for IN / NOT IN.
   - .cb-range is the two-input layout for BETWEEN / OUTSIDE.
   ───────────────────────────────────────────────────────────────── */
#condBuilderModal .panel-card{
  width:min(760px, calc(100vw - 32px));
  min-height:min(540px, calc(100dvh - 32px));
  max-height:calc(100dvh - 32px);
  /* Let the field-picker dropdown menus and date popover escape the
     card's rounded corners — without `overflow:visible` they'd be
     clipped to whatever fits inside the card, which is exactly the
     "dropdown scrolls instead of revealing options" problem. The
     panel-body itself still scrolls vertically if the body content
     gets too tall. */
  overflow:visible;
  display:flex;flex-direction:column;
}
#condBuilderModal .panel-body{
  padding:20px 24px;
  overflow-y:auto;overflow-x:visible;
  flex:1;min-height:0;
}

/* Section state — required vs error. The required state paints a soft
   yellow ring on the picker / input inside the section so the user
   sees what's still needed. The error state paints a red ring AND
   surfaces an error description below. Both states are mutually
   exclusive per-section (error wins). */
.cb-section-hd{
  display:flex;align-items:center;gap:6px;
}
/* Trailing controls (the Static/Field value-source toggle, the REQUIRED
   pill) push to the row's end; the info icon stays glued to the label
   instead of being flung to the right by space-between. Pablo 2026-06-01. */
.cb-section-hd .cb-val-source,
.cb-section-hd .cb-required-tag{margin-inline-start:auto}
.cb-required-tag{
  display:inline-flex;align-items:center;height:18px;padding:0 8px;
  border-radius:999px;
  background:color-mix(in srgb, var(--mk-warning) 18%, transparent);
  color:var(--mk-warning);
  font:700 10px var(--mk-font-ui);letter-spacing:.01em;text-transform:none;
}
.cb-section-error{
  display:flex;align-items:center;gap:6px;
  font:500 12px var(--mk-font-ui);color:var(--mk-danger);
  margin-top:2px;
}
.cb-section-error::before{
  content:"error";content:"error" / "";font-family:"Material Symbols Rounded";font-size:14px;
  font-variation-settings:'opsz' 20, 'wght' 500, 'GRAD' 0, 'FILL' 1;
}

/* Static / Field source toggle — sits in the Value section header so
   the user can swap a literal for a reference to another field of the
   same type without leaving the row. Disabled when no candidate field
   exists in scope (collectFieldSourceCandidates returned []). */
.cb-val-source{
  display:inline-flex;
  border-radius:8px;overflow:hidden;
  border:1px solid var(--border);
  background:var(--bg-input);
  flex-shrink:0;
  margin-inline-start:auto;
}
.cb-val-source button{
  display:inline-flex;align-items:center;gap:4px;
  background:transparent;border:0;
  padding:4px 9px;height:26px;
  font:600 10px var(--mk-font-mono);color:var(--fg-2);
  cursor:pointer;letter-spacing:.04em;
  transition:background var(--mk-t-fast),color var(--mk-t-fast);
}
.cb-val-source button .mi{font-size:13px}
.cb-val-source button.on{background:var(--accent);color:var(--accent-fg)}
.cb-val-source button:not(.on):not([disabled]):hover{
  background:color-mix(in srgb, var(--accent) 10%, transparent);
}
.cb-val-source button[disabled]{
  opacity:.4;cursor:not-allowed;
}
.cb-val-source.is-disabled{opacity:.55}

/* NOW() marker — shown when the value source is "Now". A valueless,
   read-only chip making clear the comparison resolves against the current
   moment at evaluation time (Pablo 2026-06-01). */
.cb-now-value{
  display:flex;align-items:center;gap:8px;
  min-height:40px;padding:0 12px;border-radius:9px;
  background:color-mix(in srgb, var(--accent) 8%, var(--bg-input));
  border:1px solid color-mix(in srgb, var(--accent) 30%, var(--border));
  color:var(--fg-1);font:600 13px var(--mk-font-ui);
}
.cb-now-value .mi{font-size:18px;color:var(--accent)}
.cb-now-value .cb-now-fn{font:700 12px var(--mk-font-mono);color:var(--accent)}
.cb-now-value .cb-now-hint{
  margin-inline-start:auto;
  font:500 11px var(--mk-font-ui);color:var(--fg-3);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;
}

/* Field-source range — TWO independent field-pickers (start + end) for
   BETWEEN / OUTSIDE. Stacked on narrow widths, side-by-side on wider
   ones; the arrow_forward glyph between them reads as "from … to …". */
.cb-range-field-picker{
  display:flex;flex-direction:column;gap:10px;
  width:100%;
}
.cb-range-field-picker .cb-range-slot{
  display:flex;flex-direction:column;gap:6px;
  min-width:0;
}
.cb-range-field-picker .cb-range-l{
  font:600 11px var(--mk-font-ui);color:var(--fg-3);
}
.cb-range-field-picker .cb-range-sep{
  font-size:18px;color:var(--fg-3);align-self:center;
}
html[dir="rtl"] .cb-range-field-picker .cb-range-sep{transform:scaleX(-1)}

/* ── Per-endpoint temporal range builder ──────────────────────────
   Start + End each become an independent endpoint with its OWN
   Static/Now/Field source toggle and the matching input (date picker /
   NOW chip / field-path builder). Pablo 2026-06-01 (expanded scope). */
.cb-range-ep-builder{
  display:flex;flex-direction:column;gap:12px;
  width:100%;
}
.cb-range-ep-builder .cb-range-slot{
  display:flex;flex-direction:column;gap:6px;
  min-width:0;
}
.cb-range-ep-builder .cb-range-l{
  font:600 11px var(--mk-font-ui);color:var(--fg-3);
}
.cb-range-ep-builder .cb-range-sep{
  font-size:18px;color:var(--fg-3);align-self:center;
}
html[dir="rtl"] .cb-range-ep-builder .cb-range-sep{transform:scaleX(-1)}
.cb-range-ep{
  display:flex;flex-direction:column;gap:8px;min-width:0;
}
.cb-range-ep-input{min-width:0}
/* Per-endpoint source toggle — same chrome as the global .cb-val-source
   but left-aligned under its endpoint label (no auto margin). */
.cb-ep-source{
  display:inline-flex;align-self:flex-start;
  border-radius:8px;overflow:hidden;
  border:1px solid var(--border);
  background:var(--bg-input);
  flex-shrink:0;
}
.cb-ep-source button{
  display:inline-flex;align-items:center;gap:4px;
  background:transparent;border:0;
  padding:4px 9px;height:26px;
  font:600 10px var(--mk-font-mono);color:var(--fg-2);
  cursor:pointer;letter-spacing:.04em;
  transition:background var(--mk-t-fast),color var(--mk-t-fast);
}
.cb-ep-source button .mi{font-size:13px}
.cb-ep-source button.on{background:var(--accent);color:var(--accent-fg)}
.cb-ep-source button:not(.on):not([disabled]):hover{
  background:color-mix(in srgb, var(--accent) 10%, transparent);
}
.cb-ep-source button[disabled]{opacity:.4;cursor:not-allowed}

/* Field-source list — N field-pickers stacked, each with a remove
   affordance. The Add-another button at the end uses the same dashed
   accent style as `.fp-add` so the chrome reads consistent across the
   Filter panel. */
.cb-list-field-picker{
  display:flex;flex-direction:column;gap:8px;width:100%;
}
.cb-list-row{
  /* Center the remove-X against the field-picker box (min 46px tall, taller
     when the path wraps) instead of pinning it to the top — Pablo 2026-06-02
     W2 #7: the X wasn't vertically centered against its row. */
  display:flex;align-items:center;gap:6px;
}
.cb-list-row .cb-field-picker{flex:1;min-width:0}
.cb-list-rm{
  display:inline-flex;align-items:center;justify-content:center;
  width:28px;height:28px;border-radius:8px;flex-shrink:0;
  background:var(--bg-input);border:1px solid var(--border);color:var(--fg-3);
  cursor:pointer;
  transition:border-color var(--mk-t-fast),color var(--mk-t-fast);
}
.cb-list-rm:hover:not([disabled]){border-color:var(--accent);color:var(--accent)}
.cb-list-rm[disabled]{opacity:.4;cursor:not-allowed}
.cb-list-rm .mi{font-size:14px}
.cb-list-add{
  display:inline-flex;align-items:center;gap:6px;align-self:flex-start;
  padding:6px 12px;border-radius:8px;
  background:transparent;border:1px dashed color-mix(in srgb, var(--accent) 55%, transparent);
  color:var(--accent);
  font:600 12px var(--mk-font-ui);cursor:pointer;
  transition:background var(--mk-t-fast);
}
.cb-list-add:hover{background:color-mix(in srgb, var(--accent) 10%, transparent)}
.cb-list-add:disabled,.cb-list-add.is-disabled{opacity:.45;pointer-events:none;cursor:not-allowed;color:var(--fg-3);border-color:var(--border);background:transparent}
.cb-list-add .mi{font-size:14px}

/* ── Formula builder (Wave 4 #10) ──────────────────────────────────
   An ordered run of operand chips (static number OR a field path with a
   numeric aggregator) joined by + − × ÷, with auto-balanced nested GROUP
   boxes for explicit grouping and a live canonical "= …" preview. Used on
   BOTH the reference (field section) and the value side. The math reads
   left-to-right in every language, so the sequence + preview are pinned
   LTR (operand ORDER is significant for − and ÷). */
.cb-formula{display:flex;flex-direction:column;gap:10px;width:100%;min-width:0}
.cb-formula-seq{
  display:flex;flex-wrap:wrap;align-items:center;gap:9px 12px;
  direction:ltr;min-width:0;
}
.cb-formula-empty{
  font:500 12px var(--mk-font-ui);color:var(--fg-3);font-style:italic;
}
.cb-f-operand{
  display:inline-flex;align-items:center;gap:4px;min-width:0;
  position:relative;
}
.cb-f-operand .cb-val-field-picker{min-width:0}
/* Number operand — compact numeric input + remove. */
.cb-f-num-input{
  width:84px;height:32px;padding:0 8px;border-radius:8px;
  background:var(--bg-input);border:1px solid var(--border);color:var(--fg-1);
  font:600 13px var(--mk-font-mono);text-align:center;
  transition:border-color var(--mk-t-fast),box-shadow var(--mk-t-fast);
}
.cb-f-num-input:focus{
  outline:none;border-color:var(--accent);
  box-shadow:0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}
/* Per-operand remove — a corner "dismiss" badge attached to the chip's
   top-inline-end, NOT inline. This lifts it out of the operator lane so
   its close glyph can't be misread as a × (multiply) operator. */
.cb-f-rm{
  display:inline-flex;align-items:center;justify-content:center;
  width:22px;height:22px;border-radius:6px;flex-shrink:0;
  background:transparent;border:1px solid transparent;color:var(--fg-3);
  cursor:pointer;transition:border-color var(--mk-t-fast),color var(--mk-t-fast),background var(--mk-t-fast);
}
.cb-f-rm:hover{border-color:var(--accent);color:var(--accent);background:color-mix(in srgb, var(--accent) 8%, transparent)}
.cb-f-rm .mi{font-size:14px}
.cb-f-operand > .cb-f-rm{
  position:absolute;top:-8px;inset-inline-end:-8px;z-index:3;
  width:18px;height:18px;border-radius:50%;
  background:var(--bg-2);border:1px solid var(--border);color:var(--fg-2);
  box-shadow:0 1px 3px rgba(0,0,0,.28);opacity:.85;
  transition:opacity var(--mk-t-fast),background var(--mk-t-fast),border-color var(--mk-t-fast),color var(--mk-t-fast);
}
.cb-f-operand > .cb-f-rm .mi{font-size:13px}
/* Always visible (discoverable + touch-safe); brightens on hover/focus. */
.cb-f-operand:hover > .cb-f-rm,
.cb-f-operand:focus-within > .cb-f-rm,
.cb-f-operand > .cb-f-rm:focus-visible{opacity:1}
.cb-f-operand > .cb-f-rm:hover{background:var(--accent);border-color:var(--accent);color:var(--accent-fg)}
/* Operator selector — segmented + − × ÷, the picked one filled accent. */
.cb-f-op{
  display:inline-flex;border-radius:8px;overflow:hidden;
  border:1px solid var(--border);background:var(--bg-input);flex-shrink:0;
}
.cb-f-op button{
  width:30px;height:32px;background:transparent;border:0;
  font:700 18px var(--mk-font-mono);color:var(--fg-2);cursor:pointer;
  transition:background var(--mk-t-fast),color var(--mk-t-fast);
}
.cb-f-op button + button{border-inline-start:1px solid var(--border)}
.cb-f-op button.on{background:var(--accent);color:var(--accent-fg)}
.cb-f-op button:not(.on):hover{background:color-mix(in srgb, var(--accent) 10%, transparent)}
/* Locked joiner — a level carries ONE operation; rows after the first
   show the level's glyph as a static tag (width matches the segmented
   selector so operands align). */
.cb-f-op.cb-f-op-static{
  width:34px;height:34px;justify-content:center;align-items:center;
  background:color-mix(in srgb, var(--accent) 7%, var(--bg-input));
  color:var(--accent-text);font:700 18px var(--mk-font-mono);
  height:32px;cursor:default;flex-shrink:0;
}
/* Group box — auto-balanced nested sub-expression. Tinted, rounded, with
   big parens framing the body and corner ungroup / remove actions. */
.cb-f-group{
  align-items:stretch;
  padding:6px 8px;border-radius:12px;
  background:color-mix(in srgb, var(--accent) 6%, var(--bg-input));
  border:1px solid color-mix(in srgb, var(--accent) 32%, var(--border));
  gap:6px;
}
.cb-f-group-paren{
  align-self:center;
  font:700 20px var(--mk-font-mono);color:color-mix(in srgb, var(--accent) 70%, var(--fg-2));
  user-select:none;
}
.cb-f-group-body{min-width:0;display:flex;align-items:center;flex-wrap:wrap;gap:9px 12px}
/* Box controls (ungroup + remove) — a hover-reveal cluster pinned to the
   group's top-inline-end corner, matching the per-operand dismiss badge so
   it reads as box chrome, not math. */
.cb-f-group-acts{
  position:absolute;top:-9px;inset-inline-end:10px;z-index:3;
  display:inline-flex;align-items:center;gap:3px;
  opacity:.85;transition:opacity var(--mk-t-fast);
}
.cb-f-group:hover > .cb-f-group-acts,
.cb-f-group:focus-within > .cb-f-group-acts{opacity:1}
.cb-f-group-acts .cb-f-ungroup,
.cb-f-group-acts > .cb-f-rm{
  position:static;opacity:1;
  display:inline-flex;align-items:center;justify-content:center;
  width:18px;height:18px;border-radius:50%;flex-shrink:0;
  background:var(--bg-2);border:1px solid var(--border);color:var(--fg-2);
  box-shadow:0 1px 3px rgba(0,0,0,.28);cursor:pointer;
  transition:background var(--mk-t-fast),border-color var(--mk-t-fast),color var(--mk-t-fast);
}
.cb-f-group-acts .cb-f-ungroup:hover,
.cb-f-group-acts > .cb-f-rm:hover{background:var(--accent);border-color:var(--accent);color:var(--accent-fg)}
.cb-f-group-acts .cb-f-ungroup .mi{font-size:13px}
/* Add buttons (number / field / group) — dashed accent, like .cb-list-add. */
.cb-formula-adds{display:inline-flex;flex-wrap:wrap;gap:5px}
.cb-f-add{
  display:inline-flex;align-items:center;gap:4px;
  padding:5px 9px;border-radius:8px;
  background:transparent;border:1px dashed color-mix(in srgb, var(--accent) 50%, transparent);
  color:var(--accent);font:600 11px var(--mk-font-ui);cursor:pointer;
  transition:background var(--mk-t-fast);
}
.cb-f-add:hover{background:color-mix(in srgb, var(--accent) 10%, transparent)}
.cb-f-add .mi{font-size:14px}
/* Warning state: composition not yet valid (needs ≥2 complete sources) —
   the +Add source button goes yellow to prompt the user. Pablo 2026-06-19. */
.cb-f-add.is-warn{
  color:var(--mk-warning);
  border-color:color-mix(in srgb, var(--mk-warning) 60%, var(--border));
  background:color-mix(in srgb, var(--mk-warning) 10%, transparent);
}
.cb-f-add.is-warn:hover{background:color-mix(in srgb, var(--mk-warning) 18%, transparent)}
/* Disabled add (a prior source is still half-picked) — can't start another. */
.cb-f-add:disabled,.cb-f-add.is-disabled{opacity:.45;pointer-events:none;cursor:not-allowed;color:var(--fg-3);border-color:var(--border);background:transparent}
/* C7 — a dropdown with only one option renders view-only: the value shows,
   but there's no chevron and it isn't clickable (the choice is forced). */
.cs.cs-single{pointer-events:none}
.cs.cs-single > .cs-btn{cursor:default}
.cs.cs-single .cs-arrow{display:none}
/* C11 — an options-less dropdown is inert (no chevron, not clickable). */
.cs.cs-empty{pointer-events:none;opacity:.6}
.cs.cs-empty .cs-arrow{display:none}

/* Wave C — + Math / Remove math affordances under a number/datetime leaf.
   + Math turns the drilled leaf into the first operand of a math
   expression; Remove math drops back to the plain breadcrumb. They sit
   on their own row in the FIELD section (flex column). */
.cb-math-add,.cb-math-exit{
  display:inline-flex;align-items:center;gap:5px;align-self:flex-start;
  padding:5px 10px;border-radius:8px;cursor:pointer;
  font:600 11px var(--mk-font-ui);transition:background var(--mk-t-fast),color var(--mk-t-fast);
}
.cb-math-add .mi,.cb-math-exit .mi{font-size:14px}
.cb-math-add{
  background:transparent;color:var(--accent-text);
  border:1px dashed color-mix(in srgb, var(--accent-text) 50%, transparent);
}
.cb-math-add:hover{background:color-mix(in srgb, var(--accent) 10%, transparent)}
/* + Math is a dropdown now — the menu prompts WHICH manipulation to
   apply (+ − × ÷) before entering math mode. */
.cb-math-add-cs{position:relative;display:inline-flex;align-self:flex-start}
.cb-math-add-cs > .cs-btn.cb-math-add{height:auto}
.cb-math-add-cs > .cs-menu{min-width:190px}
.cb-f-menu-glyph{
  width:20px;flex-shrink:0;text-align:center;
  font:700 13px var(--mk-font-mono);color:var(--accent-text);
}
.cb-math-exit{
  background:transparent;border:1px solid var(--border);color:var(--fg-3);
}
.cb-math-exit:hover{background:color-mix(in srgb, var(--fg-3) 10%, transparent);color:var(--fg-1)}

/* ── Hinge grammar — Session body + Concatenate/Aggregate rows (Wave B)
   The hinge / session / row-source pickers are plain .cs dropdowns and
   inherit the base chrome. These rules just lay out the bodies: a
   session root line, and the +Add row builders (one flex row per
   source, breadcrumb flexes, remove-X pinned at the end — same model as
   .cb-list-row). */
.cb-session-body{display:flex;flex-direction:column;gap:10px;width:100%;min-width:0}
.cb-session-root{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.cb-session-root-ic{font-size:18px;color:var(--fg-3)}
/* Hinge + session-target rendered as LEADING breadcrumb segments inside the
   .cb-field-picker box. Pablo 2026-06-21: these are just regular steps in the
   guided input — nothing special — so they render identically to the plain
   field segments that follow (no accent tint). Only the open state shows the
   shared accent border every .cs gets. */
.cb-field-seg.cb-hinge-seg.open > .cs-btn,
.cb-field-seg.cb-vhinge-seg.open > .cs-btn,
.cb-field-seg.cb-sess-seg.open > .cs-btn,
.cb-field-seg.cb-vsess-seg.open > .cs-btn{
  background:var(--bg-1);border-color:var(--accent);
}
/* The hinge-only box for Concatenate / Aggregate (rows render below it). */
.cb-field-picker.cb-hinge-lead{min-height:0}
.cb-rows{display:flex;flex-direction:column;gap:8px;width:100%;min-width:0}
.cb-row{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.cb-row .cb-row-field-picker{flex:1 1 0;min-width:0}
/* C21 (Pablo 2026-06-22): when a coalesce/agg path is expanded it wrapped
   BELOW the rank ordinal. Keep the picker on the same line as the "1" — it
   shrinks and wraps its OWN chevron segments internally instead of dropping
   under the number. (flex-basis 0 so a wide flex-basis can't force the wrap.) */
.cb-concat-row > .cb-field-picker,
.cb-agg-row > .cb-field-picker,
.cb-concat-row > .cb-row-static-box,
.cb-agg-row > .cb-row-static-box{flex:1 1 0;min-width:0}
.cb-row-empty{font:500 12px var(--mk-font-ui);color:var(--fg-3);font-style:italic}
.cb-row-note{
  font:500 11px var(--mk-font-ui);color:var(--fg-3);font-style:italic;
  padding-inline-start:2px;
}
.cb-row-adds{display:inline-flex;flex-wrap:wrap;gap:6px;align-self:flex-start}
.cb-row-rm{
  display:inline-flex;align-items:center;justify-content:center;
  width:28px;height:28px;border-radius:8px;flex-shrink:0;
  background:var(--bg-input);border:1px solid var(--border);color:var(--fg-3);
  cursor:pointer;
  transition:border-color var(--mk-t-fast),color var(--mk-t-fast);
}
.cb-row-rm:hover{border-color:var(--accent);color:var(--accent)}
.cb-row-rm .mi{font-size:14px}
.cb-concat-static-input{
  flex:1 1 140px;min-width:0;max-width:280px;height:32px;padding:0 10px;
  border-radius:8px;background:var(--bg-input);border:1px solid var(--border);
  color:var(--fg-1);font:500 13px var(--mk-font-ui);
  transition:border-color var(--mk-t-fast),box-shadow var(--mk-t-fast);
}
.cb-concat-static-input:focus{
  outline:none;border-color:var(--accent);
  box-shadow:0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}

/* Live canonical "= …" preview — monospace, accent-tinted, wraps. */
.cb-formula-preview{
  display:flex;align-items:baseline;flex-wrap:wrap;gap:6px;
  direction:ltr;
  padding:7px 11px;border-radius:9px;
  background:color-mix(in srgb, var(--accent) 8%, var(--bg-input));
  border:1px solid color-mix(in srgb, var(--accent) 26%, var(--border));
  font:600 12.5px var(--mk-font-mono);color:var(--fg-1);
  line-height:1.5;overflow-wrap:anywhere;
}
.cb-formula-preview.is-empty{color:var(--fg-3)}
.cb-f-eq{font-weight:700;color:var(--accent)}
.cb-f-preview-expr{min-width:0}
.cb-f-preview-num{
  margin-inline-start:auto;
  color:var(--accent);font-weight:700;white-space:nowrap;
}
.cb-f-preview-ph{color:var(--fg-3)}
/* Saved-row formula marker (the "ƒ" before a formula reference/value). */
.fp-expr-fn{font-weight:700;font-style:italic;color:var(--accent)}

/* Duration input — single text field shaped for the compact
   "Y M D HH:MM:SS ms" format the user dictates. The trailing
   format hint inside the box is purely visual; it doesn't get
   selected when the user clicks the input. */
.cb-duration{
  display:flex;align-items:center;gap:8px;
  padding:0 10px;
  background:var(--bg-input);border:1px solid var(--border);
  border-radius:8px;height:36px;
  transition:border-color var(--mk-t-fast);
}
.cb-duration:focus-within{border-color:var(--accent)}
.cb-duration .cb-duration-i{font-size:18px;color:var(--accent);flex-shrink:0}
.cb-duration input{
  flex:1;min-width:0;
  background:transparent;border:0;outline:none;
  color:var(--fg-1);
  font:500 13px var(--mk-font-mono);
}
.cb-duration input::placeholder{color:var(--fg-3)}
.cb-duration-fmt{
  font:500 10px var(--mk-font-mono);color:var(--fg-3);
  letter-spacing:.04em;
  flex-shrink:0;
  user-select:none;
}
.cb-range-duration{flex-wrap:wrap}
.cb-range-duration .cb-duration{flex:1;min-width:200px}

/* Multi-field duration input — each unit gets a proper labeled
   form field. Two groups (date / time) separated by a thin divider so
   the user reads "years / months / days" then "hours / minutes /
   seconds / millis" as natural duration parts. */
.cb-duration.cb-duration-parts{
  flex-direction:column;align-items:stretch;gap:0;
  height:auto;min-height:0;
  background:transparent;border:0;padding:0;
}
.cb-duration.cb-duration-parts:focus-within{border-color:transparent}
.cb-dur-section{
  display:flex;align-items:stretch;gap:14px;
  flex-wrap:wrap;
}
.cb-dur-group{
  display:grid;
  /* B24 — 56px floor (was 72) so the boxes stop forcing overflow; the
     inputs are border-box and shrink cleanly. */
  grid-template-columns:repeat(3, minmax(56px, 1fr));
  gap:10px;
  min-width:0;
  flex:1 1 240px;
}
.cb-dur-group-time{
  grid-template-columns:repeat(4, minmax(48px, 1fr));
  flex:1 1 320px;
}
.cb-dur-field{
  display:flex;flex-direction:column;align-items:stretch;gap:6px;
  min-width:0;
}
.cb-dur-l{
  font:600 11px var(--mk-font-ui);color:var(--fg-2);
  letter-spacing:.01em;
}
/* B63 #033 (Pablo) — each unit is a "-  {n}  +" stepper, not a bare
   box, so nudging one unit up/down (e.g. +1 month, -2 days) doesn't
   need the keyboard. The number stays directly typable too. */
.cb-dur-stepper{
  display:flex;align-items:stretch;gap:4px;min-width:0;
}
.cb-dur-step{
  flex:0 0 28px;width:28px;height:38px;border-radius:8px;
  background:var(--bg-input);border:1px solid var(--border);color:var(--fg-2);
  cursor:pointer;display:inline-flex;align-items:center;justify-content:center;
  transition:background var(--mk-t-fast),border-color var(--mk-t-fast),color var(--mk-t-fast);
}
.cb-dur-step .mi{font-size:16px}
.cb-dur-step:hover{background:var(--bg-2);border-color:var(--border-strong);color:var(--fg-1)}
.cb-dur-num{
  box-sizing:border-box;
  height:38px;padding:0 4px;
  background:var(--bg-input);border:1px solid var(--border);
  border-radius:8px;color:var(--fg-1);
  font:600 14px var(--mk-font-mono);
  font-variant-numeric:tabular-nums;
  text-align:center;
  flex:1 1 auto;width:100%;min-width:0;
  -moz-appearance:textfield;appearance:textfield;
  transition:border-color var(--mk-t-fast),box-shadow var(--mk-t-fast),background var(--mk-t-fast);
}
.cb-dur-num::-webkit-outer-spin-button,
.cb-dur-num::-webkit-inner-spin-button{ -webkit-appearance:none; margin:0 }
.cb-dur-num:hover{border-color:var(--border-strong)}
.cb-dur-num:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px var(--ring);background:var(--bg-1)}
/* Subtle thin divider between the date and time groups so each reads
   as its own block without needing card chrome around either. */
.cb-dur-divider{
  flex:0 0 1px;align-self:stretch;
  background:var(--border);
  margin:6px 0;
}
/* SH-07 (2026-07-02): 720 → 600 — at 601–720 the panel is 80vw (≥480px),
   wide enough for the horizontal date+time groups; stack only on mobile. */
@media (max-width: 600px){
  /* Stack the two groups vertically; divider becomes horizontal. */
  .cb-dur-section{flex-direction:column;gap:12px}
  /* B24 — column direction turns flex-basis (240/280px) into HEIGHT,
     stranding big vertical gaps between the stacked groups. */
  .cb-dur-group,.cb-dur-group-time{flex:0 0 auto}
  .cb-dur-divider{flex:0 0 1px;width:100%;height:1px;align-self:auto;margin:0}
  .cb-dur-group{grid-template-columns:repeat(3, minmax(0, 1fr))}
  .cb-dur-group-time{grid-template-columns:repeat(4, minmax(0, 1fr))}
}
/* B24 — very narrow: 4 abreast squeezes below a usable tap width and the
   long unit labels ("Milliseconds") overflow; go 2×2 instead. Labels also
   ellipsize defensively at every width. */
.cb-dur-l{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
@media (max-width: 400px){
  .cb-dur-group-time{grid-template-columns:repeat(2, minmax(0, 1fr))}
}
/* Inside a range, each duration stack gets its own row. */
/* Duration range — two trigger buttons + per-side popover modal.
   Same body/popover/modal pattern as .cb-date-pop. */
.cb-dur-range{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.cb-dur-side{position:relative;flex:1 1 220px;min-width:0}
/* Single-value duration occupies the whole value section (no range
   sibling to share the row with), so it overrides the flex basis
   used by the start/end sides in range mode. */
.cb-dur-side[data-dur-side="single"]{flex:0 1 auto;width:auto;max-width:100%}
.cb-dur-trigger{
  display:inline-flex;align-items:center;gap:8px;width:auto;max-width:100%;
  height:38px;padding:0 12px;border:1px solid var(--border);
  border-radius:8px;background:var(--bg-input);color:var(--fg-1);
  font:500 13px var(--mk-font-ui);text-align:start;cursor:pointer;
  transition:border-color var(--mk-t-fast),background var(--mk-t-fast);
}
.cb-dur-trigger:hover{border-color:var(--border-strong)}
.cb-dur-trigger.is-empty .cb-dur-trigger-l{color:var(--fg-3);font-weight:400}
.cb-dur-trigger-i{color:var(--accent);font-size:18px;flex-shrink:0}
.cb-dur-trigger-l{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:240px}
.cb-dur-trigger-edit{color:var(--fg-3);font-size:14px;flex-shrink:0}
.cb-dur-trigger:hover .cb-dur-trigger-edit{color:var(--accent)}

/* Popover — centered modal on desktop, bottom sheet on mobile-V,
   side panel on mobile-H. Hidden by default; .open toggled on parent
   .cb-dur-side opens it. */
.cb-dur-pop{
  position:fixed;inset:0;z-index:1000;
  background:rgba(0,0,0,.42);
  -webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);
  display:none;align-items:center;justify-content:center;padding:24px;
}
.cb-dur-side.open .cb-dur-pop{display:flex}
.cb-dur-pop-card{
  background:var(--bg-1);border:1px solid var(--border);
  border-radius:14px;box-shadow:var(--shadow-lg);
  width:min(520px, calc(100vw - 48px));
  max-height:calc(100dvh - 48px);
  display:flex;flex-direction:column;
}
.cb-dur-pop-hd{
  display:flex;align-items:center;gap:10px;
  padding:14px 16px;border-bottom:1px solid var(--border);
}
.cb-dur-pop-i{color:var(--accent);font-size:20px}
.cb-dur-pop-h{flex:1;font:600 14px var(--mk-font-ui);color:var(--fg-1)}
.cb-dur-pop-close{
  width:30px;height:30px;border-radius:7px;border:0;background:transparent;
  color:var(--fg-2);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;
}
.cb-dur-pop-close:hover{background:var(--bg-2);color:var(--fg-1)}
.cb-dur-pop-body{
  flex:1;padding:16px;overflow-y:auto;
  display:flex;flex-direction:column;gap:18px;
}
.cb-dur-form-group{display:flex;flex-direction:column;gap:8px}
.cb-dur-form-l{
  font:600 11px var(--mk-font-ui);color:var(--fg-3);
}
.cb-dur-form-row{
  display:grid;gap:10px;
  grid-template-columns:repeat(3, minmax(0, 1fr));
}
.cb-dur-form-time .cb-dur-form-row{grid-template-columns:repeat(4, minmax(0, 1fr))}
.cb-dur-pop-ft{
  display:flex;align-items:center;gap:8px;
  padding:12px 16px;border-top:1px solid var(--border);
}
.cb-dur-pop-clear{
  height:34px;padding:0 12px;border-radius:8px;
  background:transparent;border:1px solid var(--border);color:var(--fg-2);
  font:500 12px var(--mk-font-ui);cursor:pointer;
}
.cb-dur-pop-clear:hover{border-color:var(--mk-danger);color:var(--mk-danger)}
.cb-dur-pop-save{
  height:34px;padding:0 16px;border-radius:8px;
  background:var(--accent);border:1px solid var(--accent);color:var(--accent-fg);
  font:600 12px var(--mk-font-ui);cursor:pointer;
}
.cb-dur-pop-save:hover{filter:brightness(1.05)}

@media (max-width: 600px) and (orientation: portrait){
  .cb-dur-pop{align-items:flex-end;padding:0;z-index:2000}
  .cb-dur-pop-card{
    width:100%;max-width:100%;
    max-height:90dvh;min-height:60dvh;
    border-radius:18px 18px 0 0;
    padding:0 0 max(0px, env(safe-area-inset-bottom));
    box-shadow:0 -12px 32px rgba(0,0,0,.22);
  }
}
@media (max-height: 599px) and (orientation: landscape){
  .cb-dur-pop{align-items:stretch;justify-content:flex-end;padding:0;z-index:2000}
  .cb-dur-pop-card{
    width:min(520px, 75vw);max-width:75vw;
    height:100dvh;max-height:100dvh;
    border-radius:18px 0 0 18px;
    box-shadow:-12px 0 32px rgba(0,0,0,.22);
  }
  /* B46 P6-ML07 — no RTL justify-content override: `flex-end` on a flex
     row already resolves to the INLINE-end edge (left in RTL), which is
     what this panel wants. The old `flex-start` override pinned it to the
     physical RIGHT in Arabic while the radius/shadow rules below still
     rounded the left-anchored side, so the visible edge was square. */
  html[dir="rtl"] .cb-dur-pop-card{border-radius:0 18px 18px 0;box-shadow:12px 0 32px rgba(0,0,0,.22)}
}

/* Main-tree empty state — bare +Add condition button as primary action.
   QF chip drag-drops route through the existing .fp-add drop target
   (wireDnD). */
.fp-tree-empty{padding:8px 0}
.fp-tree-empty .fp-add{
  margin:0 auto;
  font-size:13px;height:38px;padding:0 16px;
}
.fp-tree-empty .fp-add .mi{font-size:18px}

/* Condition text — stays single-line with ellipsis at every viewport
   (Pablo audit 2026-05-27 reversed the earlier 2026-05-26 "always
   wrap" rule). When the value would overflow the pill, the trailing
   characters clip to `…`; the row never grows vertically, so the
   right-column +AND / +OR buttons stay in a clean vertical strip
   regardless of any specific row's content length. Hover tooltip
   on the pill shows the full text (wired in panels.js by the
   row-rendering helper). Wrap behaviour only re-enters in the
   `@container fp-tree (max-width: 460)` rule farther up the file —
   that's a mobile-V / mobile-H fallback where ellipsising mid-word
   is more painful than wrapping cleanly. */
.fp-cond .fp-actions{flex-shrink:0;align-self:center}
.cb-cal-weeks{display:flex;flex-direction:column;gap:6px;padding:8px 0}
.cb-cal-weeks-list{display:flex;flex-direction:column;gap:4px}
.cb-cal-week-bar{
  display:flex;align-items:center;justify-content:flex-start;
  padding:10px 14px;
  border-radius:8px;background:var(--bg-2);
  border:1px solid transparent;
  color:var(--fg-1);font:500 13px var(--mk-font-ui);
  cursor:pointer;text-align:start;
  transition:background var(--mk-t-fast),border-color var(--mk-t-fast),color var(--mk-t-fast);
}
.cb-cal-week-bar:hover{background:color-mix(in srgb,var(--accent) 6%,var(--bg-2));border-color:color-mix(in srgb,var(--accent) 22%,transparent)}
.cb-cal-week-bar.muted{opacity:.55}
.cb-cal-week-bar.today{border-color:color-mix(in srgb,var(--accent) 40%,transparent)}
.cb-cal-week-bar.in-range{background:color-mix(in srgb,var(--accent) 12%,var(--bg-2))}
.cb-cal-week-bar.range-start,
.cb-cal-week-bar.range-end{background:var(--accent);color:var(--accent-fg);border-color:var(--accent);font-weight:700}
.cb-cal-week-bar.range-start .cb-cal-week-l,
.cb-cal-week-bar.range-end .cb-cal-week-l{color:var(--accent-fg)}
.cb-cal-week-bar.on,
.cb-cal-week-bar.selected{background:var(--accent);color:var(--accent-fg);border-color:var(--accent);font-weight:700}
.cb-cal-week-bar.on .cb-cal-week-l,
.cb-cal-week-bar.selected .cb-cal-week-l{color:var(--accent-fg)}
.cb-cal-week-l{flex:1;min-width:0}

/* Datasize input — number field + unit dropdown sharing one chrome.
   The unit dropdown is a `.cs` so it inherits the standard custom
   select look; the divider keeps the two inputs visually grouped. */
.cb-datasize{
  display:flex;align-items:center;gap:0;
  background:var(--bg-input);border:1px solid var(--border);
  border-radius:8px;height:36px;
  overflow:visible;
  transition:border-color var(--mk-t-fast);
}
.cb-datasize:focus-within{border-color:var(--accent)}
.cb-datasize .cb-datasize-i{font-size:18px;color:var(--accent);padding:0 8px}
.cb-datasize .cb-datasize-num{
  flex:1;min-width:0;
  background:transparent;border:0;outline:none;
  height:34px;padding:0 8px;
  color:var(--fg-1);
  font:600 13px var(--mk-font-mono);
}
.cb-datasize-unit{
  position:relative;
  border-inline-start:1px solid var(--border);
  display:flex;align-items:stretch;
}
.cb-datasize-unit > .cs-btn{
  display:flex;align-items:center;gap:4px;
  padding:0 10px;height:34px;border:0;background:transparent;
  font:600 11px var(--mk-font-mono);color:var(--fg-2);
  cursor:pointer;border-radius:0;
  min-width:54px;justify-content:flex-end;
}
.cb-datasize-unit > .cs-menu{
  inset-inline-end:0;inset-inline-start:auto;
  min-width:64px;
}
.cb-range-datasize{flex-wrap:wrap}
.cb-range-datasize .cb-datasize{flex:1;min-width:200px}

/* Wave D — [OrderBy] + [Where] affordances rendered under the FIELD
   breadcrumb. The shared chip/button visuals (.cb-scope-chip*,
   .cb-scope-add-btn) below are reused by the Where control. */
/* Compact sub-filter buttons (Pablo 2026-06-21 #49: "these take too much
   space — simple buttons inside the path selector next to the X"). A tight
   horizontal row of small chips rather than a vertical stack of labelled rows;
   the per-control text label is dropped (the leading glyph + value carry it). */
.cb-waved-controls{
  display:flex;flex-direction:row;align-items:center;flex-wrap:wrap;
  gap:6px;margin-top:6px;
}
/* C19 (Pablo B12): the remove/action buttons must stay FIXED at the right edge
   of the row; the other options wrap BEFORE reaching them rather than pushing a
   button into the centre of a second row. The Where cluster (which carries the
   remove × / add affordance) is pinned right with margin-auto and never wraps
   internally; option chips wrap in the remaining space to its left. */
.cb-waved-controls > .cb-where-row{
  margin-inline-start:auto;flex:none;flex-wrap:nowrap;
}
.cb-waved-controls > .cb-where-row .cb-scope-chip-x{flex:none}
/* B30 C12 (Pablo): inside the path box the Where control must sit in the SAME
   cluster as Partition / Order-by — grouped with them, not shoved to the far
   opposite end of the row (which read as "a weird place"). Drop the separating
   auto-margin so `${ob}${gb}${wh}` render adjacent. Only shows now when the
   path is complete/collapsed (gated in renderCbFieldPicker). */
.cb-field-picker-ctl .cb-waved-controls > .cb-where-row{
  margin-inline-start:0;
}
/* B8-18/B8-22: when the controls live INSIDE the path box (.cb-field-picker-ctl)
   they read as an inline trailing cluster pinned to the row's end — like the
   sort panel's per-row buttons — not a separate block below. */
.cb-field-picker-ctl{flex-wrap:wrap}
.cb-field-picker-ctl > .cb-waved-controls{
  margin-top:0;margin-inline-start:auto;
  gap:4px;padding-inline-start:6px;flex-wrap:nowrap;
}
.cb-field-picker-ctl .cb-where-row{gap:6px;flex-wrap:nowrap}
/* Reuse the Sort-panel row control aesthetic (Pablo 2026-06-22 — "re-use the
   component we have in the sort panel"): plain neutral-bordered chips on the
   bg-input surface, no labels, no special accent treatment at rest; accent
   only on hover / active. Mirrors .sort-dir-btn / .sort-scope-btn (~3553). */
.cb-field-picker-ctl .cb-scope-add-btn{height:30px;padding:0 10px;gap:5px;font-size:11px;border-radius:7px}
.cb-field-picker-ctl .cb-scope-add-btn .mi{font-size:15px}
/* B10-17 + B10-19 (Pablo, recurring — "use the SAME styles as the sort panel
   filter button"). The Order-by, Partition(group-by) and Where controls now
   render with the EXACT sort-panel button aesthetic: a plain neutral-bordered
   chip on the bg-input surface, no accent fill at rest, accent only on
   hover/active. Canonical source: .sort-scope-btn / .sort-dir-btn (~3562). */
.cb-waved-controls .cb-orderby-lbl,
.cb-waved-controls .cb-where-lbl{ display:none; }
.cb-waved-controls .cb-orderby{ gap:6px; }
.cb-waved-controls .cb-orderby-cs > .cs-btn,
.cb-waved-controls .cb-groupby-cs > .cs-btn{
  height:30px;border-radius:7px;padding:0 10px;gap:5px;
  font:600 11px var(--mk-font-ui);
  background:var(--bg-input);border:1px solid var(--border);color:var(--fg-2);
}
.cb-waved-controls .cb-orderby-cs .cs-val{ max-width:120px;color:inherit; }
.cb-waved-controls .cb-subfilter-ic{ font-size:15px;color:var(--fg-3); }
.cb-orderby{
  display:flex;align-items:center;gap:8px;flex-wrap:wrap;
}
.cb-orderby-lbl{
  font:600 11px var(--mk-font-ui);color:var(--fg-3);
  text-transform:none;letter-spacing:.04em;
}
.cb-orderby-cs{position:relative;min-width:0}
.cb-orderby-cs > .cs-btn{
  display:inline-flex;align-items:center;gap:6px;
  height:30px;padding:0 10px;border-radius:7px;
  border:1px solid var(--border);background:var(--bg-input);color:var(--fg-2);
  font:600 11px var(--mk-font-ui);cursor:pointer;
  transition:border-color var(--mk-t-fast),background var(--mk-t-fast),color var(--mk-t-fast);
}
.cb-orderby-cs > .cs-btn:hover{border-color:var(--accent);color:var(--accent)}
.cb-orderby-cs > .cs-btn:hover .cb-subfilter-ic{color:var(--accent)}
.cb-orderby-cs.open > .cs-btn{border-color:var(--accent)}
/* Required + empty (First/Last with no sort yet): a SUBTLE warning ring that
   matches the sort panel's .sort-row.is-incomplete treatment — no heavy dashed
   box (Pablo: "looks horrible"). */
.cb-orderby-cs.is-trailing > .cs-btn{
  box-shadow:0 0 0 2px color-mix(in srgb, var(--mk-warning) 55%, transparent);
  border-color:color-mix(in srgb, var(--mk-warning) 60%, var(--border));
}
.cb-orderby-cs .cs-val.empty{color:var(--fg-3);font-style:italic}
.cb-orderby-dir{font-size:15px;color:var(--accent-2)}
/* C15 — grouping sub-filter (First/Last order-by) reuses the Scope-button
   aesthetic Pablo liked: a leading sort glyph + the accent "active" treatment
   once a non-default sort is committed (mirrors .sort-scope-btn.has-scope). */
.cb-subfilter-ic{font-size:15px;color:var(--fg-3);flex-shrink:0}
.cb-orderby-cs.cb-subfilter-cs > .cs-btn{border-radius:7px}
.cb-orderby-cs.has-scope > .cs-btn{
  background:color-mix(in srgb, var(--accent) 14%, transparent);
  border-color:var(--accent);
}
.cb-orderby-cs.has-scope .cb-subfilter-ic,
.cb-orderby-cs.has-scope .cs-val{color:var(--accent)}
.cb-orderby-cs .cs-val{max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Multi-key Order-by sub-slide rows (Pablo #50) */
.cb-ob-list{display:flex;flex-direction:column;gap:8px}
.cb-ob-row{display:flex;align-items:center;gap:8px}
.cb-ob-ord{flex:0 0 auto;width:20px;height:20px;border-radius:6px;display:inline-flex;
  align-items:center;justify-content:center;font:700 11px var(--mk-font-mono);
  background:var(--bg-3);color:var(--fg-3)}
.cb-ob-field-cs{position:relative;flex:1 1 0;min-width:0}
.cb-ob-field-cs > .cs-btn{display:flex;align-items:center;gap:6px;height:34px;padding:0 10px;
  border:1px solid var(--border);border-radius:8px;background:var(--bg-input);cursor:pointer;
  font:600 12px var(--mk-font-ui);color:var(--fg-1)}
.cb-ob-field-cs.open > .cs-btn,.cb-ob-field-cs > .cs-btn:hover{border-color:var(--accent)}
/* C24 + C27 (Pablo 2026-07-01): remove the dotted/dashed border on the order-by
   trailing selector — it matches every other field selector (solid). */
.cb-ob-field-cs.is-trailing > .cs-btn{border-style:solid}
.cb-ob-field-cs .cs-val{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cb-ob-field-cs .cs-val.empty{color:var(--fg-3);font-style:italic}
.cb-ob-dir,.cb-ob-rm{flex:0 0 auto;width:30px;height:30px;border-radius:8px;
  border:1px solid var(--border);background:var(--bg-1);color:var(--fg-2);cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center}
.cb-ob-dir:hover,.cb-ob-rm:hover{border-color:var(--accent);color:var(--accent)}
.cb-ob-dir .mi,.cb-ob-rm .mi{font-size:16px}
.cb-where-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
/* C5 (Pablo this batch): the row-level Where button breaks onto its own line
   under the path; align it to the inline-END so it sits beneath / beside the
   row’s remove (×) button instead of floating at the left. */
.cb-row-where{justify-content:flex-end}
/* B11-14 (Pablo): the value-source toggle + the field-dropdown slot pickers
   render as ONE connected group, not two detached boxes. */
.cb-val-grouped{display:flex;flex-direction:column;gap:0;border:1px solid var(--border);border-radius:var(--mk-radius-md);overflow:hidden}
.cb-val-grouped .cb-val-grouped-head{border:0;border-bottom:1px solid var(--divider);border-radius:0}
.cb-val-grouped > .cb-field-picker,.cb-val-grouped > .cb-rows,.cb-val-grouped > .cb-range{border-radius:0}
.cb-val-grouped > *:not(.cb-val-grouped-head){border-inline:0;border-bottom:0}
.cb-opt-tag{display:inline-flex;align-items:center;margin-inline-start:8px;padding:1px 7px;border-radius:var(--mk-radius-pill);
  font:600 10px var(--mk-font-ui);text-transform:none;letter-spacing:.03em;
  background:color-mix(in srgb,var(--accent) 13%,transparent);color:var(--accent);flex:none;white-space:nowrap}
.cb-multi-chip .cb-opt-tag{margin-inline-start:6px}
/* B11-27/B11-32: window-fn target + controls render INLINE in one path row. */
.cb-wf-inline{flex-wrap:wrap;align-items:center;gap:6px}
.cb-wf-inline .cb-wf-cs{flex:1 1 auto;min-width:150px}
.cb-wf-inline .cb-field-picker-ctl{margin-inline-start:auto;flex-wrap:nowrap}
/* C28 (Pablo 2026-07-01): collapsed wf-path summary chip — keeps the
   partition/order/filter controls inline on the first row (no wrap to a new
   line). Clicking re-expands the editable segments. */
.cb-wf-collapsed{flex-wrap:nowrap}
/* B22 C5 (Pablo): the collapsed row is real dropdown segments (PathInput
   contract) — no summary button/border, no edit icon. Collapsed segments
   hug their content instead of flex-growing; long names get ellipsis. */
.cb-wf-collapsed .cb-wf-cs{flex:0 1 auto;min-width:0}
button.cb-seg-more{cursor:pointer;font-family:var(--mk-font-ui)}
.cb-field-seg .cs-btn .cs-val:not(.empty){max-width:140px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* C29 (Pablo B12): wf target = one continuous path. Relation drill steps show
   as inline breadcrumb chips before the trailing field chooser; clicking a chip
   truncates the path back to that step. */
.cb-wf-relseg{
  display:inline-flex;align-items:center;gap:3px;flex:none;cursor:pointer;
  height:28px;padding:0 4px 0 8px;border:1px solid var(--border);border-radius:7px;
  background:var(--bg-input);color:var(--fg-1);font:600 12px var(--mk-font-ui);
  transition:border-color var(--mk-t-fast),color var(--mk-t-fast);
}
.cb-wf-relseg:hover{border-color:var(--accent);color:var(--accent)}
.cb-wf-relseg .cb-type-icon{font-size:15px;color:var(--accent-text)}
.cb-wf-relseg .cb-wf-relsep{font-size:16px;color:var(--fg-3);margin-inline-start:1px}
html[dir="rtl"] .cb-wf-relseg .cb-wf-relsep{transform:scaleX(-1)}
.cb-wf-cs .cs-item .cs-drill{margin-inline-start:auto;font-size:16px;color:var(--fg-3)}
html[dir="rtl"] .cb-wf-cs .cs-item .cs-drill{transform:scaleX(-1)}
.cb-wf-inline .cb-wf-offset{width:54px;height:30px;border:1px solid var(--border);border-radius:7px;
  background:var(--bg-input);color:var(--fg-1);font:600 12px var(--mk-font-ui);padding:0 6px;text-align:center}
/* B11-22 (Pablo): inside the path-input control row the Where button must be a
   1:1 ICON-ONLY square sitting right next to the X (no label, no gap drift) —
   matching the Partition/Order-by icon buttons. */
.cb-field-picker-ctl .cb-where-row{gap:4px}
.cb-field-picker-ctl .cb-where-row .cb-scope-add-btn{
  width:30px;height:30px;padding:0;justify-content:center;font-size:0;border-radius:7px;flex:none;
}
.cb-field-picker-ctl .cb-where-row .cb-scope-add-btn .mi{font-size:15px;margin:0;line-height:1;display:block}
/* B34 C33 (Pablo 2026-07-11): a count-distinct over a collection surfaces ONLY
   the Filter control after the path (no partition/order-by to group it with),
   so it dangled mid-row between the path and the clear-X. When the waved-controls
   cluster has no order-by/group-by sibling, push the Where row to the far edge so
   Filter sits flush beside the X. (The glyph re-centering is handled above.) */
.cb-field-picker-ctl .cb-waved-controls:not(:has(.cb-orderby-cs)):not(:has(.cb-groupby-cs)) > .cb-where-row{
  margin-inline-start:auto;
}
/* B11-06 (Pablo — "take the sort panel row as church"): the condition-builder
   reference row reuses the SAME picker engine as the sort row (renderCbFieldPicker);
   align its metrics to the sort row so it reads identically — slim box, 28px
   segment buttons, lean trailing controls. (.sort-list .sort-field-picker dims.) */
.cb-field-picker-ctl{min-height:34px;padding:3px;align-items:center}
.cb-field-picker-ctl > .cb-field-seg > .cs-btn,
.cb-field-picker-ctl .cb-field-seg > .cs-btn{min-height:28px}
.cb-field-picker-ctl .cb-field-seg + .cb-field-seg::before{font-size:16px;margin:0 1px}
.cb-field-picker-ctl > .cb-waved-controls .cb-orderby-cs > .cs-btn,
.cb-field-picker-ctl > .cb-waved-controls .cb-groupby-cs > .cs-btn,
.cb-field-picker-ctl .cb-scope-add-btn{height:28px}
/* hinge dropdown group separator (B11-26: dropped the “Source / Window
   functions” subtitle labels; a hairline keeps the grouping without text) */
.cs-sep{height:1px;margin:5px 8px;background:var(--divider)}
/* B10-18/B10-19 — window-function configuration body. Each control is a
   label + a sort-panel-style chip (.cb-orderby-cs), stacked in a tidy grid. */
.cb-wf-body{
  display:flex;flex-direction:column;gap:10px;
  margin-top:8px;padding:10px;border:1px solid var(--border);
  border-radius:9px;background:var(--bg-2);
}
.cb-wf-ctl{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.cb-wf-lbl{
  flex:0 0 88px;font:600 11px var(--mk-font-ui);color:var(--fg-3);
  text-transform:none;letter-spacing:.04em;
}
.cb-wf-req{color:var(--mk-warning);margin-inline-start:2px}
.cb-wf-offset{
  width:74px;height:30px;border-radius:7px;padding:0 10px;
  border:1px solid var(--border);background:var(--bg-input);color:var(--fg-1);
  font:600 12px var(--mk-font-ui);
}
.cb-wf-offset:focus{outline:none;border-color:var(--accent)}
.cb-wf-cs .cs-val{max-width:200px}
/* B10-18/19 follow-up (Pablo 2026-06-23): Partition / Order-by / Where as
   icon-only 1:1 buttons in a row, each opening its own slide-in. Mirrors the
   sort-panel button: neutral border on bg-input, accent on hover/active. */
.cb-ctl-iconrow{display:flex;align-items:center;gap:8px}
.cb-ctl-iconbtn{
  position:relative;width:34px;height:34px;flex:none;
  display:inline-flex;align-items:center;justify-content:center;
  border:1px solid var(--border);border-radius:8px;background:var(--bg-input);
  color:var(--fg-2);cursor:pointer;
  transition:border-color var(--mk-t-fast),background var(--mk-t-fast),color var(--mk-t-fast);
}
.cb-ctl-iconbtn .mi{font-size:19px}
.cb-ctl-iconbtn:hover{border-color:var(--accent);color:var(--accent)}
.cb-ctl-iconbtn.is-active{
  border-color:var(--accent);color:var(--accent);
  background:color-mix(in srgb, var(--accent) 12%, var(--bg-input));
}
.cb-ctl-iconbtn.is-req-missing{
  border-color:color-mix(in srgb, var(--mk-warning) 60%, var(--border));
  box-shadow:0 0 0 2px color-mix(in srgb, var(--mk-warning) 45%, transparent);
}
.cb-ctl-badge{
  position:absolute;top:-6px;inset-inline-end:-6px;min-width:16px;height:16px;
  padding:0 4px;border-radius:9px;background:var(--accent);color:#fff;
  font:700 10px var(--mk-font-ui);display:inline-flex;align-items:center;justify-content:center;
}
.cb-ctl-req-dot{
  position:absolute;top:-3px;inset-inline-end:-3px;width:7px;height:7px;border-radius:50%;
  background:var(--mk-warning);
}
/* C28 (Pablo B12): separate the control buttons more and give the OPTIONAL
   ones a clear neutral/gray border so required vs optional reads at a glance. */
.cb-field-picker-ctl,
.cb-ctl-iconrow{gap:8px}
.cb-ctl-iconbtn.is-optional{border-color:var(--fg-3)}
.cb-ctl-iconbtn.is-optional:hover{border-color:var(--accent)}
/* C25 (Pablo B12): offset = an icon + a −/value/+ numbered stepper (the
   standard NumberStepper look), replacing the bare number input. */
.cb-wf-offset-step{
  display:inline-flex;align-items:center;gap:2px;height:30px;flex:none;
  border:1px solid var(--border);border-radius:7px;background:var(--bg-input);padding:0 4px;
}
.cb-wf-offset-step .cb-wf-offset-ic{font-size:16px;color:var(--fg-3);margin-inline-end:2px}
.cb-wf-offset-step .cb-step-btn{
  width:24px;height:24px;border:0;border-radius:6px;background:transparent;cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center;color:var(--fg-2);
  transition:background var(--mk-t-fast),color var(--mk-t-fast);
}
.cb-wf-offset-step .cb-step-btn:hover{background:color-mix(in srgb,var(--accent) 14%,transparent);color:var(--accent)}
.cb-wf-offset-step .cb-step-btn .mi{font-size:16px}
.cb-wf-offset-step .cb-wf-offset-val{
  min-width:18px;text-align:center;font:700 13px var(--mk-font-ui);color:var(--fg-1);
  font-variant-numeric:tabular-nums;
}
/* C11 (Pablo B13): the offset value is click-to-edit (no leading icon); it
   swaps to a tiny number input on click. */
.cb-wf-offset-step .cb-wf-offset-val{cursor:text;border-radius:5px;padding:0 3px}
.cb-wf-offset-step .cb-wf-offset-val:hover{background:color-mix(in srgb,var(--accent) 12%,transparent)}
.cb-wf-offset-input{
  width:34px;border:0;background:transparent;outline:none;text-align:center;
  font:700 13px var(--mk-font-ui);color:var(--fg-1);font-variant-numeric:tabular-nums;
  -moz-appearance:textfield;
}
.cb-wf-offset-input::-webkit-outer-spin-button,
.cb-wf-offset-input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.cb-ms-row{
  display:flex;align-items:center;gap:10px;width:100%;
  padding:9px 12px;border:0;border-radius:8px;background:transparent;cursor:pointer;
  font:500 13px var(--mk-font-ui);color:var(--fg-1);text-align:start;
  transition:background var(--mk-t-fast);
}
.cb-ms-row:hover{background:var(--bg-2)}
.cb-ms-row .cb-ms-check{font-size:19px;color:var(--fg-3)}
.cb-ms-row.on .cb-ms-check{color:var(--accent)}
.cb-ms-row .cb-type-icon{font-size:17px;color:var(--fg-3)}
.cb-ms-l{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* B11-29: per-row asc/desc toggle on order-by rows (reuses the sort-row dir look) */
.cb-ms-dir{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;
  border:1px solid var(--border);border-radius:7px;background:var(--bg-input);color:var(--fg-2);flex:none}
.cb-ms-dir:hover{border-color:var(--accent);color:var(--accent)}
.cb-ms-dir .mi{font-size:15px}
/* C26/C27 (Pablo B12): partition / order-by as SORT-PANEL-STYLE rows — a
   numbered row per chosen field with its own field dropdown + remove, plus a
   trailing add dropdown. No checkbox, no leading arrow. */
.cb-ms-rows{display:flex;flex-direction:column;gap:8px;padding:4px 0}
.cb-ms-pathrow{display:flex;align-items:center;gap:8px}
.cb-ms-num{
  flex:none;width:22px;height:22px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;
  background:var(--accent-soft);color:var(--accent-text);font:700 11px var(--mk-font-ui);
}
.cb-ms-pathrow .cb-ms-fieldcs{flex:1 1 auto;min-width:0}
.cb-ms-dirbtn{
  flex:none;width:30px;height:30px;border:1px solid var(--border);border-radius:7px;
  background:var(--bg-input);color:var(--fg-2);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;
  transition:border-color var(--mk-t-fast),color var(--mk-t-fast);
}
.cb-ms-dirbtn:hover{border-color:var(--accent);color:var(--accent)}
.cb-ms-dirbtn .mi{font-size:16px}
.cb-ms-del{
  flex:none;width:30px;height:30px;border:1px solid transparent;border-radius:7px;
  background:transparent;color:var(--fg-3);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;
  transition:background var(--mk-t-fast),color var(--mk-t-fast);
}
.cb-ms-del:hover{background:color-mix(in srgb,var(--mk-danger) 18%,transparent);color:var(--mk-danger)}
.cb-ms-del .mi{font-size:16px}
/* C24 + C27 (Pablo 2026-07-01): the add-partition / add-sort row must NOT show a
   dotted/dashed border (flagged twice). Solid to match every other selector; the
   required state paints its own solid yellow ring via .cb-ms-required. */
.cb-ms-addcs{border-style:solid}
/* C9 (Pablo B13): relation-hop / aggregate drilldown back button inside the
   order-by / partition row dropdowns. */
.cb-ms-fieldcs .cb-ms-drillback{
  display:flex;align-items:center;gap:6px;width:100%;margin-bottom:4px;
  padding:7px 10px;border:0;border-radius:7px;background:var(--bg-2);cursor:pointer;
  font:600 11.5px var(--mk-font-ui);color:var(--fg-2);text-align:start;
}
.cb-ms-fieldcs .cb-ms-drillback:hover{color:var(--accent);background:color-mix(in srgb,var(--accent) 10%,transparent)}
.cb-ms-fieldcs .cb-ms-drillback .mi{font-size:15px}
html[dir="rtl"] .cb-ms-fieldcs .cb-ms-drillback .mi{transform:scaleX(-1)}
.cb-ms-fieldcs .cs-item .cs-drill{margin-inline-start:auto;font-size:16px;color:var(--fg-3)}
html[dir="rtl"] .cb-ms-fieldcs .cs-item .cs-drill{transform:scaleX(-1)}
.cb-ms-reqnote{
  display:flex;align-items:center;gap:6px;margin-top:10px;padding:8px 11px;border-radius:8px;
  background:color-mix(in srgb,var(--warn,#d9a400) 12%,transparent);color:var(--warn,#d9a400);
  font:600 12px var(--mk-font-ui);
}
.cb-ms-reqnote .mi{font-size:16px}
/* ═══ BATCH 15 (Pablo) — unify cb path/dropdown selectors & drop redundant chrome ═══ */
/* C32 — the source toggle already shows a "Select a value source…" placeholder;
   the extra helper span next to it is redundant and looked bad. */
.cb-val-none-hint{ display:none !important; }
/* C35/C38/C40 — window-fn + order-by/partition selectors share the SAME look as
   the initial field selector: solid border, rounded corners, no dotted line. */
.cb-ob-field-cs.is-trailing > .cs-btn,
.cb-ms-fieldcs .cb-ob-field-cs.is-trailing > .cs-btn,
.cb-ms-fieldcs.cs.is-trailing > .cs-btn,
.cb-ms-fieldcs .cs.is-trailing > .cs-btn{ border-style:solid !important; }
/* C23 + C26 (Pablo 2026-07-01): the WF partition / order-by add-row is REQUIRED
   until at least one full path is chosen — paint the agreed yellow warning ring
   on it (Save is already gated on wf.partition / wf.orderBy being non-empty). */
.cb-ms-fieldcs.cb-ms-required > .cs-btn{
  box-shadow:0 0 0 2px color-mix(in srgb, var(--mk-warning) 60%, transparent) !important;
  border-color:color-mix(in srgb, var(--mk-warning) 60%, var(--border)) !important;
}
.cb-ms-fieldcs > .cs-btn,
.cb-ms-fieldcs .cs-btn,
.cb-ob-field-cs > .cs-btn{ border-radius:8px; }
/* B31 C3 — the "no options" note inside cb menus had NO styling and rendered
   as raw text jammed against the menu edge. Quiet padded note. */
.cs-empty-note{
  padding:10px 12px;border-radius:8px;margin:2px;
  font:500 12px var(--mk-font-ui);color:var(--fg-3);
  background:var(--bg-2);text-align:center;
}
/* B31 C6 — kill the LAST border source on picked partition/order-by path
   rows: the outer .cs frame (the .cs-btn was already transparent, but the
   .cs element itself still painted a border in some themes). */
.cb-ms-fieldcs:not(.cb-ms-addcs):not(.cb-ms-required){
  border-color:transparent;background:transparent;box-shadow:none;
}
/* B25 C10 (Pablo, 3rd ask): NO border around the whole picked path in
   partition / order-by rows — the path reads as the borderless PathInput
   chain. The trailing ADD row keeps its bordered affordance (is-trailing
   solid rule above) and the required warning ring still applies. */
.cb-ms-fieldcs:not(.cb-ms-addcs):not(.cb-ms-required) > .cs-btn{
  border-color:transparent;
  background:transparent;
}
.cb-ms-fieldcs:not(.cb-ms-addcs) > .cs-btn:hover{
  background:var(--bg-2);
}
/* B25 C9 — the picked row's chain segments (PathInput collapsed contract). */
.cb-ms-seg{flex:0 1 auto}
.cb-ms-leaf{
  flex:0 1 auto;max-width:140px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  padding:2px 8px;border-radius:7px;
  background:color-mix(in srgb, var(--accent) 12%, transparent);
  color:var(--accent-text);font-weight:600;
}
.cb-ms-more{
  flex:none;padding:2px 7px;border-radius:999px;
  background:var(--bg-2);border:1px solid var(--border);
  font:700 10.5px var(--mk-font-mono);color:var(--fg-3);
}
/* C37 — drop the redundant "Select at least one field" note; the trailing
   dropdown's own border-paint (the agreed required style) already says it. */
.cb-ms-reqnote{ display:none !important; }
/* C8 (Pablo B13) — empty Quick-Filter strip: a simple, cool dashed pill with
   an icon instead of the bare ugly line of text. */
.cb-scope-empty-chips{
  display:inline-flex;align-items:center;gap:8px;width:100%;
  padding:11px 14px;border-radius:10px;
  border:1px dashed var(--border);background:var(--bg-2);
  color:var(--fg-3);font:500 12.5px var(--mk-font-ui);
}
.cb-scope-empty-chips .mi{font-size:17px;color:var(--accent-text);opacity:.85}
/* Source dropdown group labels (Source / Window functions) */
.cs-group-label{
  padding:8px 12px 4px;font:700 10px var(--mk-font-ui);
  color:var(--fg-3);text-transform:none;letter-spacing:.06em;
  position:sticky;top:0;background:var(--bg-1);
}
.cs-group-label:first-child{padding-top:4px}
/* B10-19 (Pablo): the Where add button must look like the SORT panel filter
   button, not a dashed accent pill. Solid neutral border on bg-input, accent
   only on hover. Mirrors .sort-scope-btn (~3562). */
.cb-where-row .cb-scope-add-btn{
  height:30px;padding:0 10px;border-radius:7px;gap:5px;
  border:1px solid var(--border);border-style:solid;background:var(--bg-input);
  color:var(--fg-2);font:600 11px var(--mk-font-ui);
}
.cb-where-row .cb-scope-add-btn:hover{
  border-color:var(--accent);color:var(--accent);background:var(--bg-input);
}
.cb-where-row .cb-scope-add-btn .mi{font-size:15px}
/* Filled Where chip — a neutral rounded-rect that reads as the same family as
   the sort row's controls (not a high-contrast pill). */
.cb-where-row .cb-scope-chip{
  height:30px;border-radius:7px;padding:0 4px 0 10px;
  background:var(--bg-input);border:1px solid var(--border);
}
.cb-where-row .cb-scope-chip .cb-scope-chip-i{color:var(--fg-3)}
.cb-where-tag{
  font:600 11px var(--mk-font-ui);color:var(--fg-3);
  text-transform:none;letter-spacing:.04em;
}
.cb-scope-hint{
  font:500 11px var(--mk-font-ui);color:var(--fg-3);
  /* Hint introduces the scope editor — keep it visually adjacent to the
     panel header (no top breathing room) but separate it from the QF
     section that follows so the headings don't collide. */
  margin:0 0 12px;line-height:1.5;
}
/* Inside the scope-edit slide, the .fp-section that immediately follows
   the hint sits directly under the QUICK FILTERS heading. Tighten its
   leading margin so the (hint → quick filters → conditions) stack reads
   as one block. (Adjacent-sibling selector works regardless of the
   underlying element tag — :first-of-type would miss because both the
   hint and the section are <div>s and the hint wins.) */
#scopeEditPanel .panel-body .cb-scope-hint + .fp-section{margin-top:4px}
.cb-scope-chips{
  display:flex;flex-wrap:wrap;gap:6px;
}
.cb-scope-chip{
  display:inline-flex;align-items:center;gap:6px;
  height:28px;padding:0 4px 0 10px;border-radius:999px;
  background:color-mix(in srgb, var(--accent-2) 14%, transparent);
  border:1px solid color-mix(in srgb, var(--accent-2) 30%, transparent);
  color:var(--fg-1);font:600 12px var(--mk-font-ui);
}
.cb-scope-chip-i{font-size:14px;color:var(--accent-2)}
.cb-scope-chip-l{
  max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.cb-scope-chip-edit,
.cb-scope-chip-x{
  width:20px;height:20px;border-radius:6px;
  background:transparent;border:0;cursor:pointer;color:var(--fg-3);
  display:inline-flex;align-items:center;justify-content:center;
  transition:background var(--mk-t-fast),color var(--mk-t-fast);
}
.cb-scope-chip-edit:hover{
  background:color-mix(in srgb, var(--accent) 18%, transparent);
  color:var(--accent);
}
.cb-scope-chip-x:hover{
  background:color-mix(in srgb, var(--mk-danger) 18%, transparent);
  color:var(--mk-danger);
}
.cb-scope-chip-edit .mi,
.cb-scope-chip-x .mi{font-size:13px}

/* Direct scope-filter add button — replaces the previous .cs dropdown.
   Clicking it pushes the scope-filter editor slide right away; no
   intermediate menu to navigate. The dashed accent border keeps it
   visually distinct from primary actions. */
.cb-scope-add-btn{
  display:inline-flex;align-items:center;gap:6px;
  height:32px;padding:0 12px;border-radius:8px;
  background:transparent;border:1px dashed color-mix(in srgb, var(--accent) 36%, var(--border));
  color:var(--accent);font:600 12px var(--mk-font-ui);
  cursor:pointer;
  transition:background var(--mk-t-fast),border-color var(--mk-t-fast);
}
.cb-scope-add-btn:hover{
  background:color-mix(in srgb, var(--accent) 8%, transparent);
  border-color:var(--accent);
}
.cb-scope-add-btn .mi{font-size:16px}

/* Yellow ring — required + empty. The ring sits ONLY on the actual
   input box (not on the row wrapper that contains a range pair),
   matching the focus-ring convention. Range pairs ring both slots
   because each side is its own input; collection / multi inputs
   render as a single composite box and pick up exactly one ring. */
.cb-section.is-required .cb-field-picker,
.cb-section.is-required .cb-step > .cs-btn,
.cb-section.is-required .cb-input,
.cb-section.is-required .cb-num,
.cb-section.is-required .cb-duration,
.cb-section.is-required .cb-datasize,
.cb-section.is-required .cb-multi,
.cb-section.is-required .cb-tag-input,
.cb-section.is-required .cb-date-btn,
.cb-section.is-required .cb-novalue{
  box-shadow:0 0 0 2px color-mix(in srgb, var(--mk-warning) 60%, transparent);
  border-color:color-mix(in srgb, var(--mk-warning) 60%, var(--border));
}
/* Path-selector pickers (hinge › … › field breadcrumbs, and the
   concat/coalesce/value field rows): ring ONLY the trailing dropdown that
   still needs a pick — not the whole box, whose earlier segments are
   already selected (Pablo 2026-06-19: "this whole box doesn't need the
   required outline, only the dropdown that hasn't been selected — do this
   in all the path selector components"). A picker with no trailing segment
   is complete, so it shows no ring at all. */
.cb-section.is-required .cb-field-picker{box-shadow:none;border-color:var(--border)}
.cb-section.is-required .cb-field-picker .cb-field-seg.is-trailing > .cs-btn{
  box-shadow:0 0 0 2px color-mix(in srgb, var(--mk-warning) 60%, transparent);
  border-color:color-mix(in srgb, var(--mk-warning) 60%, var(--border));
}
/* The bare <input> inside a styled wrapper (`.cb-num`, `.cb-duration`,
   `.cb-datasize`) already inherits the ring from its parent — clearing
   the input's own ring keeps the affordance to one continuous outline
   per box instead of a nested doubling. */
.cb-section.is-required .cb-num .cb-input,
.cb-section.is-required .cb-duration .cb-input,
.cb-section.is-required .cb-datasize .cb-input{
  box-shadow:none;
  border-color:transparent;
}
/* Focused input wins over the required-empty state — the user's
   active edit is more important to signal than the validation hint. */
.cb-section.is-required .cb-input:focus,
.cb-section.is-required .cb-num:focus-within,
.cb-section.is-required .cb-duration:focus-within,
.cb-section.is-required .cb-datasize:focus-within,
.cb-section.is-required .cb-multi:focus-within,
.cb-section.is-required .cb-tag-input:focus-within,
.cb-section.is-required .cb-field-picker:focus-within,
.cb-section.is-required .cb-date-btn:focus-visible{
  box-shadow:0 0 0 2px color-mix(in srgb, var(--accent) 50%, transparent);
  border-color:var(--accent);
}
/* Pablo 2026-06-18: a required FIELD section that holds a formula was ringing
   every operand picker. Ring only the trailing (next-to-fill) box so just
   the value that still needs input shows the yellow outline. */
.cb-section.is-required .cb-formula .cb-field-picker{box-shadow:none;border-color:var(--border)}
/* Ring only the EMPTY trailing dropdown inside the new-operand picker, not the
   whole .cb-f-picker box (Pablo 2026-06-21: "the dropdown has the required
   outline which is good, but the outside box also has it which is wrong"). */
.cb-section.is-required .cb-formula .cb-f-picker.is-new{box-shadow:none;border-color:var(--border)}
.cb-section.is-required .cb-formula .cb-f-picker.is-new .cb-field-seg.is-trailing > .cs-btn,
.cb-section.is-required .cb-formula .cb-f-picker.is-new > .cb-f-src-seg > .cs-btn{
  box-shadow:0 0 0 2px color-mix(in srgb, var(--mk-warning) 60%, transparent);
  border-color:color-mix(in srgb, var(--mk-warning) 60%, var(--border));
}
.cb-section.is-required .cb-formula .cb-f-picker.is-new:focus-within{
  box-shadow:none;border-color:var(--border);
}
/* Red ring — validated invalid. Same scope as the yellow ring. */
.cb-section.is-error .cb-field-picker,
.cb-section.is-error .cb-step > .cs-btn,
.cb-section.is-error .cb-input,
.cb-section.is-error .cb-num,
.cb-section.is-error .cb-duration,
.cb-section.is-error .cb-datasize,
.cb-section.is-error .cb-multi,
.cb-section.is-error .cb-tag-input,
.cb-section.is-error .cb-date-btn{
  box-shadow:0 0 0 2px color-mix(in srgb, var(--mk-danger) 60%, transparent);
  border-color:color-mix(in srgb, var(--mk-danger) 70%, var(--border));
}
.cb-section.is-error .cb-num .cb-input,
.cb-section.is-error .cb-duration .cb-input,
.cb-section.is-error .cb-datasize .cb-input{
  box-shadow:none;
  border-color:transparent;
}

/* Mobile-V: full-width bottom sheet anchored to the bottom of the
   viewport. The card grows from the bottom edge and the panel-body
   scrolls inside. Prioritizes information density over chrome. */
@media (max-width: 600px) and (orientation: portrait){
  #condBuilderModal{
    align-items:flex-end;justify-content:center;padding:0;
    background:color-mix(in srgb, var(--scrim) 50%, transparent);
    backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
  }
  /* Item 6.6 — the bottom sheet on mobile portrait was cramped at
     90vh. Lift it to 95vh AND require at least 80vh so deep condition
     chains have room to breathe without the user needing to scroll
     the parent. */
  #condBuilderModal .panel-card{
    width:100%;max-width:100%;
    min-height:80dvh;
    max-height:95dvh;
    border-radius:18px 18px 0 0;
    box-shadow:0 -20px 60px rgba(0,0,0,.35);
  }
  /* Calendar popup — escapes the bottom-sheet cond-builder card to
     a full-viewport overlay on mobile-V (two stacked sheets read as
     too cluttered). See the standalone .cb-date-pop mobile-V rules
     further down — they own the full-screen treatment. */
  .cb-date-pop{
    align-items:stretch;justify-content:stretch;
    padding:0;
    background:color-mix(in srgb, var(--scrim) 50%, transparent);
  }
  .cb-date-pop-card{
    width:100%;max-width:100%;
    height:100%;max-height:100%;min-height:100%;
    border-radius:0;
    box-shadow:none;
  }
}
/* Mobile-H: side panel anchored to the inline-end edge. Half-width on
   landscape so the user can still see what's behind it for context. */
@media (max-height: 599px) and (orientation: landscape){
  #condBuilderModal{
    align-items:stretch;justify-content:flex-end;padding:0;
    background:color-mix(in srgb, var(--scrim) 50%, transparent);
    backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
  }
  #condBuilderModal .panel-card{
    width:min(520px, 80vw);max-width:80vw;
    min-height:100dvh;max-height:100dvh;
    border-radius:18px 0 0 18px;
    box-shadow:-20px 0 60px rgba(0,0,0,.35);
  }
  html[dir="rtl"] #condBuilderModal .panel-card{
    border-radius:0 18px 18px 0;
    box-shadow:20px 0 60px rgba(0,0,0,.35);
  }
  /* Calendar popup mirrors the cond builder — a side panel anchored
     to the inline-end edge so the user keeps spatial context with
     the field they're editing (item 6.5). */
  .cb-date-pop{
    align-items:stretch;justify-content:flex-end;
    padding:0;
    background:color-mix(in srgb, var(--scrim) 50%, transparent);
  }
  .cb-date-pop-card{
    width:min(520px, 80vw);max-width:80vw;
    min-height:100dvh;max-height:100dvh;
    border-radius:18px 0 0 18px;
    box-shadow:-20px 0 60px rgba(0,0,0,.35);
  }
  html[dir="rtl"] .cb-date-pop-card{
    border-radius:0 18px 18px 0;
    box-shadow:20px 0 60px rgba(0,0,0,.35);
  }
}
/* Multi-date value picker for membership-multi ops on date/datetime
   leaves. Each row is a trigger button + an X. + Add date appends a
   new empty row. (Pablo 2026-05-30 — replaces the typed-string tag
   input so date values get a real picker per row.) */
.cb-multi-date-list{
  display:flex;flex-direction:column;gap:8px;
}
.cb-multi-date-row{
  display:grid;grid-template-columns:1fr auto;gap:8px;align-items:stretch;
  position:relative;
}
/* Per-row Mocca date picker takes the 1fr column. The cb-date-wrap
   carries the visible trigger + the popover (anchored via the shared
   positionAnchoredPopover()). (Pablo 2026-05-31 WD3.3 — replaced the
   prior trigger+hidden-native-input pattern with a real per-row Mocca
   calendar that respects truncation, RTL, and dark-mode tokens.) */
.cb-multi-date-row > .cb-date-wrap{min-width:0}
.cb-multi-date-row > .cb-date-wrap > .cb-date-btn{width:100%}
/* De-dupe pulse: when the user picks a date that already exists at
   another row, setCbDateValue jumps multiDateIdx to the existing row
   and commitSingleDay marks the row with .cb-multi-date-jumped for
   ~700ms so the visual feedback reads as "already there". */
@keyframes cb-multi-date-pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 0%, transparent); }
  40%      { box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 35%, transparent); }
}
.cb-multi-date-row.cb-multi-date-jumped > .cb-date-wrap > .cb-date-btn{
  animation: cb-multi-date-pulse 700ms ease-out;
  border-color: var(--accent);
}
.cb-multi-date-rm{
  width:40px;border-radius:9px;
  border:1px solid var(--border);background:var(--bg-input);
  color:var(--fg-3);cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center;
}
.cb-multi-date-rm:hover{color:var(--mk-danger);border-color:var(--mk-danger)}
.cb-multi-date-rm .mi{font-size:15px}
.cb-multi-date-add{
  display:inline-flex;align-items:center;gap:6px;
  padding:0 14px;height:36px;border-radius:9px;
  background:transparent;color:var(--accent);
  border:1px dashed color-mix(in srgb, var(--accent) 50%, transparent);
  font:600 12px var(--mk-font-ui);cursor:pointer;
  align-self:flex-start;
  transition:background var(--mk-t-fast), border-color var(--mk-t-fast);
}
.cb-multi-date-add:hover{
  background:color-mix(in srgb, var(--accent) 8%, transparent);
  border-color:var(--accent);
}
.cb-multi-date-add .mi{font-size:16px}

.cb-body{display:flex;flex-direction:column;gap:18px}
.cb-section{display:flex;flex-direction:column;gap:8px;min-width:0}
.cb-section-hd{
  font:600 11px var(--mk-font-ui);color:var(--fg-2);
  text-transform:none;letter-spacing:.08em;
  display:flex;align-items:center;gap:8px;
}
/* Per-section info icon — sits next to the section label (FIELD,
   OPERATOR, SCOPE, VALUE). Hover (mouse) shows the native title
   tooltip; sustained-touch reveals a styled tooltip card below.
   Pablo 2026-05-30: descriptions belong here, not on dropdown options. */
.cb-section-info{
  font-size:14px;color:var(--fg-3);
  width:18px;height:18px;border-radius:50%;
  display:inline-flex;align-items:center;justify-content:center;
  /* default cursor — the `help` (question-mark) cursor read as ugly and
     implied the glyph was a "?" (Pablo 2026-06-01). */
  cursor:default;position:relative;
  transition:color var(--mk-t-fast), background var(--mk-t-fast);
}
.cb-section-info:hover{
  color:var(--accent);
  background:color-mix(in srgb, var(--accent) 14%, transparent);
}
.cb-section-info.mocca-touch-revealed::after,
.cb-section-info:hover::after{
  content:attr(data-mocca-tip);
  position:absolute;top:calc(100% + 8px);inset-inline-start:0;
  z-index:50;
  max-width:280px;width:max-content;
  padding:10px 12px;border-radius:9px;
  background:var(--bg-1);border:1px solid var(--border);
  color:var(--fg-1);font:500 12px var(--mk-font-ui);line-height:1.5;
  letter-spacing:0;text-transform:none;
  box-shadow:0 14px 36px rgba(0,0,0,.22);
  white-space:normal;
  pointer-events:none;
}
.cb-section-info:hover::after{
  /* Slight delay so a quick mouse-over the section header doesn't fire
     the tooltip — only intent to hover the icon does. */
  animation: cb-tip-fade 200ms ease 350ms both;
}
@keyframes cb-tip-fade{
  from { opacity:0; transform:translateY(-2px); }
  to   { opacity:1; transform:translateY(0); }
}

/* Inline breadcrumb of dropdowns — each picked path step is its own
   .cs dropdown sitting side-by-side, separated by ">" chevrons. The
   trailing "Select…" segment lets the user pick the next step. Wraps
   to a second row gracefully on narrow viewports. */
.cb-field-picker{
  display:flex;flex-wrap:wrap;align-items:stretch;gap:0;
  padding:4px;
  background:var(--bg-input);
  border:1px solid var(--border);
  border-radius:9px;
  min-height:46px;
}
.cb-field-seg{display:inline-flex}
/* B10-16 (Pablo): X to clear the whole reference path. Sits at the trailing
   end of the picker box; danger-tinted on hover, neutral at rest. */
.cb-path-clear{
  align-self:center;flex:none;margin-inline-start:auto;
  width:24px;height:24px;border-radius:6px;
  display:inline-flex;align-items:center;justify-content:center;
  background:transparent;border:0;cursor:pointer;color:var(--fg-3);
  transition:background var(--mk-t-fast),color var(--mk-t-fast);
}
.cb-path-clear:hover{
  background:color-mix(in srgb, var(--mk-danger) 16%, transparent);color:var(--mk-danger);
}
.cb-path-clear .mi{font-size:15px}
.cb-field-seg + .cb-field-seg{margin-inline-start:2px}
.cb-field-seg + .cb-field-seg::before{
  content:"chevron_right"; content:"chevron_right" / "";   /* B67 R32 (R67-115) — a separator: nothing to read */
  font-family:"Material Symbols Rounded";
  font-size:18px;color:var(--fg-3);
  align-self:center;margin:0 2px;
  font-variation-settings:'opsz' 20, 'wght' 400, 'GRAD' 0, 'FILL' 0;
}
html[dir="rtl"] .cb-field-seg + .cb-field-seg::before{content:"chevron_left"}
.cb-field-seg > .cs-btn{
  display:inline-flex;align-items:center;gap:8px;
  height:36px;padding:0 10px;border-radius:7px;
  background:transparent;border:1px solid transparent;
  color:var(--fg-1);font:500 13px var(--mk-font-ui);
  cursor:pointer;white-space:nowrap;
  transition:background var(--mk-t-fast),border-color var(--mk-t-fast);
}
.cb-field-seg > .cs-btn:hover{background:var(--bg-2);border-color:var(--border)}
.cb-field-seg.open > .cs-btn{background:var(--bg-1);border-color:var(--accent)}
.cb-field-seg > .cs-btn .cb-type-icon{font-size:16px;color:var(--accent-text);flex-shrink:0}
.cb-field-seg > .cs-btn .cs-val{max-width:180px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
.cb-field-seg > .cs-btn .cs-val.empty{color:var(--fg-3);font-style:italic}
.cb-field-seg > .cs-btn .cs-arrow{color:var(--fg-3);font-size:16px}
/* Pablo (this batch): every field selector — resolved OR the trailing
   “Select…” chooser — must share ONE style. The trailing segment no longer
   gets a dashed accent border at rest; its empty italic “Select…” label is the
   only differentiator. (Required-state warning rings are applied separately.) */
.cb-field-seg.is-trailing > .cs-btn{
  border-style:solid;
  border-color:transparent;
}
/* C8 (Pablo this batch): when a path grows long the picker WRAPS subsequent
   segments onto the next line instead of shrinking the already-selected
   buttons until they collapse. Segments keep their intrinsic size (flex:0 0
   auto) and wrap as whole units; the cs-val ellipsis still caps each one. */
.cb-field-picker > .cb-field-seg{flex:0 0 auto}
.cb-field-seg > .cs-menu{
  inset-inline-start:0;inset-inline-end:auto;
  min-width:240px;max-height:360px;overflow-y:auto;
  padding:6px;
}
.cb-field-seg.open-up > .cs-menu{ top:auto;bottom:calc(100% + 4px); }
/* B8-17 (Pablo 2026-06-22): the value path's trailing dropdown was unreachable
   once the chain was EXPANDED — the wide run of earlier segments overlapped its
   button. Pin every value segment in its own stacking context and lift the
   trailing one (and any open menu) above its siblings so its .cs-btn always
   receives the click. */
.cb-val-field-picker .cs.cb-val-field-seg{position:relative;z-index:1}
.cb-val-field-picker .cs.cb-val-field-seg.is-trailing{z-index:2}
.cb-val-field-picker .cs.cb-val-field-seg.open{z-index:6}
.cb-val-field-picker .cs.cb-val-field-seg > .cs-btn{pointer-events:auto}
/* B8-14 (Pablo 2026-06-22): the concat source-kind menu's options "showed up
   only for a split second when closing". The shared .cs-menu fades via a 150ms
   opacity transition; on this row-embedded segment the open never visually
   settled, so only the fade-OUT registered as a flash. Toggle it instantly
   (no transition) so open shows the options and close hides them cleanly. */
.cb-concat-skind-cs > .cs-menu{ transition:none; }
.cb-field-seg .cs-item{
  display:flex;align-items:center;gap:12px;
  padding:10px 12px;border-radius:8px;
  cursor:pointer;
  color:var(--fg-1);font:500 13px var(--mk-font-ui);
  min-height:42px;
}
.cb-field-seg .cs-item:hover{background:color-mix(in srgb, var(--accent) 8%, transparent)}
.cb-field-seg .cs-item .cb-type-icon{font-size:18px;color:var(--accent-text);flex-shrink:0}
.cb-field-seg .cs-item .cb-item-l{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cb-field-seg .cs-item .cb-item-chev{color:var(--fg-3);font-size:16px;flex-shrink:0}
html[dir="rtl"] .cb-field-seg .cs-item .cb-item-chev::before{content:"chevron_left"}

/* Info icon — surfaces the field's description on hover (native title
   tooltip) or sustained-touch (mocca-touch-revealed class flips on a
   custom-styled tooltip below). Pablo 2026-05-30: "this prototype will
   exemplify what field descriptions are intended for". */
.cb-field-seg .cs-item .cb-item-info{
  color:var(--fg-3);font-size:16px;flex-shrink:0;/* B60 \u2014 no help cursor anywhere (Pablo) */
  position:relative;
  border-radius:50%;
  transition:color var(--mk-t-fast), background var(--mk-t-fast);
}
.cb-field-seg .cs-item .cb-item-info:hover{
  color:var(--accent);
  background:color-mix(in srgb, var(--accent) 12%, transparent);
}
/* Touch reveal — styled tooltip card anchored to the info icon. */
.cb-item-info.mocca-touch-revealed::after{
  content:attr(data-mocca-tip);
  position:absolute;top:calc(100% + 8px);inset-inline-end:0;
  z-index:50;
  max-width:240px;width:max-content;
  padding:10px 12px;border-radius:9px;
  background:var(--bg-1);border:1px solid var(--border);
  color:var(--fg-1);font:500 12px var(--mk-font-ui);line-height:1.45;
  box-shadow:0 14px 36px rgba(0,0,0,.20);
  white-space:normal;
}

/* Step picker — full-width .cs dropdown. Each .cs-item carries a type
   icon and (optionally) a trailing chevron when picking the item will
   drill further into a sub-context. */
.cb-step{display:flex;width:100%}
.cb-step > .cs-btn{
  flex:1;min-width:0;
  height:40px;padding:0 12px;border-radius:9px;
  background:var(--bg-input);border:1px solid var(--border);
  color:var(--fg-1);font:500 13px var(--mk-font-ui);
  display:flex;align-items:center;gap:10px;
  justify-content:flex-start;
  cursor:pointer;
  transition:border-color var(--mk-t-fast);
}
.cb-step > .cs-btn:hover{border-color:color-mix(in srgb, var(--accent) 35%, var(--border))}
.cb-step > .cs-btn .cs-val{flex:1;text-align:start;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
.cb-step > .cs-btn .cs-val.empty{color:var(--fg-3);font-style:italic}
.cb-step > .cs-btn .cs-arrow{color:var(--fg-3);font-size:18px;margin-inline-start:auto}
.cb-step > .cs-btn .cb-type-icon{font-size:18px;color:var(--accent);flex-shrink:0}
.cb-step.open > .cs-btn{border-color:var(--accent)}
.cb-step > .cs-menu{
  inset-inline-start:0;inset-inline-end:auto;
  /* B55 (Pablo: "The dropdown select list looks good but in some cases it takes
     the full width of the screen and looks weird") — `width:100%` tracks the
     trigger, which is right in a narrow row but sprawls once the trigger is a
     full-bleed panel field (the game's Filters slide is 100% wide on tablet and
     mobile). Cap it at a readable measure and keep a floor so short triggers
     still get a usable menu. */
  width:100%;min-width:min(240px,calc(100vw - 48px));
  max-width:min(440px,calc(100vw - 32px));
  /* Number type (10 ops: = ≠ < ≤ > ≥ BETWEEN OUTSIDE EXISTS EMPTY)
     and duration type (same 10) used to overflow the previous 360px
     cap by ~2 items — they were reachable only by scroll, which the
     user read as "can't select." Bumped to 480px so all 10 ops list
     vertically inline; longer lists still scroll. */
  max-height:480px;overflow-y:auto;
  padding:6px;
}
.cb-step .cs-item{
  display:flex;align-items:center;gap:12px;
  padding:10px 14px;border-radius:8px;
  cursor:pointer;
  color:var(--fg-1);font:500 13px var(--mk-font-ui);
  min-height:42px;
}
.cb-step .cs-item:hover{background:color-mix(in srgb, var(--accent) 8%, transparent)}
.cb-step .cs-item.on{background:color-mix(in srgb, var(--accent) 14%, transparent);color:var(--accent)}
.cb-step .cs-item .cb-type-icon{font-size:18px;color:var(--accent);flex-shrink:0}
.cb-step .cs-item .cb-item-l{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cb-step .cs-item .cb-item-chev{color:var(--fg-3);font-size:16px;flex-shrink:0}
html[dir="rtl"] .cb-step .cs-item .cb-item-chev::before{content:"chevron_left"}
/* Operator picker: trailing monospace glyph (=, ≠, …) sits at the end of
   the row, after the icon + Title-Case word (Pablo 2026-06-19). */
.cb-step[data-step="op"] .cs-item .cb-op-glyph{
  margin-inline-start:auto;flex-shrink:0;
  font:600 13px var(--mk-font-mono);color:var(--fg-3);
}
.cb-step[data-step="op"] .cs-item.on .cb-op-glyph{color:var(--accent)}
.cb-step[data-step="op"] > .cs-btn .cb-type-icon{font-size:18px;color:var(--accent);flex-shrink:0}

/* Plain typed input (text / number / date / datetime / email / url). */
.cb-input{
  height:40px;padding:0 12px;border-radius:9px;
  background:var(--bg-input);border:1px solid var(--border);
  color:var(--fg-1);font:500 13px var(--mk-font-ui);
  width:100%;
  transition:border-color var(--mk-t-fast);
}
.cb-input:focus{outline:none;border-color:var(--accent)}

/* Number input — wrap the native input with custom stepper buttons so
   we can theme them. Native spin buttons are hidden via -webkit /
   moz appearance because their cross-browser look is heavy and
   inconsistent. The wrapper carries the focus ring; the input itself
   has no border. */
.cb-num{
  position:relative;display:flex;align-items:stretch;
  height:40px;border-radius:9px;
  background:var(--bg-input);border:1px solid var(--border);
  transition:border-color var(--mk-t-fast);
  overflow:hidden;
}
.cb-num:focus-within{border-color:var(--accent)}
.cb-num > .cb-input{
  flex:1;min-width:0;height:auto;
  background:transparent;border:0;border-radius:0;
  padding:0 12px;
}
.cb-num > .cb-input:focus{border-color:transparent}
.cb-num > .cb-input[type="number"]{
  -moz-appearance:textfield;
  appearance:textfield;
}
.cb-num > .cb-input[type="number"]::-webkit-outer-spin-button,
.cb-num > .cb-input[type="number"]::-webkit-inner-spin-button{
  -webkit-appearance:none;appearance:none;margin:0;display:none;
}
.cb-num-steps{
  display:flex;flex-direction:column;
  width:22px;flex-shrink:0;
  border-inline-start:1px solid color-mix(in srgb, var(--border) 70%, transparent);
}
.cb-num-step{
  flex:1;min-height:0;padding:0;
  background:transparent;border:0;cursor:pointer;
  color:var(--fg-3);
  display:inline-flex;align-items:center;justify-content:center;
  transition:background var(--mk-t-fast),color var(--mk-t-fast);
}
.cb-num-step + .cb-num-step{
  border-top:1px solid color-mix(in srgb, var(--border) 70%, transparent);
}
.cb-num-step:hover{
  background:color-mix(in srgb, var(--accent) 10%, transparent);
  color:var(--accent);
}
.cb-num-step:active{
  background:color-mix(in srgb, var(--accent) 18%, transparent);
}
.cb-num-step .mi{font-size:14px;line-height:1}

/* Value-input variants */
.cb-novalue{
  padding:10px 12px;border-radius:9px;
  background:var(--bg-2);color:var(--fg-3);
  font:500 12px var(--mk-font-ui);
  font-style:italic;
}
.cb-range{
  display:flex;align-items:center;gap:8px;
}
.cb-range .cb-input{flex:1;min-width:0}
.cb-range .cb-num{flex:1;min-width:0}
.cb-range-sep{
  color:var(--fg-3);font-size:18px;flex-shrink:0;
}
html[dir="rtl"] .cb-range-sep{transform:scaleX(-1)}
.cb-multi{
  display:flex;flex-wrap:wrap;gap:6px;
  padding:8px;border-radius:9px;
  background:var(--bg-input);border:1px solid var(--border);
}
.cb-multi-chip{
  display:inline-flex;align-items:center;gap:6px;
  height:30px;padding:0 10px;border-radius:999px;
  background:var(--bg-2);border:1px solid var(--border);
  color:var(--fg-1);font:600 12px var(--mk-font-ui);
  cursor:pointer;
  transition:background var(--mk-t-fast),border-color var(--mk-t-fast),color var(--mk-t-fast);
}
.cb-multi-chip:hover{border-color:color-mix(in srgb, var(--accent) 35%, var(--border))}
.cb-multi-chip.on{
  background:color-mix(in srgb, var(--accent) 16%, transparent);
  border-color:var(--accent);color:var(--accent);
}
.cb-multi-chip .cb-type-icon{font-size:14px;color:inherit}
.cb-multi-chip .cb-opt-flag{width:16px;height:16px}

/* Round-cropped flag/image for relation options. The CDN serves
   landscape PNGs; object-fit:cover + border-radius:50% turns them
   into circular 1:1 sigils that match the icon column width. */
.cb-opt-flag{
  display:inline-block;
  width:18px;height:18px;
  border-radius:50%;
  object-fit:cover;
  flex-shrink:0;
  background:var(--bg-2);
  box-shadow:0 0 0 1px color-mix(in srgb, var(--border) 70%, transparent) inset;
}

/* Multi-select dropdown (long relation lists). Visually the same .cs
   chrome as a single-select; the menu rows add an inline checkbox and
   the Select-all row sits PINNED at the top with a tristate icon —
   only the items list scrolls. */
.cb-multi-cs > .cs-menu{
  max-height:320px;
  overflow:hidden;
  min-width:280px;
  display:flex;flex-direction:column;
}
.cb-multi-items{
  flex:1;min-height:0;
  overflow-y:auto;
}
/* Trigger: when the selection is non-empty we render inline tag chips
   (each with its visual sigil) so the user can see WHAT is selected
   without opening the menu. The container scrolls horizontally so
   long selection lists never wrap the trigger button. */
.cb-multi-btn{
  display:flex;align-items:center;gap:8px;
  min-height:40px;
}
.cb-multi-trigger-tags{
  flex:1;min-width:0;
  display:flex;align-items:center;gap:4px;
  overflow-x:auto;
  scrollbar-width:thin;
  padding:4px 0;
  -webkit-mask-image:linear-gradient(to right, transparent 0, #000 12px, #000 calc(100% - 12px), transparent 100%);
          mask-image:linear-gradient(to right, transparent 0, #000 12px, #000 calc(100% - 12px), transparent 100%);
}
.cb-multi-trigger-tags::-webkit-scrollbar{height:4px}
.cb-multi-trigger-tags::-webkit-scrollbar-thumb{
  background:color-mix(in srgb, var(--accent) 30%, transparent);
  border-radius:2px;
}
.cb-multi-trigger-tag{
  display:inline-flex;align-items:center;gap:4px;
  height:24px;padding:0 8px;border-radius:999px;
  background:color-mix(in srgb, var(--accent) 14%, transparent);
  border:1px solid color-mix(in srgb, var(--accent) 30%, transparent);
  color:var(--fg-1);
  font:600 11px var(--mk-font-ui);
  flex-shrink:0;
  white-space:nowrap;
}
.cb-multi-trigger-tag .cb-opt-flag{width:14px;height:14px}
.cb-multi-trigger-tag .cb-type-icon{font-size:12px;color:var(--accent)}
.cb-multi-trigger-tag-l{
  max-width:160px;overflow:hidden;text-overflow:ellipsis;
}
.cb-multi-counter{
  flex-shrink:0;
  font:600 11px var(--mk-font-mono);color:var(--fg-3);  font-variant-numeric:tabular-nums;
  padding:2px 6px;border-radius:5px;
  background:var(--bg-2);
}
.cb-multi-item{
  display:flex;align-items:center;gap:10px;
  padding:8px 10px;border-radius:6px;cursor:pointer;
}
.cb-multi-item:hover{background:color-mix(in srgb, var(--accent) 8%, transparent)}
.cb-multi-item .cb-multi-check{
  font-size:18px;
  color:var(--fg-3);
  transition:color var(--mk-t-fast);
}
.cb-multi-item.on .cb-multi-check{color:var(--accent)}
.cb-multi-item .cb-item-l{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cb-multi-all{
  display:flex;align-items:center;gap:10px;
  padding:8px 10px;
  flex-shrink:0;
  border-bottom:1px solid color-mix(in srgb, var(--border) 60%, transparent);
  border-radius:0;
  background:var(--bg-1);
  font:600 12px var(--mk-font-ui);color:var(--fg-1);
  cursor:pointer;text-transform:none;letter-spacing:.04em;
  position:sticky;top:0;z-index:1;
}

/* In-menu search row — sticky beneath the Select-all row (or at top
   in single-select). Doesn't behave as a .cs-item: the input takes
   the click. JS handler intercepts e.stopPropagation so the parent
   .cs.open stays open across keystrokes. */
.cs-search{
  display:flex;align-items:center;gap:6px;
  padding:6px 8px;
  flex-shrink:0;
  background:var(--bg-1);
  border-bottom:1px solid color-mix(in srgb, var(--border) 50%, transparent);
  position:sticky;top:0;z-index:1;
}
.cb-multi-cs .cs-search{top:36px}
.cs-search .cs-search-i{
  color:var(--fg-3);font-size:16px;
}
.cs-search-input{
  flex:1;min-width:0;
  height:28px;padding:0 4px;
  background:transparent;border:0;outline:none;
  color:var(--fg-1);font:500 12px var(--mk-font-ui);
}
.cs-search-input::placeholder{color:var(--fg-3);font-style:italic}
.cb-multi-all:hover{background:color-mix(in srgb, var(--accent) 10%, transparent)}
.cb-multi-all .cb-multi-check{font-size:18px;color:var(--fg-3)}
.cb-multi-all-partial .cb-multi-check,
.cb-multi-all-full    .cb-multi-check{color:var(--accent)}
.cb-multi-all .cb-multi-count{
  margin-inline-start:auto;
  font:600 11px var(--mk-font-mono);color:var(--fg-3);
  font-variant-numeric:tabular-nums;
}

/* Tag input — text/number IN/NOT IN. Chips render INLINE with the
   typing input inside one bounded box so it reads like a single
   control. Pressing Enter or comma commits the typing buffer as a
   chip; Backspace on empty buffer pops the last chip; click anywhere
   in the box focuses the typing surface. */
.cb-tag-input{
  display:flex;flex-wrap:wrap;align-items:center;gap:6px;
  min-height:42px;padding:6px 10px;
  background:var(--bg-input);border:1px solid var(--border);
  border-radius:9px;
  cursor:text;
  transition:border-color var(--mk-t-fast);
}
.cb-tag-input:focus-within{border-color:var(--accent)}
.cb-tag{
  display:inline-flex;align-items:center;gap:4px;
  height:26px;padding:0 4px 0 10px;
  background:color-mix(in srgb, var(--accent) 14%, transparent);
  border:1px solid color-mix(in srgb, var(--accent) 30%, transparent);
  border-radius:999px;
  color:var(--fg-1);font:600 12px var(--mk-font-ui);
}
.cb-tag-l{
  max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.cb-tag-x{
  width:18px;height:18px;border-radius:6px;
  background:transparent;border:0;cursor:pointer;
  color:var(--fg-3);
  display:inline-flex;align-items:center;justify-content:center;
  transition:background var(--mk-t-fast),color var(--mk-t-fast);
}
.cb-tag-x .mi{font-size:12px}
.cb-tag-x:hover{
  background:color-mix(in srgb, var(--mk-danger) 18%, transparent);
  color:var(--mk-danger);
}
.cb-tag-typing-wrap{
  flex:1;min-width:160px;
  display:flex;align-items:center;gap:6px;
}
.cb-tag-typing{
  flex:1;min-width:80px;
  height:28px;border:0;background:transparent;
  color:var(--fg-1);font:500 13px var(--mk-font-ui);
  outline:none;
}
.cb-tag-typing::placeholder{color:var(--fg-3);font-style:italic}
/* Hide native spinner — the .cb-tag-typing-steps below replace it with
   themed buttons that match the rest of the modal. */
.cb-tag-typing[type="number"]{
  -moz-appearance:textfield;
  appearance:textfield;
}
.cb-tag-typing[type="number"]::-webkit-outer-spin-button,
.cb-tag-typing[type="number"]::-webkit-inner-spin-button{
  -webkit-appearance:none;appearance:none;margin:0;display:none;
}
/* Themed up/down stepper for the tag-typing number input — flush
   alongside the input, between it and the +Add button. */
.cb-tag-typing-steps{
  display:flex;flex-direction:column;
  width:18px;height:24px;flex-shrink:0;
  border:1px solid color-mix(in srgb, var(--border) 70%, transparent);
  border-radius:6px;overflow:hidden;
  background:var(--bg-2);
}
.cb-tag-typing-steps .cb-num-step{
  flex:1;min-height:0;width:auto;padding:0;
}
.cb-tag-typing-steps .cb-num-step + .cb-num-step{
  border-top:1px solid color-mix(in srgb, var(--border) 70%, transparent);
}
.cb-tag-typing-steps .cb-num-step .mi{font-size:12px}
/* Explicit +Add affordance — appears only when the typing buffer has
   content. Mirrors the Enter shortcut for users who don't discover it. */
.cb-tag-add{
  display:inline-flex;align-items:center;gap:4px;
  height:24px;padding:0 8px 0 6px;border-radius:999px;
  background:color-mix(in srgb, var(--accent) 16%, transparent);
  border:1px solid color-mix(in srgb, var(--accent) 36%, transparent);
  color:var(--accent);font:700 11px var(--mk-font-ui);
  letter-spacing:.04em;text-transform:none;
  cursor:pointer;flex-shrink:0;
  transition:background var(--mk-t-fast),border-color var(--mk-t-fast);
}
.cb-tag-add:hover{
  background:color-mix(in srgb, var(--accent) 28%, transparent);
  border-color:var(--accent);
}
.cb-tag-add .mi{font-size:14px}
.cb-tag-add[hidden]{display:none}

/* Custom date / datetime picker. The trigger button mirrors .cb-input
   styling for visual continuity; clicking it toggles an inline popover
   that holds a month grid (date) plus an HH:MM row (datetime). The
   popover positions absolutely below the trigger and is allowed to
   escape the modal card via the cb modal's overflow:visible override. */
.cb-date-wrap{position:relative;display:flex;flex:1;min-width:0}
.cb-date-btn{
  flex:1;min-width:0;
  display:flex;align-items:center;gap:10px;
  height:40px;padding:0 12px;border-radius:9px;
  background:var(--bg-input);border:1px solid var(--border);
  color:var(--fg-1);font:500 13px var(--mk-font-ui);
  cursor:pointer;
  transition:border-color var(--mk-t-fast);
}
.cb-date-btn:hover{border-color:color-mix(in srgb, var(--accent) 35%, var(--border))}
.cb-date-wrap.open .cb-date-btn{border-color:var(--accent)}
.cb-date-btn .cb-date-icon{color:var(--accent);font-size:18px;flex-shrink:0}
.cb-date-btn .cb-date-val{flex:1;text-align:start;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
.cb-date-btn .cb-date-val.empty{color:var(--fg-3);font-style:italic}
.cb-date-btn .cs-arrow{color:var(--fg-3);font-size:18px}

/* Calendar popover — floats on top of the parent modal as its own
   dialog, the way a confirmation pop-up would. A fixed-position overlay
   dims the modal behind it; the inner card centres in the viewport so
   the date picker reads as a focused sub-task rather than as a tooltip
   hanging off an input. */
.cb-date-pop{
  position:fixed;
  inset:0;
  z-index:1000;
  background:rgba(0,0,0,.42);
  -webkit-backdrop-filter:blur(2px);
  backdrop-filter:blur(2px);
  display:none;
  align-items:center;justify-content:center;
  padding:24px;
  overflow:auto;  /* fallback scroll when the card outgrows the viewport */
}
.cb-date-wrap.open .cb-date-pop,
.cb-date-pop.is-open{display:flex}
.cb-date-pop-card{
  background:var(--bg-1);
  border:1px solid var(--border);border-radius:12px;
  box-shadow:var(--shadow-lg);
  padding:14px;
  display:flex;flex-direction:column;gap:10px;
  max-width:calc(100vw - 48px);
  max-height:calc(100dvh - 48px);
  /* overflow:visible lets the timezone dropdown's absolutely-positioned
     menu escape the card; the popup overlay itself (.cb-date-pop) sits
     above the modal and handles long-content scrolling instead. */
  overflow:visible;
}

/* Responsive layout for the calendar + clock pair. The user spec:
   flex-col on Mobile-V and Tablet (narrow), flex-row on Mobile-H
   and Desktop (wide). For single date (no clock) the column-only
   layout doesn't matter. */
.cb-datetime-layout{
  display:flex;gap:14px;align-items:flex-start;
  flex-direction:row;
}
.cb-cal-col{flex:0 0 auto;min-width:280px}
.cb-clock-col{flex:1;min-width:0}
/* When the step machinery shows ONLY one phase (date OR clock OR
   year-grid OR month-grid), the column widens to fill the popover
   card. The legacy "calendar + clocks side by side" layout went away
   with the layered-steps refactor — each step gets the full room. */
.cb-cal-col-wide{flex:1;min-width:0;width:100%}
.cb-clock-col-wide{flex:1;min-width:0;width:100%}

/* Year / Month / Quarter pickers — grid of selectable cells with
   prev/next decade or year navigation in the header. Cells echo the
   .cb-cal-cell visual language so the picker feels like a sibling of
   the date calendar. */
.cb-year-picker, .cb-month-picker, .cb-quarter-picker{
  display:flex;flex-direction:column;gap:8px;
  min-width:280px;
}
.cb-cal-decade, .cb-cal-year-label-static{
  flex:1;text-align:center;
  font:700 13px var(--mk-font-ui);color:var(--fg-1);
  font-variant-numeric:tabular-nums;
}
.cb-year-grid{
  display:grid;grid-template-columns:repeat(4, 1fr);gap:6px;
}
.cb-month-grid{
  display:grid;grid-template-columns:repeat(4, 1fr);gap:6px;
}
.cb-quarter-grid{
  display:grid;grid-template-columns:repeat(2, 1fr);gap:8px;
}
.cb-year-cell, .cb-month-cell, .cb-quarter-cell{
  height:44px;padding:0 4px;border-radius:9px;
  background:transparent;border:1px solid transparent;
  color:var(--fg-1);font:600 13px var(--mk-font-mono);
  font-variant-numeric:tabular-nums;
  cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center;
  transition:background var(--mk-t-fast),border-color var(--mk-t-fast),color var(--mk-t-fast);
}
.cb-quarter-cell{height:64px;font-size:16px;flex-direction:column;gap:2px;line-height:1.1}
.cb-quarter-cell-q{font:600 16px var(--mk-font-mono);font-variant-numeric:tabular-nums}
.cb-quarter-cell-mo{font:500 10px var(--mk-font);opacity:.7;letter-spacing:.04em;text-transform:none}
.cb-quarter-cell.on .cb-quarter-cell-mo,
.cb-quarter-cell.range-start .cb-quarter-cell-mo,
.cb-quarter-cell.range-end .cb-quarter-cell-mo{opacity:.85;color:var(--accent-fg)}
.cb-year-cell:hover, .cb-month-cell:hover, .cb-quarter-cell:hover{
  background:var(--bg-2);border-color:var(--border);
}
.cb-year-cell.on, .cb-month-cell.on, .cb-quarter-cell.on,
.cb-year-cell.range-start, .cb-month-cell.range-start, .cb-quarter-cell.range-start,
.cb-year-cell.range-end, .cb-month-cell.range-end, .cb-quarter-cell.range-end{
  background:var(--accent);border-color:var(--accent);color:var(--accent-fg);
}
.cb-year-cell.in-range, .cb-month-cell.in-range, .cb-quarter-cell.in-range{
  background:color-mix(in srgb, var(--accent) 14%, transparent);
}

/* Week-truncation mode — hovering any cell in a row highlights the
   WHOLE row so the user reads "I'm picking this week, not just this
   day". Uses CSS :has() to project the hover state across siblings
   sharing the same data-cal-row. Selected/in-range cells already get
   their own accent; this rule lights up everything else in the row
   on hover only. */
.cb-cal-grid.is-week .cb-cal-cell:not(.blank):not(.is-disabled){cursor:pointer}
.cb-cal-grid.is-week:has(.cb-cal-cell[data-cal-row="0"]:hover) .cb-cal-cell[data-cal-row="0"]:not(.blank),
.cb-cal-grid.is-week:has(.cb-cal-cell[data-cal-row="1"]:hover) .cb-cal-cell[data-cal-row="1"]:not(.blank),
.cb-cal-grid.is-week:has(.cb-cal-cell[data-cal-row="2"]:hover) .cb-cal-cell[data-cal-row="2"]:not(.blank),
.cb-cal-grid.is-week:has(.cb-cal-cell[data-cal-row="3"]:hover) .cb-cal-cell[data-cal-row="3"]:not(.blank),
.cb-cal-grid.is-week:has(.cb-cal-cell[data-cal-row="4"]:hover) .cb-cal-cell[data-cal-row="4"]:not(.blank),
.cb-cal-grid.is-week:has(.cb-cal-cell[data-cal-row="5"]:hover) .cb-cal-cell[data-cal-row="5"]:not(.blank){
  background:color-mix(in srgb, var(--accent) 18%, transparent);
  border-color:color-mix(in srgb, var(--accent) 40%, transparent);
}

/* Step dots — one per substep; the current one is highlighted, done
   steps wear a softer fill. Clicking jumps the user to that step. */
.cb-range-step-dots{
  display:flex;align-items:center;gap:6px;
}
.cb-step-dot{
  width:8px;height:8px;border-radius:50%;
  background:color-mix(in srgb, var(--fg-3) 45%, transparent);
  cursor:pointer;
  transition:background var(--mk-t-fast),transform var(--mk-t-fast);
}
.cb-step-dot.done{ background:color-mix(in srgb, var(--accent) 55%, transparent); }
.cb-step-dot.on{ background:var(--accent); transform:scale(1.35); }
@media (max-width: 600px) and (orientation: portrait){
  .cb-datetime-layout{flex-direction:column}
  /* Mobile Portrait (V) — bottom sheet so the picker doesn't feel
     like the whole OS got hijacked. Slides up from the bottom, leaves
     a strip of the underlying view visible. Step header sticks to
     the sheet's top edge; date actions stick to the bottom. */
  .cb-date-pop{
    align-items:flex-end;justify-content:stretch;
    padding:0;
    z-index:2000;
    background:color-mix(in srgb, var(--scrim) 50%, transparent);
  }
  .cb-date-pop-card{
    width:100%;max-width:100%;
    height:auto;
    max-height:90dvh;
    min-height:60dvh;
    border-radius:18px 18px 0 0;
    padding:0 0 max(14px, env(safe-area-inset-bottom));
    overflow:hidden;
    display:flex;flex-direction:column;
    box-shadow:0 -12px 32px rgba(0,0,0,.22);
  }
  /* Step header pins to the top of the sheet so the user always sees
     which phase they're on; date actions pin to the bottom. */
  .cb-date-pop-card .cb-range-step-hd{
    position:sticky;top:0;z-index:2;
    background:var(--bg-1);
    padding:14px 16px 12px;
    border-bottom:1px solid var(--border);
  }
  .cb-date-pop-card .cb-datetime-layout{
    flex:1;min-height:0;
    overflow-y:auto;
    padding:12px 14px 0;
    gap:18px;
  }
  /* Both columns reclaim the full popover width on mobile-V. */
  .cb-cal-col, .cb-cal-col-wide,
  .cb-clock-col, .cb-clock-col-wide{
    min-width:0;width:100%;
  }
  /* Calendar cells grow with the available width so the grid reads at
     a glance on a phone instead of feeling like a desktop popover
     squeezed onto a small screen. */
  .cb-cal-grid .cb-cal-cell{height:40px;font-size:14px}
  .cb-cal-dow-cell{font-size:11px}
  /* Clock dials shrink to a fraction of the viewport so the whole time
     section fits without forcing the sheet to scroll. Tighter than the
     standalone mobile-V rule because here we're inside a bottom-sheet
     card that already eats some vertical space. */
  .cb-clocks .cb-clock{max-width:min(32vw, 130px)}
  .cb-date-actions{
    position:sticky;bottom:0;
    background:var(--bg-1);
    padding:12px 14px max(12px, env(safe-area-inset-bottom));
    border-top:1px solid var(--border);
    margin-top:auto;
  }
}
@media (min-width: 601px) and (max-width: 1024px) and (min-height: 600px){
  .cb-datetime-layout{flex-direction:column}
}
/* Desktop & tablet (P + T variants — wider than 720px AND tall enough):
   the popover anchors near its trigger instead of acting like a full-
   page modal. The .cb-date-pop overlay stays full-viewport so the JS
   positioner can place the card anywhere on screen (and so the click-
   outside-to-close logic still works through the wrap), but the
   backdrop scrim + blur is removed and pointer-events skip the empty
   overlay — only the card itself receives clicks. The card's exact
   top / left is set inline by positionAnchoredPopover() per trigger
   geometry, with a flip-up + horizontal clamp so it always fits the
   viewport. Bottom sheet (mobile-V) and side panel (mobile-H) below
   keep the existing fullscreen / side treatment. */
/* Desktop + tablet (P + T variants — width ≥ 721 AND height ≥ 600):
   the date popover renders as a TRUE CENTERED MODAL in the middle of
   the viewport (NOT panel-confined). The full-viewport backdrop dims
   everything, the card centres at a comfortable working width, and
   the calendar + clocks live SIDE BY SIDE on desktop (flex-row) so
   the picker reads as one tight focus area. Mobile-V bottom sheet
   and mobile-H side panel below override with their own treatments. */
@media (min-width: 601px) and (min-height: 600px){
  .cb-date-pop{
    /* Restore the default full-viewport overlay from the base rule
       (panel-confined inset was a misread of the audit) and dim
       everything so the picker reads as a focused sub-task. */
    inset:0;
    width:auto;min-width:0;
    background:color-mix(in srgb, var(--scrim) 50%, transparent);
    -webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);
    padding:24px;
    align-items:center;justify-content:center;
  }
  html[dir="rtl"] .cb-date-pop{inset:0}
  .cb-date-pop-card{
    /* Wide enough to host calendar + clocks side-by-side at desktop
       sizes (~280 cal + ~330 clocks + gap + padding ≈ 660). Caps at
       viewport - 48 so even a tablet-narrow viewport stays inside.
       The card centres in the viewport, so its anchor is the screen
       middle in any direction. */
    width:auto;
    max-width:min(720px, calc(100vw - 48px));
    max-height:calc(100dvh - 80px);
  }
  /* Desktop / tablet keep the side-by-side flex-row layout for
     calendar + clocks — overrides the earlier blanket flex-column
     rule scoped to mobile-V. The clock col stays wide enough for
     HH/MM side-by-side via .cb-clocks below; the calendar col holds
     its 280px min-width. */
  .cb-date-pop-card .cb-datetime-layout{flex-direction:row}
}
/* Tablet specifically (P-wide but height-constrained portrait, or
   narrow tablet) — when the card has to squeeze under ~600px wide
   (viewport - 48 below ~648), stack calendar above clocks so neither
   col gets compressed below their min-width. */
/* Tablet band (601–1024, tall enough): stack calendar above clocks so neither
   col gets compressed below their min-width. (SH-01: the old never-matching
   `(min-width:721px) and (max-width:720px)` guard clause is gone — this is
   the sane re-expression.) */
@media (min-width: 601px) and (max-width: 1024px) and (min-height: 600px){
  .cb-date-pop-card .cb-datetime-layout{flex-direction:column}
  .cb-date-pop-card .cb-cal-col,
  .cb-date-pop-card .cb-cal-col-wide,
  .cb-date-pop-card .cb-clock-col,
  .cb-date-pop-card .cb-clock-col-wide{width:100%;min-width:0}
  /* ── B59 (Pablo: "On Tablet, the Close and Save buttons are cropped and outside of
     the modal. Please don't do that we already had this component down") ──────────
     Measured at 1000×700 (a landscape tablet — in this band by WIDTH, but far shorter
     than the portrait shapes this rule was written against): the card's content came
     to 686px inside an 618px box, and because `.cb-date-pop-card` is deliberately
     `overflow:visible` (so the timezone dropdown can escape it), the actions row —
     the last child — simply painted 27px BELOW the viewport, unreachable.

     The band above is what makes it tall: it stacks the calendar OVER the clocks, so
     a merged date+time step is roughly twice the height it is on desktop, while the
     fold is smaller. The fix is the pattern the mobile bands in this file already
     use: the LAYOUT scrolls and the chrome is pinned, so the footer is the one thing
     that can never be pushed off. It costs the dropdown's escape hatch inside this
     band only, which is the right trade against an unreachable Save. */
  .cb-date-pop-card{
    max-height:calc(100dvh - 48px);
    overflow:hidden;                   /* the card no longer grows past its box */
  }
  .cb-date-pop-card .cb-datetime-layout{
    flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;
  }
  /* B63 #032 (Pablo): a week-truncation picker has just a handful of
     week bars (.cb-cal-weeks-list) — far shorter than the merged
     date+time layout this scroll region is sized for — so forcing the
     same scroll here pushed the year/month header out of view for no
     reason. Let the card grow to fit instead; it only ever needs to
     for this mode. */
  .cb-date-pop-card .cb-datetime-layout:has(.cb-cal-weeks-list){
    overflow-y:visible;
  }
  .cb-date-pop-card .cb-range-step-hd{flex:0 0 auto}
  .cb-date-pop-card .cb-date-actions{
    flex:0 0 auto;position:sticky;bottom:0;z-index:2;
    background:var(--bg-1);border-top:1px solid var(--divider,var(--border));
    margin-top:0;padding-top:10px;
  }
}
/* Mobile Landscape (H) — render as a side panel anchored to the
   inline-end edge so the user can still see the field they were
   editing on the left. Width capped so a small landscape device
   still gets breathing room around the card. */
@media (max-height: 599px) and (orientation: landscape){
  .cb-date-pop{
    align-items:stretch;justify-content:flex-end;
    padding:0;
  }
  /* Side panel: full viewport height. B46 P6-ML01 — the old
     header / body / footer COLUMN was verified at a real landscape
     phone height (237px) and failed: chrome ate 98px of 237, leaving
     the body 89px of a ~280px calendar, so NOT ONE day cell was
     visible (the time step showed only the timezone row). At this
     height the chrome is what doesn't fit, so it moves to a second
     COLUMN — step header pinned top, actions pinned bottom, sharing
     one grid area via align-self — and the calendar / clocks get the
     card's full height. Width is the resource landscape has spare. */
  .cb-date-pop-card{
    width:min(520px, 75vw);max-width:75vw;
    height:100dvh;max-height:100dvh;
    border-radius:18px 0 0 18px;
    overflow:hidden;
    display:grid;
    grid-template-columns:minmax(0,1fr) 140px;
    grid-template-areas:"body chrome";
    align-items:stretch;
    gap:0 12px;padding:10px 12px;
    box-shadow:-12px 0 32px rgba(0,0,0,.22);
  }
  .cb-date-pop-card .cb-range-step-hd{
    grid-area:chrome;align-self:start;position:static;
    flex-direction:column;align-items:flex-start;gap:8px;
    padding:2px 0 0;background:transparent;
  }
  .cb-date-pop-card .cb-datetime-layout{
    grid-area:body;min-height:0;
    overflow-y:auto;overscroll-behavior:contain;
    /* The month/year `.cs-menu`s stay in layout when closed (opacity-
       hidden, app-wide pattern), so they inflate this box's scroll
       size even though the calendar itself fits. Scrollbars off: on a
       phone they are overlay anyway, and the visible desktop-style
       bars read as "content is cut off" when nothing is. */
    scrollbar-width:none;
    padding:0 12px 0 0;
    border-inline-end:1px solid var(--border);
    gap:12px;
    /* Two-column side-by-side at landscape — both shrink to fit */
    flex-direction:row;flex-wrap:wrap;align-items:flex-start;
  }
  .cb-date-pop-card .cb-datetime-layout::-webkit-scrollbar{width:0;height:0}
  html[dir="rtl"] .cb-date-pop-card .cb-datetime-layout{padding:0 0 0 12px}
  .cb-date-pop-card .cb-cal-col,
  .cb-date-pop-card .cb-cal-col-wide{flex:1 1 240px;min-width:0;max-width:340px}
  .cb-date-pop-card .cb-clock-col,
  .cb-date-pop-card .cb-clock-col-wide{flex:1 1 200px;min-width:0}
  /* The calendar column keeps the body centred rather than pinned to the
     top, so a taller landscape window doesn't read two-thirds empty.
     `safe` matters: this box scrolls, and plain centred alignment clips
     the top of anything taller than the box with no way to scroll back
     to it. Where `safe` is unsupported the declaration drops and the
     flex-start above stands — which is the correct fallback anyway. */
  .cb-date-pop-card .cb-datetime-layout{align-items:safe center;justify-content:safe center}
  .cb-date-pop-card .cb-date-actions{
    grid-area:chrome;align-self:end;
    flex-direction:column;align-items:stretch;gap:6px;
    padding:6px 0 max(0px, env(safe-area-inset-bottom));
    border-top:0;background:transparent;
  }
  .cb-date-pop-card .cb-date-actions > *{width:100%;justify-content:center}
  /* B46 P6-ML07 — see .cb-dur-pop: `flex-end` IS inline-end in both
     directions, so the RTL override that pinned this to the physical
     right (against its own rounded-left styling) is gone. */
  html[dir="rtl"] .cb-date-pop-card{
    border-radius:0 18px 18px 0;
    box-shadow:12px 0 32px rgba(0,0,0,.22);
  }
}
/* COMPACTION is a separate question from the 2-column restructure above.
   A 421-599px-tall landscape window fits the natural rhythm (chrome 126 +
   calendar 279 = 405) with room to spare, and shrinking cells there is a
   regression — 24px rows with 339px of dead space below them. So the
   tightening only applies where the fold genuinely cannot take it. */
@media (max-height: 420px) and (orientation: landscape){
  .cb-date-pop-card .cb-cal{gap:4px}
  .cb-date-pop-card .cb-cal-hd{padding-bottom:0;gap:6px}
  .cb-date-pop-card .cb-cal-dow-cell{padding:1px 0}
  .cb-date-pop-card .cb-cal-cell{height:24px;border-radius:7px}
  /* Dial is bounded by HEIGHT here, not width — and the time step's tz row
     + numeric row + dial have to clear ~215px together, so the section's
     own rhythm tightens with it. */
  .cb-date-pop-card .cb-time-section{gap:6px;padding:2px}
  .cb-date-pop-card .cb-time-row{padding:3px 8px}
  .cb-date-pop-card .cb-clocks .cb-clock{max-width:min(160px, 40vh)}
}

.cb-cal{display:flex;flex-direction:column;gap:6px}
.cb-cal-hd{
  display:flex;flex-wrap:wrap;align-items:center;gap:8px;
  padding-bottom:4px;
}
.cb-cal-year-ctl,
.cb-cal-month-ctl{
  display:inline-flex;align-items:center;gap:2px;
  flex:1;min-width:0;
}
.cb-cal-year-ctl{justify-content:flex-start}
/* B63 #031 (Pablo): the Next-month arrow sat right against the month
   dropdown's own chevron at the shared 2px gap — the two read as one
   overlapping cluster. The header has room to spare, so the month
   control gets its own wider gap instead of matching the year side. */
.cb-cal-month-ctl{justify-content:flex-end;gap:8px}
.cb-cal-nav{
  width:28px;height:28px;border-radius:7px;
  background:transparent;border:1px solid transparent;color:var(--fg-2);
  cursor:pointer;flex-shrink:0;
  display:inline-flex;align-items:center;justify-content:center;
  transition:background var(--mk-t-fast),border-color var(--mk-t-fast),color var(--mk-t-fast);
}
.cb-cal-nav:hover{background:var(--bg-2);border-color:var(--border);color:var(--fg-1)}
.cb-cal-nav .mi{font-size:16px}
html[dir="rtl"] .cb-cal-nav[data-year-nav="-1"] .mi::before,
html[dir="rtl"] .cb-cal-nav[data-month-nav="-1"] .mi::before{content:"chevron_right"}
html[dir="rtl"] .cb-cal-nav[data-year-nav="1"] .mi::before,
html[dir="rtl"] .cb-cal-nav[data-month-nav="1"] .mi::before{content:"chevron_left"}
.cb-cal-year-label{
  min-width:60px;height:28px;
  padding:0 10px;border-radius:7px;
  background:transparent;border:1px solid transparent;
  color:var(--fg-1);font:700 14px var(--mk-font-ui);
  cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center;
  font-variant-numeric:tabular-nums;
  transition:background var(--mk-t-fast),border-color var(--mk-t-fast);
}
.cb-cal-year-label:hover{background:var(--bg-2);border-color:var(--border)}
.cb-cal-year-input{
  min-width:74px;height:28px;
  padding:0 8px;border-radius:7px;
  background:var(--bg-input);border:1px solid var(--accent);
  color:var(--fg-1);font:700 14px var(--mk-font-ui);
  text-align:center;
  font-variant-numeric:tabular-nums;
  /* Hide spinners in webkit / firefox to stay consistent with the
     rest of the inputs in the modal. */
  -moz-appearance:textfield;
  appearance:textfield;
}
.cb-cal-year-input::-webkit-outer-spin-button,
.cb-cal-year-input::-webkit-inner-spin-button{display:none;margin:0}
.cb-cal-year-input:focus{outline:none}
.cb-cal-month-cs{position:relative;flex:1;min-width:0}
.cb-cal-month-cs > .cs-btn{
  display:flex;align-items:center;gap:6px;
  height:28px;padding:0 10px;border-radius:7px;
  background:transparent;border:1px solid transparent;
  color:var(--fg-1);font:600 13px var(--mk-font-ui);
  cursor:pointer;justify-content:space-between;
  min-width:96px;
  transition:background var(--mk-t-fast),border-color var(--mk-t-fast);
}
.cb-cal-month-cs > .cs-btn:hover{background:var(--bg-2);border-color:var(--border)}
.cb-cal-month-cs.open > .cs-btn{background:var(--bg-1);border-color:var(--accent)}
.cb-cal-month-cs > .cs-btn .cs-arrow{font-size:16px;color:var(--fg-3)}
.cb-cal-month-cs > .cs-menu{
  inset-inline-start:0;inset-inline-end:auto;
  min-width:140px;max-height:280px;overflow-y:auto;
  padding:4px;
}
.cb-cal-month-cs .cs-item{
  padding:6px 10px;border-radius:6px;
  font:500 13px var(--mk-font-ui);color:var(--fg-1);
  cursor:pointer;
}
.cb-cal-month-cs .cs-item:hover{background:color-mix(in srgb, var(--accent) 8%, transparent)}
.cb-cal-month-cs .cs-item.on{background:color-mix(in srgb, var(--accent) 14%, transparent);color:var(--accent)}

.cb-cal-dow{
  display:grid;
  grid-template-columns:repeat(7, 1fr);
  gap:2px;
  padding:0 2px;
}
.cb-cal-dow-cell{
  text-align:center;
  font:600 10px var(--mk-font-mono);
  color:var(--fg-3);letter-spacing:.06em;
  text-transform:none;
  padding:4px 0;
}
.cb-cal-grid{
  display:grid;
  grid-template-columns:repeat(7, 1fr);
  gap:2px;
}
.cb-cal-cell{
  height:34px;border-radius:8px;
  background:transparent;border:1px solid transparent;
  color:var(--fg-1);font:500 13px var(--mk-font-ui);
  cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center;
  transition:background var(--mk-t-fast),border-color var(--mk-t-fast),color var(--mk-t-fast);
}
.cb-cal-cell.blank{cursor:default;pointer-events:none}
.cb-cal-cell:not(.blank):hover{background:var(--bg-2);border-color:var(--border)}
.cb-cal-cell.is-today{
  color:var(--accent);
  border-color:color-mix(in srgb, var(--accent) 30%, transparent);
}
.cb-cal-cell.on{
  background:var(--accent);border-color:var(--accent);color:var(--accent-fg);
}
.cb-cal-cell.on:hover{background:var(--accent);color:var(--accent-fg)}
/* B63 #029 — live preview while a touch drag is over this cell (finger
   still down, nothing committed yet). Distinct from `.on` (committed)
   so the user can tell "hovering here" from "picked". */
.cb-cal-cell-dragging{
  background:color-mix(in srgb, var(--accent) 22%, transparent);
  border-color:var(--accent);
}
/* Range trace — the "between" days get a soft accent fill. The start
   and end retain the solid .on selected style; the trace just unifies
   them visually. */
.cb-cal-cell.in-range{
  background:color-mix(in srgb, var(--accent) 14%, transparent);
  border-color:transparent;
  color:var(--fg-1);
  border-radius:0;
}
.cb-cal-cell.range-start{border-end-end-radius:0;border-start-end-radius:0}
.cb-cal-cell.range-end  {border-end-start-radius:0;border-start-start-radius:0}
html[dir="rtl"] .cb-cal-cell.range-start{border-end-start-radius:0;border-start-start-radius:0;border-end-end-radius:8px;border-start-end-radius:8px}
html[dir="rtl"] .cb-cal-cell.range-end  {border-end-end-radius:0;border-start-end-radius:0;border-end-start-radius:8px;border-start-start-radius:8px}
/* Constraint-disabled cells — outside the field's min/max window.
   Keep them readable but visibly not-pickable; the button is also
   `disabled` in HTML so the click never reaches the day-pick handler. */
.cb-cal-cell.is-disabled{
  color:color-mix(in srgb, var(--fg-3) 60%, transparent);
  cursor:not-allowed;
  text-decoration:line-through;
  text-decoration-color:color-mix(in srgb, var(--fg-3) 40%, transparent);
}
.cb-cal-cell.is-disabled:hover{background:transparent;border-color:transparent}
.cb-cal-cell:focus-visible{
  outline:2px solid var(--accent);outline-offset:1px;
}

/* Today / Clear shortcut row — pinned at the bottom of the date
   popover, separated from the calendar/clock by a subtle divider. */
.cb-date-actions{
  display:flex;align-items:center;justify-content:space-between;gap:8px;
  padding-top:8px;
  border-top:1px solid var(--border);
}
.cb-date-action{
  display:inline-flex;align-items:center;gap:6px;
  height:30px;padding:0 12px;border-radius:8px;
  background:transparent;border:1px solid var(--border);
  color:var(--fg-1);font:600 12px var(--mk-font-ui);
  cursor:pointer;
  transition:background var(--mk-t-fast),border-color var(--mk-t-fast),color var(--mk-t-fast);
}
.cb-date-action:hover{
  background:color-mix(in srgb, var(--accent) 8%, transparent);
  border-color:var(--accent);color:var(--accent);
}
.cb-date-action .mi{font-size:14px}
[data-cb-date-clear]:hover{
  border-color:var(--mk-danger);color:var(--mk-danger);
  background:color-mix(in srgb, var(--mk-danger) 10%, transparent);
}

/* Time section. In range mode this lists two rows (From / To) above a
   single shared clock; the active row gets a tinted background and
   the clock writes back to that slot. */
.cb-time-section{
  display:flex;flex-direction:column;gap:10px;
  padding:6px 4px;
}
/* Section gating: dim + freeze interactions until a date exists, and
   keep clocks visually inert until the user clicks an HH/MM input.
   The dimming intentionally cascades through descendants so users
   read the whole control as "not yet". */
.cb-time-section.is-no-date{
  opacity:.45;
  pointer-events:none;
}
.cb-time-section.is-inactive .cb-clocks{
  opacity:.55;
}
.cb-time-section.is-inactive .cb-clock{
  cursor:not-allowed;
}
.cb-time-section.is-active .cb-clock{cursor:pointer}

/* Top bar — timezone selector + 12h/24h format toggle on the same row. */
.cb-time-top{
  display:flex;align-items:center;gap:8px;
  flex-wrap:wrap;
}
.cb-time-top .cb-tz{flex:1;min-width:200px}
.cb-fmt-toggle{
  display:inline-flex;
  border-radius:8px;overflow:hidden;
  border:1px solid var(--border);
  background:var(--bg-input);
  flex-shrink:0;
}
.cb-fmt-toggle button{
  background:transparent;border:0;
  padding:6px 10px;height:32px;
  font:600 11px var(--mk-font-mono);color:var(--fg-2);
  cursor:pointer;letter-spacing:.04em;
  transition:background var(--mk-t-fast),color var(--mk-t-fast);
}
.cb-fmt-toggle button.on{background:var(--accent);color:var(--accent-fg)}
.cb-fmt-toggle button:hover:not(.on){background:color-mix(in srgb, var(--accent) 10%, transparent)}

/* AM / PM segment inside a time row — shows up only in 12h mode. */
.cb-time-ampm{
  display:inline-flex;
  border-radius:6px;overflow:hidden;
  border:1px solid var(--border);
  background:var(--bg-input);
  margin-inline-start:4px;
  flex-shrink:0;
}
.cb-time-ampm button{
  background:transparent;border:0;
  padding:0 8px;height:28px;
  font:600 10px var(--mk-font-mono);color:var(--fg-2);
  cursor:pointer;letter-spacing:.04em;
  transition:background var(--mk-t-fast),color var(--mk-t-fast);
}
.cb-time-ampm button.on{background:var(--accent);color:var(--accent-fg)}

/* 12h mode — soften the AM (outer) ring and lift the PM (inner) ring so
   the user reads the dual circumference as "morning shade vs. evening
   shade". 24h mode keeps both rings at equal intensity. */
.cb-clocks.is-12h .cb-clock-pos-outer circle{
  fill:transparent;
}
.cb-clocks.is-12h .cb-clock-pos-outer text{
  fill:var(--fg-3);
}
.cb-clocks.is-12h .cb-clock-pos-inner circle{
  fill:transparent;
}
/* The PM shade is ONE disc under the whole inner numeral circle (Pablo,
   DS review 2026-07-07) — not a tint per number. */
.cb-clock-inner-disc{
  fill:color-mix(in srgb, var(--accent) 9%, transparent);
  stroke:color-mix(in srgb, var(--accent) 22%, transparent);
  stroke-width:1;
}
.cb-clocks.is-12h .cb-clock-pos-inner text{
  fill:color-mix(in srgb, var(--accent) 80%, var(--fg-1));
}
.cb-clocks.is-12h .cb-clock-pos.on circle{
  fill:var(--accent);
}
.cb-clocks.is-12h .cb-clock-pos.on text{
  fill:var(--accent-fg);
}
.cb-time-rows{display:flex;flex-direction:column;gap:6px}
.cb-time-row{
  display:flex;align-items:center;gap:6px;
  padding:6px 8px;border-radius:8px;
  background:var(--bg-2);
  border:1px solid transparent;
  transition:background var(--mk-t-fast),border-color var(--mk-t-fast);
}
.cb-time-row.active{
  background:color-mix(in srgb, var(--accent) 12%, transparent);
  border-color:var(--accent);
}
.cb-time-row-l{
  font:600 10px var(--mk-font-mono);color:var(--fg-3);
  text-transform:none;letter-spacing:.08em;
  min-width:36px;
}
.cb-time-icon{color:var(--accent);font-size:18px}
.cb-time-input{
  width:46px;height:30px;border-radius:6px;
  background:var(--bg-input);border:1px solid var(--border);
  color:var(--fg-1);font:600 14px var(--mk-font-mono);
  text-align:center;
  font-variant-numeric:tabular-nums;
  transition:border-color var(--mk-t-fast);
}
.cb-time-input:focus{outline:none;border-color:var(--accent)}
.cb-time-sep{font:700 14px var(--mk-font-mono);color:var(--fg-2)}
/* Millisecond box (truncation:millisecond) — typed only, no dial. */
.cb-time-input.cb-time-ms{width:56px}
.cb-time-ms-l{font:600 10px var(--mk-font-ui);color:var(--fg-3)}
/* B63 #003 (Pablo): on mobile portrait, a millisecond row (label/icon +
   HH + MM + SS + MS box+label + AM/PM segment) is the widest the row
   ever gets — at the fixed 6px gap it overflowed the popover card. The
   gap shrinks with viewport width instead of staying fixed, and the
   fields themselves narrow a touch, so the row always fits. */
@media (max-width: 599px) and (orientation: portrait){
  .cb-time-row{ gap:clamp(2px, 1.2vw, 6px); padding:6px 6px; }
  .cb-time-row-l{ min-width:0; }
  .cb-time-input{ width:40px; }
  .cb-time-input.cb-time-ms{ width:44px; }
  .cb-time-ms-l{ margin-inline-start:-2px; }
}

/* Clock circles — one for hours, one for minutes. The active position
   highlights with the accent fill and a line from the centre traces
   the "hand" so the value reads at a glance. */
.cb-clocks{
  display:flex;gap:12px;justify-content:center;
  /* Allow the HH/MM clock row to wrap when the side-by-side combined
     date+time view squeezes either subdial below the legibility floor
     (~160px each). At that point the two clocks stack vertically inside
     the same clock-col so HH lives above MM rather than next to it. */
  flex-wrap:wrap;
}
.cb-clock-block{
  display:flex;flex-direction:column;align-items:center;gap:6px;
  /* Each subdial reserves at least 160px so a tap-sized clock face fits
     even after the +6px label height is factored in. Falling under this
     would shave the SVG to ~140px in the combined view; flex-basis lets
     siblings still grow when there's room. */
  flex:1 1 160px;min-width:160px;
}
.cb-clock-lbl{
  font:600 10px var(--mk-font-mono);color:var(--fg-3);
  text-transform:none;letter-spacing:.08em;
}
.cb-clock{
  width:100%;max-width:180px;aspect-ratio:1/1;
  display:block;
  /* A whisper of depth so the dial reads as a physical face. */
  filter:drop-shadow(0 1px 2px color-mix(in srgb, var(--fg-1) 10%, transparent));
}
.cb-clock-bg{
  fill:var(--bg-2);
  stroke:var(--border);stroke-width:1;
}
.cb-clock-pos{cursor:pointer}
.cb-clock-pos circle{
  fill:transparent;
  transition:fill var(--mk-t-fast);
}
.cb-clock-pos:hover circle{fill:color-mix(in srgb, var(--accent) 14%, transparent)}
/* B24 polish (Pablo: "open to a slight improvement") — the selected dot
   wears a soft accent halo so the active value pops without extra chrome. */
.cb-clock-pos.on circle{fill:var(--accent);stroke:color-mix(in srgb, var(--accent) 28%, transparent);stroke-width:3}
/* Range-mode endpoint highlights — both slot positions are visible at
   once but only the ACTIVE slot wears the strong fill. The passive
   endpoint sits on a softer tint so the user still sees where the
   other end of the span is. */
.cb-clock-pos.is-a:not(.is-active) circle,
.cb-clock-pos.is-b:not(.is-active) circle{
  fill:color-mix(in srgb, var(--accent) 35%, transparent);
}
.cb-clock-pos.is-active circle{fill:var(--accent)}
.cb-clock-pos text{
  fill:var(--fg-2);
  font:600 9px var(--mk-font-mono);
  pointer-events:none;
  font-variant-numeric:tabular-nums;
}
/* Dual-ring hour clock — both rings use equal-weight dots and labels
   so the outer (AM 0..11) stops bleeding past the background circle
   and the inner (PM 12..23) stops feeling oversized. Labels stay
   small enough to fit inside the 6px-radius dots at any clock size. */
.cb-clock-pos-outer text{font-size:6px;font-weight:700}
.cb-clock-pos-inner text{font-size:6px;font-weight:700}
.cb-clock-pos.on text,
.cb-clock-pos.is-active text,
.cb-clock-pos.is-a text,
.cb-clock-pos.is-b text{fill:var(--accent-fg)}
/* Faint guide circles for the two hour rings — outer = AM, inner = PM
   — keep the dual-ring intent legible even at small sizes. */
.cb-clock-ring-trace{
  stroke:color-mix(in srgb, var(--border) 70%, transparent);
  stroke-width:1; stroke-dasharray:2 3;
  fill:none; pointer-events:none;
}
/* Drag-aware clocks: the SVG itself receives the pointer; individual
   dots stay decorative so the cursor never gets stuck on a label. */
.cb-clock{ touch-action:none; cursor:pointer; user-select:none; }
.cb-clock-bead{
  fill:var(--accent); pointer-events:none;
  stroke:var(--bg-1); stroke-width:1;
}
.cb-clock-rings{
  display:flex;flex-direction:column;gap:2px;align-items:center;
  margin-top:2px;
}
/* The legend ONLY appears in 12h mode (where both rings share 1..12
   labels and need disambiguation). 24h mode never renders the
   .cb-clock-rings wrapper, so this rule is purely defensive: should
   stale markup survive a render path we haven't audited, the legend
   stays hidden whenever the parent dial isn't in 12h mode. */
.cb-clocks:not(.is-12h) .cb-clock-rings{display:none}
/* When only the hour clock is rendered (truncation:'hour'), the lone
   block was stretching to fill the row via flex:1 — the SVG still
   capped at max-width:160px so it looked centered, but the surrounding
   space and labels (HH) drifted unevenly when the popover width
   changed. Lock the block to its content and let the parent's existing
   justify-content:center keep it visually balanced. */
/* `is-single` = exactly one clock (hour-only field, OR the mobile split
   where each of hour/minute/second is its own step — Pablo 2026-06-02 W2
   #9). Reuse the centered, larger hour-only treatment so the lone clock
   fills the step at full size. */
.cb-clocks.is-hour-only,
.cb-clocks.is-single{justify-content:center}
.cb-clocks.is-hour-only .cb-clock-block,
.cb-clocks.is-single .cb-clock-block{flex:0 0 auto;width:auto;max-width:200px}

/* Mobile-V (portrait): keep the clocks side-by-side so the bottom
   sheet never needs to scroll for them. The clock dial shrinks with
   the available width via flex:1 — each clock claims an equal share
   of the row, capped at min(38vw, 150px) so they stay readable. */
@media (max-width: 600px) and (orientation: portrait){
  .cb-clocks{flex-direction:row;gap:8px;flex-wrap:nowrap;align-items:flex-start;justify-content:center}
  .cb-clock-block{flex:1 1 0;min-width:0;max-width:none}
  .cb-clock{max-width:min(38vw, 150px);margin-inline:auto}
}
/* Hour-only mode on mobile-V — single dial gets the whole row but
   capped tighter so the bottom sheet stays compact. */
@media (max-width: 600px) and (orientation: portrait){
  .cb-clocks.is-hour-only .cb-clock-block,
  .cb-clocks.is-single .cb-clock-block{flex:0 0 auto;width:auto}
  .cb-clocks.is-hour-only .cb-clock,
  .cb-clocks.is-single .cb-clock{max-width:min(60vw, 200px)}
}
.cb-clock-ring-l{
  font:500 10px var(--mk-font-mono);color:var(--fg-3);
  letter-spacing:.05em;
}
.cb-clock-ring-l.ring-out::before{content:'○ '; color:var(--fg-3)}
.cb-clock-ring-l.ring-in::before{content:'● '; color:var(--accent)}

/* Timezone selector — sits above the time rows; same .cs visual
   language as the other dropdowns so it feels like a modal-native
   control. The offset tag is monospaced for vertical alignment. */
.cb-tz{
  display:flex;align-items:center;gap:8px;
  padding:0 2px;
}
.cb-tz-lbl{
  font:600 10px var(--mk-font-mono);color:var(--fg-3);
  letter-spacing:.08em;text-transform:none;
  flex-shrink:0;
}
.cb-tz-cs{position:relative;flex:1;min-width:0}
.cb-tz-cs > .cs-btn{
  display:flex;align-items:center;gap:8px;
  height:32px;padding:0 10px;border-radius:8px;
  background:var(--bg-input);border:1px solid var(--border);
  color:var(--fg-1);font:500 12px var(--mk-font-ui);
  cursor:pointer;
  transition:border-color var(--mk-t-fast);
}
.cb-tz-cs > .cs-btn:hover{border-color:color-mix(in srgb, var(--accent) 40%, var(--border))}
.cb-tz-cs.open > .cs-btn{border-color:var(--accent)}
.cb-tz-cs > .cs-btn .cs-val{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:start}
.cb-tz-off{
  font:600 10px var(--mk-font-mono);color:var(--fg-3);
  font-variant-numeric:tabular-nums;
  padding:1px 6px;border-radius:5px;
  background:var(--bg-2);
  flex-shrink:0;
}
.cb-tz-cs > .cs-menu{
  inset-inline-start:0;inset-inline-end:auto;
  min-width:240px;max-height:280px;overflow-y:auto;
  padding:4px;
}
.cb-tz-cs .cs-item{
  display:flex;align-items:center;gap:8px;
  padding:7px 10px;border-radius:6px;
  font:500 12px var(--mk-font-ui);color:var(--fg-1);
  cursor:pointer;
}
.cb-tz-cs .cs-item:hover{background:color-mix(in srgb, var(--accent) 8%, transparent)}
.cb-tz-cs .cs-item.on{background:color-mix(in srgb, var(--accent) 14%, transparent);color:var(--accent)}
.cb-tz-cs .cs-item .cb-tz-l{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* Range arc — traces the clockwise sweep from slot A to slot B at the
   clock's mid-radius. Paints UNDER the position dots (rendered first
   in the SVG order) so each endpoint dot sits on the arc, reading as
   "the span goes from here to here". */
.cb-clock-arc{
  stroke:var(--accent);stroke-width:5;stroke-linecap:round;
  opacity:.32;
  pointer-events:none;
}
.cb-clock-hand{
  stroke:var(--accent);stroke-width:2.5;stroke-linecap:round;
  pointer-events:none;
}
.cb-clock-pivot{
  fill:var(--accent);
  stroke:var(--bg-1);stroke-width:1;
  pointer-events:none;
}
.cb-ampm{
  display:inline-flex;
  border-radius:7px;overflow:hidden;
  border:1px solid var(--border);
  background:var(--bg-input);
}
.cb-ampm button{
  background:transparent;border:0;
  padding:6px 10px;
  font:600 11px var(--mk-font-ui);color:var(--fg-2);
  cursor:pointer;
}
.cb-ampm button.on{background:var(--accent);color:var(--accent-fg)}

/* ─────────────────────────────────────────────────────────────────
   SORT PANEL — slide-in chrome (shared with .filter-panel). Each row is
   grip + field chip (opens cb-field-picker in sort mode) + direction
   segmented + nulls-position segmented + remove. The list scrolls
   inside the panel; "+ Add sort" sits at the end as a dashed-accent
   button (.fp-add) — same affordance as Filter's "+ AND" / "+ OR".
   ───────────────────────────────────────────────────────────────── */
.sort-list{
  display:flex;flex-direction:column;gap:8px;
  flex:1;min-height:0;overflow-y:auto;
  padding-bottom:8px;
}
.sort-row{
  display:grid;
  /* grip | inline picker | acts cluster */
  grid-template-columns:auto 1fr auto;
  align-items:center;gap:8px;
  padding:8px 10px;border-radius:9px;
  background:var(--bg-2);border:1px solid var(--border);
}
/* A row whose field path isn't a complete sortable terminal — ring only the
   EMPTY (trailing) dropdown, not the whole row (Pablo 2026-06-19: "the whole
   div shouldn't have the required outline, just the dropdown that is empty").
   Mirrors the cond-builder's `.cb-section.is-required … .is-trailing` rule. */
.sort-row.is-incomplete .cb-field-seg.is-trailing > .cs-btn{
  box-shadow:0 0 0 2px color-mix(in srgb, var(--mk-warning) 60%, transparent);
  border-color:color-mix(in srgb, var(--mk-warning) 60%, var(--border));
}
.sort-row.is-incomplete .cb-field-seg.is-trailing > .cs-btn:focus-within{
  box-shadow:0 0 0 2px color-mix(in srgb, var(--accent) 50%, transparent);
  border-color:var(--accent);
}
.sort-row-acts{
  display:inline-flex;align-items:center;gap:6px;flex-shrink:0;
}
/* C2 (Pablo B19): while the sort key's path is incomplete, hide the whole acts
   cluster (scope / direction / remove) — those controls only make sense once
   the full path is chosen. A subtle discard-X (.sort-rm-draft) takes its place
   so an unfinished row is never a dead end. */
/* B21 C10 (Pablo, across the board): while a row's field path is being
   EDITED (any dropdown in the picker is open), the trailing action cluster
   (direction / remove / partition‧order‧filter) hides — matching the
   PathInput component contract (acts show only in the resting state). */
/* B34 C30 (Pablo 2026-07-11): the remove-X must ALWAYS be visible while the
   path is still being filled/edited — "regret-delete needs it before the path
   is complete". Reverses B32's blanket acts hide: keep the acts cluster present
   so the remove-X stays reachable, but continue hiding only the scope /
   direction controls (which are meaningless until the path resolves). */
.cb-wf-inline:has(.cs.open) .cb-field-picker-ctl{display:none}
.sort-row:has(.sort-field-picker .cs.open) .sort-row-acts,
.cb-field-picker:has(> .cb-field-seg.cs.open) ~ .sort-row-acts,
.sort-row.is-incomplete .sort-row-acts{display:inline-flex}
.sort-row:has(.sort-field-picker .cs.open) .sort-row-acts > :is(.sort-scope-btn,.sort-dir-btn),
.cb-field-picker:has(> .cb-field-seg.cs.open) ~ .sort-row-acts > :is(.sort-scope-btn,.sort-dir-btn),
.sort-row.is-incomplete .sort-row-acts > :is(.sort-scope-btn,.sort-dir-btn){display:none}
.sort-rm-draft{
  width:30px;height:30px;border-radius:7px;flex-shrink:0;
  display:inline-flex;align-items:center;justify-content:center;
  border:1px solid transparent;background:transparent;color:var(--fg-3);
  cursor:pointer;transition:color var(--mk-t-fast),background var(--mk-t-fast);
}
.sort-rm-draft:hover{
  color:var(--mk-danger,#d64545);
  background:color-mix(in srgb, var(--mk-danger,#d64545) 12%, transparent);
}
.sort-rm-draft .mi{font-size:18px}
.sort-scope-btn,
.sort-dir-btn{
  width:30px;height:30px;border-radius:7px;
  border:1px solid var(--border);background:var(--bg-input);
  color:var(--fg-2);cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center;
  position:relative;
  transition:border-color var(--mk-t-fast), color var(--mk-t-fast);
}
.sort-scope-btn:hover,
.sort-dir-btn:hover{
  color:var(--accent);border-color:var(--accent);
}
.sort-scope-btn .mi,
.sort-dir-btn .mi{font-size:15px}
.sort-scope-btn.has-scope{
  background:color-mix(in srgb, var(--accent) 14%, transparent);
  color:var(--accent);border-color:var(--accent);
}
.sort-scope-count{
  position:absolute;top:-4px;inset-inline-end:-4px;
  background:var(--accent);color:var(--bg-1);
  min-width:14px;height:14px;border-radius:999px;
  font:700 9px var(--mk-font-ui);
  display:inline-flex;align-items:center;justify-content:center;
  padding:0 3px;
}
.sort-row.dragging{opacity:.45}
.sort-row.drop-before{box-shadow:inset 0 2px 0 var(--accent)}
.sort-row.drop-after{box-shadow:inset 0 -2px 0 var(--accent)}
/* Slimmer inline picker for sort rows — a sort key is a single field, so
   the 46px touch target the filter cond-builder uses is unnecessary here
   and made the rows feel oversized. The markup nests a real .cb-field-
   picker inside the .sort-field-picker wrapper, so collapse the wrapper
   (display:contents) and slim the inner box. Pablo 2026-06-01. */
.sort-row{padding:6px 8px}
.sort-field-picker{display:contents}
.sort-list .sort-field-picker > .cb-field-picker{min-height:32px;padding:2px}
.sort-list .sort-field-picker .cb-field-seg > .cs-btn{height:28px;padding:0 8px}
.sort-list .sort-field-picker .cb-field-seg + .cb-field-seg::before{font-size:16px;margin:0 1px}
/* B22 (Pablo): grip / row-number bubble REMOVED — the whole .sort-row box is
   the drag affordance (it already carries draggable). Grab cursor on the row
   chrome; interactive chips/buttons inside reset it. */
.sort-row{cursor:grab}
.sort-row:active{cursor:grabbing}
.sort-row :is(button,input,.cs,.cb-field-seg){cursor:pointer}
.sort-row.dragging{cursor:grabbing}

/* Field chip — mirrors the cb-field-picker breadcrumb (icon + label +
   chevron separators) but as a single clickable button. Opens the
   shared cond-builder modal in sort mode on click. */
.sort-field-chip{
  display:inline-flex;align-items:center;gap:6px;min-width:0;
  height:32px;padding:0 10px;border-radius:7px;
  background:var(--bg-input);border:1px solid var(--border);
  color:var(--fg-1);cursor:pointer;
  font:500 12px var(--mk-font-ui);text-align:start;
  transition:border-color var(--mk-t-fast), color var(--mk-t-fast);
}
.sort-field-chip:hover{border-color:var(--accent);color:var(--accent)}
.sort-field-chip.is-empty{
  border-style:dashed;color:var(--fg-3);background:transparent;
}
.sort-field-chip .sort-chip-seg{
  display:inline-flex;align-items:center;gap:4px;min-width:0;
}
.sort-field-chip .sort-chip-seg .mi{font-size:13px;color:var(--fg-3)}
.sort-field-chip .sort-chip-l{
  overflow:hidden;white-space:nowrap;text-overflow:ellipsis;max-width:140px;
}
.sort-field-chip .sort-chip-sep{font-size:13px;color:var(--fg-3);flex-shrink:0}
.sort-field-chip .sort-chip-edit{
  font-size:13px;color:var(--fg-3);margin-inline-start:auto;flex-shrink:0;
}
.sort-field-chip:hover .sort-chip-edit{color:var(--accent)}
.sort-field-chip.is-empty .sort-chip-edit{display:none}
.sort-field-chip .sort-chip-empty-l{font-style:italic}

/* Segmented controls — direction (asc/desc) + nulls position (first/
   last). Independent: switching direction never auto-flips nulls. */
.sort-seg{
  display:inline-flex;background:var(--bg-input);border:1px solid var(--border);
  border-radius:7px;overflow:hidden;
}
.sort-seg button{
  width:28px;height:30px;background:transparent;border:0;
  color:var(--fg-2);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;
}
.sort-seg button .mi{font-size:15px}
.sort-seg button.on{background:color-mix(in srgb, var(--accent) 16%, transparent);color:var(--accent)}

.sort-rm{
  width:28px;height:30px;border-radius:7px;
  border:1px solid var(--border);background:var(--bg-input);
  color:var(--fg-3);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;
}
.sort-rm:hover{color:var(--mk-danger);border-color:var(--mk-danger)}
.sort-rm .mi{font-size:15px}
.sort-empty{
  display:flex;flex-direction:column;align-items:center;gap:8px;
  padding:36px 16px;color:var(--fg-3);
  font:500 12px var(--mk-font-ui);text-align:center;
}
.sort-empty .mi{font-size:28px}
.sort-add{margin-top:4px;align-self:flex-start}

/* Mobile-V: keep everything on ONE row — grip · field · dir/scope/remove.
   The slim picker leaves enough width, and Pablo 2026-06-01 #8 didn't want
   the action buttons bumped to a second row. */
@media (max-width: 600px){ /* SH-07: 720 → 600 — compact grid is a mobile treatment */
  .sort-row{
    grid-template-columns:auto 1fr auto;
    grid-template-areas:none;
    row-gap:0;
  }
  .sort-row-acts{justify-self:end;gap:4px}
  .sort-field-chip .sort-chip-l{max-width:none}
}

/* ─────────────────────────────────────────────────────────────────
   ALERTS MODAL — the list scrolls inside the modal so a long backlog
   never spills past the modal card. Unread rows get an accent dot, a
   denser background and bolder title; read rows fade back. Clicking
   a row toggles its read state.
   ───────────────────────────────────────────────────────────────── */
#alertsModal .panel-card{max-height:min(640px, calc(100dvh - 48px))}
#alertsModal .panel-body{padding:0;overflow:hidden;display:flex}
/* Mobile modal behaviour (Pablo 2026-07-12): the Alerts modal should behave
   like the other mobile modals — a BOTTOM SHEET in portrait, a right-edge
   SIDE PANEL in landscape (same pattern as the profile sub-sheet). Scoped to
   #alertsModal so it wins over the generic centered `.panel-card` rules. */
@media (max-width:600px) and (orientation:portrait){
  #alertsModal{align-items:flex-end;justify-content:stretch;padding:0}
  #alertsModal .panel-card{
    width:100%;max-width:100%;max-height:86dvh;
    border-radius:18px 18px 0 0;border-inline-width:0;border-bottom:0;
    transform:translateY(100%);transition:transform 260ms var(--mk-ease);
  }
  #alertsModal.open .panel-card{transform:none}
}
@media (max-height:599px) and (orientation:landscape){
  #alertsModal{align-items:stretch;justify-content:flex-end;padding:0}
  #alertsModal .panel-card{
    height:100%;max-height:100%;width:min(420px, 92vw);
    border-radius:0;border-block-width:0;border-inline-end:0;
    transform:translateX(100%);transition:transform 260ms var(--mk-ease);
  }
  #alertsModal.open .panel-card{transform:none}
  html[dir="rtl"] #alertsModal .panel-card{transform:translateX(-100%)}
  html[dir="rtl"] #alertsModal.open .panel-card{transform:none}
}
.alerts-list{
  flex:1;min-height:0;
  display:flex;flex-direction:column;gap:8px;
  padding:14px 16px;overflow-y:auto;
}
.alert-row{
  display:grid;
  grid-template-columns:32px 1fr auto;
  gap:10px;align-items:flex-start;
  padding:10px;border-radius:10px;
  background:var(--bg-2);border:1px solid var(--border);
  cursor:pointer;
  transition:background var(--mk-t-fast),border-color var(--mk-t-fast),opacity var(--mk-t-fast);
}
.alert-row:hover{border-color:color-mix(in srgb, var(--accent) 40%, var(--border))}
.alert-row.is-unread{
  background:color-mix(in srgb, var(--accent) 6%, var(--bg-2));
  border-color:color-mix(in srgb, var(--accent) 30%, var(--border));
}
.alert-row.is-unread .alert-title{font-weight:700}
.alert-row.is-read{opacity:.65}
.alert-icon{
  width:32px;height:32px;border-radius:9px;
  display:inline-flex;align-items:center;justify-content:center;
  background:color-mix(in srgb, var(--accent) 12%, transparent);color:var(--accent);
  flex-shrink:0;
}
.alert-icon .mi{font-size:18px}
.alert-row.kind-warn .alert-icon{background:color-mix(in srgb, var(--mk-warning) 16%, transparent);color:var(--mk-warning)}
.alert-row.kind-success .alert-icon{background:color-mix(in srgb, var(--mk-success) 16%, transparent);color:var(--mk-success)}
.alert-row.kind-danger .alert-icon{background:color-mix(in srgb, var(--mk-danger) 16%, transparent);color:var(--mk-danger)}
.alert-meta{min-width:0;display:flex;flex-direction:column;gap:2px}
.alert-title{font:600 13px var(--mk-font-ui);color:var(--fg-1)}
.alert-body{font:500 12px var(--mk-font-ui);color:var(--fg-2);line-height:1.5}
.alert-side{display:flex;flex-direction:column;align-items:flex-end;gap:6px}
.alert-dot{
  width:8px;height:8px;border-radius:999px;background:var(--accent);
  flex-shrink:0;
  box-shadow:0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}
.alert-row.is-read .alert-dot{display:none}
.alert-time{font:500 10px var(--mk-font-mono);color:var(--fg-3);white-space:nowrap}
.alerts-empty{
  padding:36px 16px;text-align:center;color:var(--fg-3);
  font:500 12px var(--mk-font-ui);
  display:flex;flex-direction:column;align-items:center;gap:8px;
}
.alerts-empty .mi{font-size:28px;color:var(--fg-3)}

/* ─────────────────────────────────────────────────────────────────
   SEARCH MODAL — V7 pattern.
   - Desktop/tablet: dropdown anchored directly to the navbar search
     bar (which IS the live input). The modal's own header and input
     wrap are hidden — only chips + results show. JS sets top/left/
     width inline so the dropdown's left edge aligns with the bar's
     left edge.
   - Mobile-V / Mobile-H: full-screen overlay with blurred backdrop.
     The navbar bar is hidden at these breakpoints, so the modal's
     own input + header come back as the typing surface.
   ───────────────────────────────────────────────────────────────── */
#searchModal{align-items:flex-start;justify-content:center;padding:0}
#searchModal .panel-card{
  /* JS sets top/left/width inline on desktop/tablet; CSS defaults are
     the "centered" fallback (used if JS never runs). */
  position:fixed;
  top:calc(var(--mk-nav-h) + 6px);
  left:50%;transform:translateX(-50%);
  width:min(640px, calc(100% - 32px));
  max-height:min(560px, calc(100dvh - var(--mk-nav-h) - 32px));
  border-radius:12px;
}
html[dir="rtl"] #searchModal .panel-card{transform:translateX(50%)}
/* Desktop/tablet: the navbar bar owns the input. The modal collapses
   to chips + results only — no redundant header or second input.
   Mobile breakpoints below restore both. */
#searchModal .panel-hd,
#searchModal .search-input-wrap{display:none}
/* Desktop/tablet dropdown mode: the overlay must NOT intercept clicks,
   so the navbar input stays editable while the panel floats over body
   content. Only the panel-card catches pointer events. Mobile media
   queries below re-enable overlay pointer events for the full-screen
   sheet pattern. JS handles outside-click close via a document-level
   listener while the dropdown is open. */
#searchModal{pointer-events:none}
#searchModal .panel-card{pointer-events:auto}

/* Mobile-V & Mobile-H: full-screen overlay with a blurred backdrop so
   the dashboard reads through. The navbar bar is hidden at these
   breakpoints, so we restore the modal's header + input as the only
   typing surface. */
@media (max-width: 600px) and (orientation: portrait),
       (max-height: 599px) and (orientation: landscape){
  /* Mobile breakpoints: restore overlay pointer events so taps on the
     blurred backdrop close the modal (V7 mobile sheet pattern). */
  #searchModal{pointer-events:auto;background:color-mix(in srgb, var(--scrim) 70%, transparent);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}
  #searchModal .panel-card{
    position:fixed;
    top:0;bottom:0;left:0;right:0;
    transform:none;
    width:100%;max-width:100%;
    max-height:none;
    border-radius:0;
    /* Card itself stays opaque so results don't fight the blur — the
       blur sits on the overlay BEHIND the card. */
    background:var(--bg-1);
  }
  html[dir="rtl"] #searchModal .panel-card{transform:none}
  /* Header sits above the input with extra breathing room so the
     title and the typing surface don't visually fight. */
  #searchModal .panel-hd{display:flex;padding:14px 14px 4px}
  #searchModal .search-input-wrap{display:flex;margin:12px 14px 8px;height:44px}
}
/* Mobile-H specifically — slightly tighter spacing so input + a couple
   of result rows fit above the on-screen keyboard at the shortest
   heights, while still giving the header-to-input gap room to breathe. */
@media (max-height: 599px) and (orientation: landscape){
  #searchModal .panel-hd{padding:10px 12px 4px;border-bottom:0}
  #searchModal .search-input-wrap{height:38px;margin:10px 14px 6px}
  #searchModal .search-chips{padding:0 12px 6px}
  #searchModal .search-chip{padding:4px 8px;font-size:10px}
  #searchModal .search-chip .mi{font-size:12px}
  #searchModal .search-results{padding:4px 8px}
  #searchModal .search-result{padding:6px 10px}
}
.search-input-wrap{
  display:flex;align-items:center;gap:10px;
  padding:10px 14px;background:var(--bg-input);
  border:1px solid var(--border);border-radius:10px;
  margin:14px 16px 0;
}
.search-input-wrap .mi{font-size:20px;color:var(--fg-2)}
.search-input-wrap input{
  flex:1;background:transparent;border:0;outline:none;
  font:500 14px var(--mk-font-ui);color:var(--fg-1);
}
.search-input-wrap input::placeholder{color:var(--fg-3)}

.search-chips{display:flex;flex-wrap:wrap;gap:6px;padding:10px 16px 0}
.search-chip{
  display:inline-flex;align-items:center;gap:6px;
  padding:6px 10px;border-radius:999px;
  background:var(--bg-input);border:1px solid var(--border);
  font:600 11px var(--mk-font-ui);color:var(--fg-2);
  cursor:pointer;white-space:nowrap;
  transition:all var(--mk-t-fast);
}
.search-chip .mi{font-size:14px}
.search-chip:hover{border-color:var(--accent);color:var(--accent)}
.search-chip.on{
  background:color-mix(in srgb, var(--accent) 12%, transparent);
  border-color:var(--accent);
  color:var(--accent);
}

.search-results{
  display:flex;flex-direction:column;gap:4px;
  padding:8px 8px;margin:0 8px;
}
.search-result{
  display:grid;
  grid-template-columns:32px 1fr auto;
  gap:10px;align-items:center;
  padding:8px 10px;border-radius:8px;cursor:pointer;
  transition:background var(--mk-t-fast);
}
.search-result:hover{background:var(--bg-2)}
.search-result-icon{
  width:32px;height:32px;border-radius:8px;
  background:var(--bg-2);color:var(--fg-2);
  display:inline-flex;align-items:center;justify-content:center;
}
.search-result-icon .mi{font-size:16px}
.search-result-name{font:600 13px var(--mk-font-ui);color:var(--fg-1);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.search-result-sub{font:500 11px var(--mk-font-mono);color:var(--fg-3)}
.search-result-meta{display:flex;flex-direction:column;gap:0;min-width:0}
.search-result-amt{font:700 12px var(--mk-font-mono);text-align:end;font-variant-numeric:tabular-nums}
.search-result-amt.in{color:var(--accent)}
.search-result-amt.out{color:var(--mk-debt)}
.search-result-kind{
  font:600 10px var(--mk-font-ui);letter-spacing:.01em;
  padding:3px 8px;border-radius:999px;
  background:var(--bg-2);color:var(--fg-3);white-space:nowrap;
}
.search-empty{
  padding:36px 16px;text-align:center;color:var(--fg-3);
  font:500 12px var(--mk-font-ui);
}

/* ── RESPONSIVE ─────────────────────────────────────────────────── */
@media (max-width: 600px) and (orientation: portrait){
  /* Filter takes the whole screen on mobile-V — the side-panel sliding
     in over a partial bg leaves a cramped sliver of conditions tree;
     full-screen gives the user room to navigate. */
  .filter-panel{
    inset-inline-start:0;inset-inline-end:0;top:0;bottom:0;
    width:100%;height:100%;
    border-inline-start:0;border-radius:0;
    transform:translateX(110%);
  }
  html[dir="rtl"] .filter-panel{transform:translateX(-110%)}
  .filter-panel.open{transform:translateX(0) !important}
  /* Center modals get a wider footprint on small screens */
  .panel-card{border-radius:14px}
  #searchModal{padding-top:6vh;padding-inline:12px}
  .modal-overlay{padding:12px}
}

@media (max-height: 599px) and (orientation: landscape){
  .panel-card{max-height:calc(100dvh - 24px)}
  .modal-overlay{padding:12px}
  /* B59 (Pablo: "…and a side panel in mobile landscape") — this band used to take
     the full surface, on the argument that a slide-from-right panel leaves "a sliver
     of real content visible". That reasoning was about WIDTH, and a landscape phone
     has width to spare — it is HEIGHT that is scarce, which is why every other rule
     in this band trims vertical padding. A side panel therefore costs nothing here
     and keeps the page behind it, matching the modal's own landscape treatment
     (`#alertsModal`, `#condBuilderModal`, `.cb-date-pop` — all side panels here).
     The panel is generous (min 380px, and it may take three-fifths of the width) so
     the conditions tree is not the sliver the old note worried about. */
  /* B64-05 SUPERSEDES the B59 note above (Pablo, 2026-09-23: panels are
     "a full screen panel in mobile (both orientations) that's a global rule for
     the Mocca app"). Newer comment wins: the landscape phone gets the same full
     surface as portrait; the height-saving trims below still apply. */
  .filter-panel{
    inset-inline-start:0;inset-inline-end:0;top:0;bottom:0;
    width:100%;min-width:0;height:100%;
    border-inline-start:0;border-radius:0;
    transform:translateX(110%);
  }
  html[dir="rtl"] .filter-panel{transform:translateX(-110%)}
  .filter-panel.open{transform:translateX(0) !important}
  .panel-hd{padding:10px 14px}
  .panel-body{padding:12px}
  .panel-ft{padding:10px 14px}
  /* Crunch the slide footers — mobile-H height is the scarce axis (the
     browser URL bar eats into it too), and the 16px-padded footer plus
     full-height buttons left the conditions tree a sliver (Pablo
     2026-06-12). Compact paddings + smaller buttons reclaim ~30px. */
  .fp-slide .panel-ft{padding:8px 12px;gap:8px}
  .panel-ft .panel-btn{padding:6px 12px;font-size:11px}
  #searchModal{padding-top:24px}

  /* JS (adjustFilterPanelLayout) moves the .fp-chips element into the
     panel header and hides the standalone Quick filters section so
     the conditions tree gets the full vertical space. The chip row in
     the header scrolls horizontally if there are too many. */
  .filter-panel .fp-section.hidden-mobile-h{display:none}
  .filter-panel .panel-hd.with-inline-chips{gap:12px;padding:8px 12px}
  .filter-panel .panel-hd.with-inline-chips .panel-hd-l{flex-shrink:0}
  .filter-panel .panel-hd.with-inline-chips .panel-hd-l .panel-title{font-size:13px}
  .filter-panel .panel-hd.with-inline-chips .fp-chips{
    flex:1;min-width:0;
    flex-wrap:nowrap;overflow-x:auto;
    padding:0;
    scrollbar-width:thin;
    margin:0 4px;
  }
  .filter-panel .panel-hd.with-inline-chips .fp-chip{
    padding:4px 6px 4px 10px;
    font-size:10px;
    flex-shrink:0;
  }
  .filter-panel .panel-hd.with-inline-chips .fp-chip .fp-chip-tag{font-size:12px}
  .filter-panel .panel-hd.with-inline-chips .fp-chip-edit,
  .filter-panel .panel-hd.with-inline-chips .fp-chip-del{width:16px;height:16px}
  .filter-panel .panel-hd.with-inline-chips .fp-chip-edit .mi,
  .filter-panel .panel-hd.with-inline-chips .fp-chip-del .mi{font-size:11px}
  /* Conditions section gets compact treatment so the tree below has
     more room to breathe. */
  .filter-panel .fp-section-conditions{padding:8px 14px}
  .filter-panel .fp-section-conditions .fp-section-hd{font-size:10px;margin-bottom:4px}
}
/* B46 P6-ML08 — the compactions above were tried FIRST (Pablo 2026-06-12,
   "a sliver") and at a real landscape PHONE height they are still not enough:
   hd 49 + tabs 45 + section-hd band 35 + footer 57 = 194 of 237px, leaving the
   conditions tree **43px — one row of nine**. Height is exhausted there; WIDTH
   is not. So the footer leaves the vertical flow for a right-hand gutter, the
   same move the datetime picker's chrome column makes.

   ≤420px ONLY — mirroring the date picker split at the top of this file, and
   for the same measured reason. This is a RESTRUCTURE, not a compaction, and
   it costs 164px of panel WIDTH; at 540–599px tall the natural footer row
   already leaves the tree ~354px (≈9 rows), so there is no height to buy and
   the gutter would just be a 29%-of-panel width tax on short DESKTOP windows
   (the panel is only 560px wide above 1024px). Scoping it to ≤599px was the
   exact mistake this session had already documented for the picker. */
@media (max-height: 420px) and (orientation: landscape){
  .filter-panel{--fp-ft-gutter:164px}
  /* NB: no `position:relative` on .fp-slide — it is already `position:absolute;
     inset:0` (the slide stack overlays its slides), which is itself a
     containing block for the footer below. Adding relative here overrides
     that and makes the slides FLOW vertically, stacking 335px slides down
     the page instead of overlaying them. */
  .filter-panel .fp-slide > :not(.panel-hd):not(.panel-ft){margin-inline-end:var(--fp-ft-gutter)}
  .filter-panel .fp-slide > .panel-ft{
    position:absolute;inset-inline-end:0;inset-block-end:0;
    width:var(--fp-ft-gutter);max-height:calc(100% - 52px);
    flex-direction:column;justify-content:flex-end;align-items:stretch;
    gap:6px;padding:10px 12px;
    border-top:0;background:transparent;
    overflow-y:auto;overscroll-behavior:contain;
  }
  .filter-panel .fp-slide > .panel-ft .panel-btn{width:100%;justify-content:center}
  /* The conditions section absorbs the height the footer gave back. */
  .filter-panel .fp-section-conditions{flex:1;min-height:0}
}

/* ═══ 2026-06-11 — condition-builder UX revisions (Pablo) ══════════
   1. Long-path compression: "+N" bubble between the first and last
      segments of a deep breadcrumb; click expands.
   2. Slide-header crumbs: "Filters › +2 › Add Condition".
   3. Concat/Coalesce single-chain rows — one input per source.
   4. Formula INDENTED TREE — indentation = parenthesis grouping, with
      drag-and-drop between levels.
   ═══════════════════════════════════════════════════════════════════ */

/* ── 1 · "+N" chain-compression bubble ── */
.cb-seg-more{
  align-self:center;flex-shrink:0;
  display:inline-flex;align-items:center;justify-content:center;
  min-width:30px;height:24px;padding:0 7px;margin:0 4px;
  border-radius:999px;border:1px solid color-mix(in srgb, var(--accent) 35%, var(--border));
  background:color-mix(in srgb, var(--accent) 12%, transparent);
  color:var(--accent);font:700 11px var(--mk-font-ui);cursor:pointer;
  transition:background var(--mk-t-fast),border-color var(--mk-t-fast);
}
.cb-seg-more:hover{background:color-mix(in srgb, var(--accent) 20%, transparent);border-color:var(--accent)}

/* ── 2 · Slide-header breadcrumb ── */
.panel-title-crumbs{
  display:flex;align-items:center;gap:1px;min-width:0;
}
.panel-title-crumbs .fp-crumb{
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  color:var(--fg-3);font-weight:600;flex-shrink:1;min-width:0;
}
.panel-title-crumbs .fp-crumb-cur{color:var(--fg-1);flex-shrink:0}
.fp-crumb-sep{font-size:15px;color:var(--fg-3);flex-shrink:0}
html[dir="rtl"] .fp-crumb-sep{transform:scaleX(-1)}
.fp-crumb-more{
  flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;
  min-width:26px;height:20px;padding:0 6px;
  border-radius:999px;border:1px solid color-mix(in srgb, var(--accent) 35%, var(--border));
  background:color-mix(in srgb, var(--accent) 12%, transparent);
  color:var(--accent);font:700 10px var(--mk-font-ui);cursor:pointer;
  transition:background var(--mk-t-fast),border-color var(--mk-t-fast);
}
.fp-crumb-more:hover{background:color-mix(in srgb, var(--accent) 20%, transparent);border-color:var(--accent)}

/* ── 3 · Concat / Coalesce single-chain source rows ──
   The ROW is the input box; the kind segment + hinge + breadcrumb chips
   flow inside it (inner pickers flatten to transparent). */
.cb-concat-chain{
  display:flex;align-items:center;flex-wrap:wrap;gap:2px;
  padding:4px;min-height:46px;
  background:var(--bg-input);
  border:1px solid var(--border);
  border-radius:9px;
}
.cb-concat-chain .cb-field-picker{
  background:transparent;border:none;padding:0;min-height:0;
  flex:1 1 auto;min-width:0;border-radius:0;
}
/* The mini hinge / session .cs chips inside a chain read as segments. */
.cb-concat-chain > .cs.cb-rowhinge-cs > .cs-btn,
.cb-concat-chain > .cs.cb-rowsess-cs > .cs-btn{
  background:transparent;border:1px solid transparent;height:36px;
}
.cb-concat-chain > .cs.cb-rowhinge-cs > .cs-btn:hover,
.cb-concat-chain > .cs.cb-rowsess-cs > .cs-btn:hover{background:var(--bg-2);border-color:var(--border)}
/* Remove pins to the row's TOP corner — absolute, so a wrapped chain
   never pushes the X onto its own line and the row keeps no dead
   trailing column (Pablo 2026-06-12: "the X button shouldn't take a
   whole row … it should remain on the top"). */
.cb-concat-chain,
.cb-agg-row{position:relative;padding-inline-end:40px}
.cb-concat-chain > .cb-row-rm,
.cb-agg-row > .cb-row-rm{
  position:absolute;top:6px;inset-inline-end:6px;margin-inline-start:0;
}
/* Static literal input sits flush inside the chain box — and FILLS the
   remaining row width instead of leaving blank space. */
.cb-concat-chain .cb-concat-static-input{
  background:var(--bg-1);
  flex:1 1 160px;max-width:none;
}
/* Static TYPE chip reads as a segment like the hinge/session chips. */
.cb-concat-chain .cs.cb-static-type-cs > .cs-btn{
  background:transparent;border:1px solid transparent;height:36px;
}
.cb-concat-chain .cs.cb-static-type-cs > .cs-btn:hover{background:var(--bg-2);border-color:var(--border)}
/* Drag-to-reorder chrome — grip + drop-edge indicators (order matters:
   coalesce priority / concat output order). When the field chain wraps onto
   several lines the grip + ordinal must sit at the TOP, aligned with the
   FIRST field row, instead of stealing a whole first line (Pablo 2026-06-19:
   "the selector's first row of fields should start in the first row"). */
.cb-concat-row,.cb-agg-row{align-items:flex-start}
.cb-concat-row > .cb-coalesce-ord,
.cb-agg-row > .cb-coalesce-ord{margin-top:5px}
/* Pablo 2026-06-22: no drag handle — the row box itself is the drag affordance
   (set draggable on mousedown). Show the grab cursor on the row chrome but not
   over its interactive chips/inputs. */
.cb-concat-row,.cb-agg-row{cursor:grab}
.cb-concat-row:active,.cb-agg-row:active{cursor:grabbing}
.cb-concat-row :is(input,textarea,button,.cs,.cb-field-seg,[contenteditable]),
.cb-agg-row :is(input,textarea,button,.cs,.cb-field-seg,[contenteditable]){cursor:auto}
.cb-row.dragging{opacity:.45}
.cb-row.drop-before{box-shadow:0 -2px 0 0 var(--accent)}
.cb-row.drop-after{box-shadow:0 2px 0 0 var(--accent)}
/* Row-level Where breaks onto its own line under the chain segments. */
.cb-concat-chain .cb-row-where,
.cb-agg-row .cb-row-where{flex-basis:100%;min-width:0;padding:2px 2px 4px}
/* B8-27 (Pablo 2026-06-22): an EXPANDED path dropped BELOW the row's ordinal +
   connector (C) buttons instead of starting on their line. The descendant rule
   `.cb-concat-chain .cb-field-picker{flex:1 1 auto}` was overriding the C21
   `flex:1 1 0`, so a wide expanded chain's content width forced the wrap. Pin
   the row's OWN direct picker back to flex-basis:0 (higher source order wins)
   so it shrinks and wraps its chevron segments internally, on the same line. */
.cb-concat-row > .cb-row-field-picker,
.cb-agg-row > .cb-row-field-picker{flex:1 1 0;min-width:0}
/* Coalesce priority ordinal — makes "order = priority" legible. */
.cb-coalesce-ord{
  flex-shrink:0;width:22px;height:22px;margin-inline-end:2px;
  display:inline-flex;align-items:center;justify-content:center;
  border-radius:999px;background:color-mix(in srgb, var(--accent) 14%, transparent);
  color:var(--accent);font:700 11px var(--mk-font-mono);
}

/* ── 4 · Formula indented tree ── */
.cb-formula-seq.cb-formula-tree{
  display:flex;flex-direction:column;align-items:stretch;gap:4px;
}
.cb-f-row{min-width:0}
.cb-f-row-main{display:flex;align-items:center;gap:8px;min-width:0;border-radius:9px}
/* Pablo 2026-06-21: drag the row BOX itself (handles removed). The box shows
   a grab cursor; interactive controls inside reset it to default. */
.cb-f-row-main[data-f-grip]{cursor:grab}
.cb-f-row-main[data-f-grip] input,
.cb-f-row-main[data-f-grip] textarea,
.cb-f-row-main[data-f-grip] button,
.cb-f-row-main[data-f-grip] [contenteditable]{cursor:default}
.cb-f-row-main[data-f-grip]:active{cursor:grabbing}
.cb-f-drag{
  font-size:16px;color:var(--fg-3);cursor:grab;flex-shrink:0;
  padding:2px 0;border-radius:4px;
}
.cb-f-drag:hover{color:var(--accent)}
/* Aligns a container's FIRST row (no operator) with its op'd siblings:
   one 40px locked-op tag. */
.cb-f-op-spacer{width:34px;flex-shrink:0}
.cb-f-row-acts{
  display:inline-flex;gap:3px;margin-inline-start:auto;flex-shrink:0;
  opacity:.7;transition:opacity var(--mk-t-fast);
  position:relative;z-index:3;
}
/* B8-20 (Pablo 2026-06-22): the formula row's action buttons were unpressable
   — the draggable row surface sat over them. Pin them above and guarantee
   pointer events so a click always lands. */
.cb-f-row-acts button,
.cb-f-row-acts .cs{pointer-events:auto;position:relative;z-index:3}
.cb-f-row > .cb-f-row-main:hover .cb-f-row-acts,
.cb-f-row > .cb-f-row-main:focus-within .cb-f-row-acts{opacity:1}
.cb-f-wrap{
  display:inline-flex;align-items:center;gap:0;padding:3px 5px;border-radius:6px;
  background:transparent;border:1px dashed color-mix(in srgb, var(--accent) 45%, transparent);
  color:var(--accent);cursor:pointer;
  transition:background var(--mk-t-fast);
}
.cb-f-wrap .mi{font-size:12px}
.cb-f-wrap:hover{background:color-mix(in srgb, var(--accent) 8%, transparent)}
/* Group row — tinted header + indented children. The accent rail under it
   IS the parenthesis (mirrors the Filters condition-tree indentation).
   C5 (Pablo 2026-06-20): the header no longer eats a full empty first row —
   the group lays out as a flex ROW so the first child operand sits on the
   same line as the group's op tag + controls (left rail), and only the
   necessary height scrolls. */
/* Group = a multi-operation sub-level. Restyled to read like the Filters
   condition-tree (Pablo 2026-06-21: "make it look like the filters condition
   indentation tree, not this box"): a compact header row carrying the level's
   operation glyph + controls (no box), then the operands indented beneath a
   left accent rail — the rail IS the parenthesis. */
/* B25 C6 (Pablo): the math GROUP doesn't break into its own full row —
   the op glyph header and the indented operand stack share ONE line
   (header hugs its content, children take the rest; the accent rail on
   .cb-f-children keeps reading as the parenthesis). */
.cb-f-row-group{
  display:flex;flex-direction:row;align-items:flex-start;gap:6px;position:relative;
}
.cb-f-row-group > .cb-f-row-main{
  display:flex;align-items:center;gap:6px;flex:0 0 auto;
  padding:6px 0 1px;background:transparent;border:0;width:auto;
}
.cb-f-row-group > .cb-f-children{flex:1 1 auto;min-width:0}
.cb-f-row-group > .cb-f-row-main > .cb-f-op,
.cb-f-row-group > .cb-f-row-main > .cb-f-op-spacer{flex:0 0 auto}
.cb-f-group-tag{
  display:inline-flex;align-items:center;gap:5px;flex-shrink:0;
  font:600 11px var(--mk-font-ui);
  color:color-mix(in srgb, var(--accent) 75%, var(--fg-2));
}
.cb-f-group-tag .mi{font-size:15px}
/* Formula reads LTR even in RTL (operand order is significant), so the
   indent rail is a physical LEFT margin/border. */
/* C4 (Pablo this batch): tighten the formula group’s indent rail + row gap —
   the gutter between the operator/operands read as unnecessarily wide. */
.cb-f-children{
  margin-left:9px;
  padding-left:8px;
  border-left:2px solid color-mix(in srgb, var(--accent) 35%, var(--border));
}
.cb-f-row-group > .cb-f-row-main{gap:5px}
.cb-f-row-group .cb-f-ungroup,
.cb-f-row-group > .cb-f-row-main > .cb-f-rm{
  position:static;opacity:1;width:22px;height:22px;border-radius:6px;flex-shrink:0;
  display:inline-flex;align-items:center;justify-content:center;
  background:transparent;border:1px solid transparent;color:var(--fg-3);
  cursor:pointer;box-shadow:none;
}
.cb-f-row-group .cb-f-ungroup:hover,
.cb-f-row-group > .cb-f-row-main > .cb-f-rm:hover{border-color:var(--accent);color:var(--accent);background:transparent}
.cb-f-row-group .cb-f-ungroup .mi{font-size:14px}
/* Drag feedback */
.cb-f-dragging{opacity:.35}
/* Icon-only add-term (Pablo 2026-06-21: "leave just the icon, bigger, in the
   dotted line — no text to translate"). A dashed pill carrying only the
   level's math glyph. */
.cb-f-add-icon{
  display:inline-flex;align-items:center;justify-content:center;
  width:30px;height:30px;padding:0;border-radius:8px;
  border:1.5px dashed color-mix(in srgb,var(--accent) 45%,var(--border));
  background:transparent;color:var(--accent-text);cursor:pointer;
  transition:background var(--mk-t-fast),border-color var(--mk-t-fast);
}
.cb-f-add-icon:hover:not(:disabled){background:var(--accent-soft);border-color:var(--accent)}
.cb-f-add-icon .cb-f-menu-glyph{width:auto;font-size:16px}
.cb-f-add-icon.is-disabled,.cb-f-add-icon:disabled{opacity:.4;cursor:not-allowed}
.cb-f-drop-before > .cb-f-row-main{box-shadow:0 -2px 0 0 var(--accent)}
.cb-formula-adds.cb-f-drop-tail-on{outline:2px dashed var(--accent);outline-offset:3px;border-radius:8px}
.cb-f-row-new.cb-f-drop-tail-on{outline:2px dashed var(--accent);outline-offset:3px;border-radius:8px}
.cb-formula-tree .cb-formula-adds{display:flex;flex-wrap:wrap;gap:5px;padding-top:2px}
.cb-formula-tree .cb-formula-empty{padding:2px 0}

/* ── 5 · Unified path-input operand rows (Pablo 2026-06-12) ──
   Every formula operand — and the trailing "new operand" row — is the
   SAME bordered path-input box as the conditions in the Filters panel:
   source segment › [session target] › drill… / static number. */
.cb-f-row-main .cb-f-picker{flex:1 1 auto;min-width:0}
.cb-f-picker.is-new{border-style:dashed}
.cb-f-picker .cb-f-num-input{flex:0 1 120px}
/* In-box remove — pushed to the box's inline end, TOP-aligned so when the box
   wraps to >1 line the X sits at the top-right corner instead of floating in
   the vertical middle (Pablo 2026-06-22). On a single line it reads the same. */
.cb-f-rm-in{margin-inline-start:auto;align-self:flex-start;margin-block-start:1px}
/* Keep the row-act wrap menu visible while its dropdown is open. */
.cb-f-row-main:has(.cs.open) .cb-f-row-acts{opacity:1}
.cb-f-wrap-cs{position:relative}
.cb-f-wrap-cs > .cs-menu{min-width:170px}
/* Static-row chain box (concat/coalesce) — same flex behaviour as the
   field-row picker so the literal input fills the row. */
.cb-row-static-box{flex:1 1 200px;min-width:0}
/* C5 (Pablo) — Static boolean toggle: a True/False segmented control shown
   instead of a text literal when the row is under a boolean-class aggregate. */
.cb-static-bool{display:inline-flex;gap:4px;flex:1 1 auto;min-width:0;padding:3px;border-radius:9px;background:var(--bg-input);border:1px solid var(--border)}
.cb-bool-opt{
  flex:1 1 0;min-width:0;display:inline-flex;align-items:center;justify-content:center;gap:5px;
  height:28px;padding:0 12px;border:0;border-radius:7px;background:transparent;cursor:pointer;
  font:600 13px var(--mk-font-ui);color:var(--fg-2);
  transition:background var(--mk-t-fast),color var(--mk-t-fast);
}
.cb-bool-opt .mi{font-size:15px}
.cb-bool-opt:hover{background:color-mix(in srgb,var(--accent) 8%,transparent);color:var(--fg-1)}
.cb-bool-opt.on{background:var(--accent);color:var(--accent-fg)}
/* Unified VALUE lead box — source segment (+ inline static / NOW editor)
   in one bordered chain. */
.cb-val-unified{align-items:center}
.cb-val-static-host{
  flex:1 1 220px;min-width:0;display:flex;align-items:center;gap:8px;
}
.cb-val-unified .cb-now-value{border:none;background:transparent;padding:4px 6px}
/* B9-23/B9-25 — quiet hint shown in place of a blank value input when the
   field path hasn't resolved to a comparable leaf yet (kills the "empty
   input" dead-end). */
.cb-val-hint{
  flex:1 1 220px;min-width:0;display:flex;align-items:center;gap:7px;
  padding:7px 10px;border-radius:8px;
  background:var(--bg-2);color:var(--fg-3);
  font:500 12px var(--mk-font-ui);
}
.cb-val-hint .mi{font-size:16px;opacity:.7}

/* ═══ B23 C11 (Pablo 2026-07-06) — the numbered grip bubble returns ONLY where
   order matters: sort rows when there is MORE THAN ONE row (the number = sort
   priority; with a single row it's irrelevant, so no bubble). Replicates the
   old .sort-grip metrics; the row box itself stays the drag affordance.
   Concat/coalesce sub-path rows already carry .cb-coalesce-ord (order =
   priority/output order) — that bubble is the same statement. */
.sort-row{grid-template-columns:1fr auto}
.sort-row:has(> .sort-ord){grid-template-columns:auto 1fr auto}
.sort-ord{
  width:24px;height:24px;border-radius:7px;flex-shrink:0;
  display:inline-flex;align-items:center;justify-content:center;
  background:var(--bg-input);border:1px solid var(--border);
  color:var(--fg-3);font:700 12px var(--mk-font-ui);cursor:grab;
}
.sort-row:active .sort-ord{cursor:grabbing}
.cb-coalesce-ord{cursor:grab}

/* ── B35 S1 — actionable alerts ── */
.alert-acts{ display:flex;gap:7px;margin-top:8px; }
.alert-act{ display:inline-flex;align-items:center;gap:5px;padding:6px 12px;border-radius:8px;border:1px solid var(--bd-1,#dfe4e8);background:var(--bg-1,#fff);font:600 12px/1 var(--mk-font-ui,inherit);cursor:pointer;color:var(--fg-2,#4a5768); }
.alert-act .mi{ font-size:15px; }
.alert-act.ok{ border-color:color-mix(in srgb,#2f9e63 45%,transparent);color:#2f9e63; }
.alert-act.ok:hover{ background:color-mix(in srgb,#2f9e63 10%,transparent); }
.alert-act.no{ border-color:color-mix(in srgb,#d64545 40%,transparent);color:#d64545; }
.alert-act.no:hover{ background:color-mix(in srgb,#d64545 9%,transparent); }
.alert-resolved{ display:inline-flex;align-items:center;gap:5px;margin-top:8px;font:700 11.5px/1 var(--mk-font-ui,inherit); }
.alert-resolved.approved{ color:#2f9e63; } .alert-resolved.rejected{ color:#d64545; }
.alert-resolved .mi{ font-size:15px; }

/* ═══ B54-00 · MoccaSelect — the ONE dropdown, in a form row ═══════════════
   (Pablo, four times this batch: "this is not the dropdown component we've been
   working on", "…we've been working on forever", "this should be a dropdown
   select component", "…the multi-select with search dropdown selector".)
   select-host.js emits the condition builder's OWN markup, so it inherits every
   `.cs` / `.cb-multi-*` rule above. These few rows are what a dropdown needs
   when it stands in a FORM FIELD rather than a condition row: full width, a
   field-height trigger, and a start-anchored menu. */
.cs.msel{ max-width:100% }
.cs.msel.msel-block{ display:block;width:100% }
.cs.msel.msel-block > .cs-btn{ width:100%;justify-content:flex-start;min-height:38px;padding:7px 11px;
  border-radius:8px;font:600 12.5px var(--mk-font-ui) }
.cs.msel > .cs-btn > .cs-val{ flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:start }
.cs.msel > .cs-btn > .cs-val.empty{ color:var(--fg-3);font-weight:500 }
.cs.msel > .cs-menu{ inset-inline-start:0;inset-inline-end:auto;max-height:300px;overflow:auto;overscroll-behavior:contain }
.cs.msel.cb-multi-cs.msel-block > .cs-btn{ padding:5px 9px }
.cs.msel .cs-item-l{ flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap }
.cs.msel .av.sm{ width:20px;height:20px;font-size:9px;flex:none }
/* Compact variant — a dropdown that sits in a section header (the title panel's
   country switch) keeps the header's own scale. */
.cs.msel.msel-sm > .cs-btn{ min-height:30px;padding:4px 9px;font:600 11.5px var(--mk-font-ui) }
.cs.msel.msel-sm .cb-opt-flag{ width:16px;height:16px }
@media (pointer:coarse),(max-width:600px){ .cs.msel > .cs-btn{ min-height:44px } .cs.msel .cs-item{ min-height:40px } }

/* B54-11 · panel header actions (MoccaPanel `acts`) ───────────────────────
   One or two icon buttons beside the close button. The heart is the reason it
   exists: "we could simply have the heart to the top right of the panel and it
   would turn pink if I select it or gray if it's unselected". */
.mp-panel .mp-hd-acts{ display:flex;align-items:center;gap:4px;margin-inline-start:auto;flex:0 0 auto }
.mp-hd-act{ position:relative;display:inline-flex;align-items:center;justify-content:center;
  width:36px;height:36px;border:0;border-radius:50%;background:transparent;color:var(--fg-3);cursor:pointer;
  transition:background var(--mk-t-fast),color var(--mk-t-fast) }
.mp-hd-act::after{ content:'';position:absolute;inset:-4px }
.mp-hd-act .mi{ font-size:21px }
.mp-hd-act:hover{ background:var(--bg-2);color:var(--fg-1) }
.mp-hd-act.on{ color:oklch(.65 .21 355) }
.mp-hd-act.on:hover{ background:color-mix(in srgb,oklch(.65 .21 355) 12%,transparent) }
/* B63-133 — a destructive header action (e.g. deleting an address) reads red
   on hover, same shape as every other .mp-hd-act. */
.mp-hd-act-danger:hover{ background:color-mix(in srgb,var(--mk-danger,#d64545) 14%,transparent);color:var(--mk-danger,#d64545) }

/* ── B65 W1 (065-082) — a panel opened from a panel is a slide of it ─────────
   panel-host.js `stackRule`: the panel underneath stays exactly where it is
   (the "shell" Pablo wants to stay in place) and the new one slides in over it
   with a Back arrow; nothing underneath answers clicks while it is covered. */
.filter-panel.ps-under{ pointer-events:none; }
.filter-panel.ps-top{ box-shadow:-16px 0 40px rgba(13,37,48,.18); }
.panel-hd .ps-back{ margin-inline-end:2px;flex:0 0 auto; }
.panel-hd.ps-has-back .panel-hd-l > .ent-hd-ic{ display:none; }
/* B65 W1 (065-082) — Filter ⇄ Sort: the shell and tabs stay, the content slides */
.filter-panel.fp-swap{ transition:none !important; }
@keyframes fpSwapFwd{ from{ transform:translateX(26%);opacity:0 } to{ transform:none;opacity:1 } }
@keyframes fpSwapBack{ from{ transform:translateX(-26%);opacity:0 } to{ transform:none;opacity:1 } }
.fp-swap-fwd{ animation:fpSwapFwd .28s cubic-bezier(.32,.72,.28,1); }
.fp-swap-back{ animation:fpSwapBack .28s cubic-bezier(.32,.72,.28,1); }
html[dir="rtl"] .fp-swap-fwd{ animation-name:fpSwapBack; }
html[dir="rtl"] .fp-swap-back{ animation-name:fpSwapFwd; }
@media (prefers-reduced-motion:reduce){ .fp-swap-fwd, .fp-swap-back{ animation:none; } }
/* B66 W5 — a CLOSED off-canvas panel / drawer casts no shadow: its 60px blur leaked a dark band down the
   right edge of every phone screen in dark mode (seen in Jockey Staff; Mocca had it too). */
.filter-panel:not(.open), .dwr:not(.on){ box-shadow:none !important; }

/* B67 R67-031 — a closed panel leaves the keyboard's Tab order: parked off-screen it still held its buttons, so Tab walked
   through the invisible Filter / Sort / Quick-filter / Profile / Chart editors (40 stops on the Dashboard). Hidden once the
   slide-out ends; visible at once when it opens. */
.filter-panel:not(.open){ visibility:hidden; transition:transform 280ms var(--mk-ease), visibility 0s linear 300ms; }
.filter-panel.open{ visibility:visible; transition:transform 280ms var(--mk-ease), visibility 0s; }
