/* Bundled Inter (latin, variable weight axis) — the typographic backbone of the
   Notion-leaning look. Self-hosted (no external font CDN, sovereign) at
   dist/assets/inter.woff2 (copied from ui/assets via the trunk copy-dir). The
   `--y-font` stack lists "Inter" first, then system fallbacks while it loads. */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/assets/inter.woff2") format("woff2");
}

/* ============================================================================
   ycell design system
   A cohesive, modern, Office-grade look. Everything is driven by CSS custom
   properties so theming is one place. The old UI was "vraiment moche"; this is
   the antidote: restrained palette, crisp 1px borders, real depth on focus,
   tight typographic rhythm.

   THEMING
   -------
   All colours are CSS custom properties. The *default* (:root) values are the
   Light theme. A `data-theme="dark"` attribute on <html> overrides the colour
   tokens for Dark. A `data-accent="…"` attribute on <html> overrides the accent
   ramp (blue is the default / built into :root). Switching themes is therefore a
   single attribute flip on document.documentElement (see ui/src/theme.rs).

   NB: non-colour tokens (radii, spacing, type, metrics) are theme-independent and
   live only in :root. Dark/accent blocks override colours *only*.
   ========================================================================== */

:root {
  /* --- brand & accent (Blue — refined, restrained à la Notion) --- */
  --y-accent:        #2383e2;   /* clean, calmer blue */
  --y-accent-hover:  #1a6fc4;
  --y-accent-soft:   #e8f1fb;
  --y-accent-ring:   rgba(35, 131, 226, 0.26);
  --y-accent-ink:    #ffffff;   /* text drawn on top of a solid accent fill */

  /* --- surfaces (warm, content-first whites) --- */
  --y-bg:            #f7f7f5;   /* warm app shell behind everything */
  --y-surface:       #ffffff;   /* panels, ribbon, cards */
  --y-surface-2:     #f6f5f3;   /* subtle raised rows */
  --y-surface-3:     #efeeec;   /* headers, inert chips */

  /* --- ink (warm near-black, not cold) --- */
  --y-ink:           #37352f;   /* primary text */
  --y-ink-soft:      #6b6a66;   /* secondary text */
  --y-ink-faint:     #9b9a97;   /* hints, placeholders */
  --y-ink-invert:    #ffffff;

  /* --- lines (soft + warm, hairline) --- */
  --y-border:        #ebebea;
  --y-border-strong: #dcdbd7;
  --y-grid-line:     #ececeb;
  --y-grid-header:   #f7f7f5;

  /* --- semantic --- */
  --y-ok:            #2c8c5a;
  --y-warn:          #b7791f;
  --y-error:         #e0564b;
  --y-stale:         #b7791f;

  /* --- titlebar (LIGHT + calm — no more Office navy bar) --- */
  --y-titlebar-from: #ffffff;
  --y-titlebar-to:   #ffffff;
  --y-titlebar-ink:  #37352f;
  --y-titlebar-doc:  #9b9a97;

  /* --- assorted derived / component-local colours (hoisted out of rules) --- */
  --y-hover-veil:    rgba(55, 53, 47, .055);  /* warm Notion-style hover wash */
  --y-active-veil:   rgba(55, 53, 47, .09);
  --y-danger-soft:   #fdecea;                /* danger button hover bg */
  --y-danger-line:   #f5c6c0;                /* danger button hover border */
  --y-code-bg:       #1e1e1a;                /* SQL / code block background */
  --y-code-ink:      #e7e6e1;                /* SQL / code block text */
  --y-aihead-from:   #fbfbfa;                /* AI panel header gradient */
  --y-aihead-to:     #f6f5f3;
  --y-stale-bg:      #fbf3e0;                /* stale pill */
  --y-stale-line:    #ecd9b0;
  --y-scrim:         rgba(15, 15, 14, .32);  /* soft modal backdrop */
  --y-cell-editor-bg:#ffffff;                /* floating cell editor */

  /* --- elevation — soft, warm, subtle (Notion-like, not heavy). --- */
  --y-shadow-tint:   15, 15, 14;             /* rgb channels used by the shadows */
  --y-shadow-1: 0 1px 2px rgba(var(--y-shadow-tint),.06), 0 1px 2px rgba(var(--y-shadow-tint),.08);
  --y-shadow-2: 0 4px 14px rgba(var(--y-shadow-tint),.10), 0 1px 4px rgba(var(--y-shadow-tint),.07);
  --y-shadow-3: 0 14px 44px rgba(var(--y-shadow-tint),.16), 0 4px 12px rgba(var(--y-shadow-tint),.10);

  /* --- radii --- subtle (modern, not bubbly) --- */
  --y-r-sm: 5px;
  --y-r-md: 7px;
  --y-r-lg: 10px;
  --y-r-xl: 13px;                            /* modals & large cards */

  /* --- spacing scale --- */
  --y-s1: 4px;
  --y-s2: 8px;
  --y-s3: 12px;
  --y-s4: 16px;
  --y-s5: 24px;

  /* --- type --- */
  --y-font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, "Helvetica Neue", Arial, sans-serif;
  --y-mono: "Cascadia Code", "SF Mono", "JetBrains Mono", ui-monospace, Menlo, monospace;
  --y-fs-xs: 11px;
  --y-fs-sm: 12px;
  --y-fs-md: 13px;
  --y-fs-lg: 15px;
  --y-fs-xl: 18px;

  /* --- chrome metrics, shared with the canvas grid via JS reads --- */
  /* Slim single-row toolbar (was 92px Office ribbon). The tab strip + a 40px
     control row ≈ 44px total; the canvas grid is a flex sibling and re-fits its
     CSS box automatically, but the token is kept truthful for any JS read. */
  --y-ribbon-h: 44px;
  --y-formula-h: 34px;
  --y-status-h: 24px;
  --y-ai-w: 320px;
}

/* ============================================================================
   DARK THEME — colour token overrides only.
   Tuned to feel as crafted as Light: near-black (not pure black) surfaces with a
   faint blue cast, layered elevation via lighter surfaces, softened borders, and
   a slightly brighter accent so it pops on dark.
   ========================================================================== */
:root[data-theme="dark"] {
  --y-accent-soft:   #1a2b46;
  --y-accent-ring:   rgba(74, 150, 255, 0.40);
  --y-accent-ink:    #ffffff;

  --y-bg:            #15171c;
  --y-surface:       #1d2026;
  --y-surface-2:     #23272f;
  --y-surface-3:     #2a2f38;

  --y-ink:           #e7eaee;
  --y-ink-soft:      #aab2bd;
  --y-ink-faint:     #8e95a0;   /* AA on dark surfaces */
  --y-ink-invert:    #15171c;

  --y-border:        #343a44;
  --y-border-strong: #454c58;
  --y-grid-line:     #2c313a;
  --y-grid-header:   #23272f;

  --y-ok:            #3fbf75;
  --y-warn:          #e0a13c;
  --y-error:         #f06a6e;
  --y-stale:         #e0a13c;

  --y-titlebar-from: #1d2026;
  --y-titlebar-to:   #1d2026;
  --y-titlebar-ink:  #e7eaee;
  --y-titlebar-doc:  #8e95a0;

  --y-hover-veil:    rgba(255, 255, 255, .06);
  --y-active-veil:   rgba(255, 255, 255, .10);
  --y-danger-soft:   #3a1f21;
  --y-danger-line:   #5e3034;
  --y-code-bg:       #0b1018;
  --y-code-ink:      #cfe3ff;
  --y-aihead-from:   #20242c;
  --y-aihead-to:     #1a1e25;
  --y-stale-bg:      #2e2716;
  --y-stale-line:    #4a3d1c;
  --y-scrim:         rgba(0, 0, 0, .60);
  --y-cell-editor-bg:#23272f;

  /* deeper, darker shadows so elevation still reads on dark surfaces */
  --y-shadow-tint:   0, 0, 0;
  --y-shadow-1: 0 1px 2px rgba(0,0,0,.40), 0 1px 3px rgba(0,0,0,.50);
  --y-shadow-2: 0 4px 12px rgba(0,0,0,.45), 0 2px 4px rgba(0,0,0,.40);
  --y-shadow-3: 0 12px 32px rgba(0,0,0,.55), 0 4px 8px rgba(0,0,0,.45);
}

/* ============================================================================
   ACCENT PRESETS — override the accent ramp only. Blue is the :root default, so
   `data-accent="blue"` (or no attribute) needs nothing extra. These work on top
   of either theme; the soft/ring tints are deliberately separate per theme via
   the dark block above only for the *default* blue — for the alternative accents
   we provide both a light and a dark soft value.
   ========================================================================== */
:root[data-accent="green"] {
  --y-accent:        #1c8a4d;
  --y-accent-hover:  #166f3e;
  --y-accent-soft:   #e4f4ea;
  --y-accent-ring:   rgba(28, 138, 77, 0.32);
}
:root[data-theme="dark"][data-accent="green"] {
  --y-accent:        #36b56e;
  --y-accent-hover:  #2c9d5e;
  --y-accent-soft:   #16301f;
  --y-accent-ring:   rgba(54, 181, 110, 0.40);
}

:root[data-accent="violet"] {
  --y-accent:        #6d3fd1;
  --y-accent-hover:  #5a31b3;
  --y-accent-soft:   #efe9fb;
  --y-accent-ring:   rgba(109, 63, 209, 0.32);
}
:root[data-theme="dark"][data-accent="violet"] {
  --y-accent:        #9168ec;
  --y-accent-hover:  #7d52df;
  --y-accent-soft:   #271a44;
  --y-accent-ring:   rgba(145, 104, 236, 0.42);
}

:root[data-accent="amber"] {
  --y-accent:        #c2710d;
  --y-accent-hover:  #a35e0a;
  --y-accent-soft:   #fbeed6;
  --y-accent-ring:   rgba(194, 113, 13, 0.32);
}
:root[data-theme="dark"][data-accent="amber"] {
  --y-accent:        #e2962f;
  --y-accent-hover:  #cd8221;
  --y-accent-soft:   #392a12;
  --y-accent-ring:   rgba(226, 150, 47, 0.42);
}

:root[data-accent="rose"] {
  --y-accent:        #c2255c;
  --y-accent-hover:  #a31d4d;
  --y-accent-soft:   #fbe4ec;
  --y-accent-ring:   rgba(194, 37, 92, 0.32);
}
:root[data-theme="dark"][data-accent="rose"] {
  --y-accent:        #e85084;
  --y-accent-hover:  #d63f73;
  --y-accent-soft:   #3a1722;
  --y-accent-ring:   rgba(232, 80, 132, 0.42);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  font-family: var(--y-font);
  font-size: var(--y-fs-md);
  color: var(--y-ink);
  background: var(--y-bg);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* ============================================================================
   This is an APPLICATION, not a document: the chrome (ribbon, labels, buttons,
   panels, menus) is NOT text-selectable — drag-selecting UI text feels broken.
   Only real CONTENT is selectable/copyable: form fields, editable areas,
   code/values (ids, links, mono), and the genuine content panels (AI answers,
   report preview, cell-explain). The grid cells live on a <canvas> and handle
   their own range selection, so they're unaffected. Add `.y-selectable` to opt
   any other text block back in.
   ========================================================================== */
body { -webkit-user-select: none; user-select: none; }
input, textarea, select, [contenteditable="true"], code, pre,
.y-fingerprint, .y-aipanel, .y-report-preview-wrap, .y-explain,
.y-selectable, .y-selectable * {
  -webkit-user-select: text;
  user-select: text;
}

/* ============================================================================
   ACCESSIBILITY — a single, consistent keyboard focus ring.
   Only `:focus-visible` (keyboard / programmatic focus) draws the ring, so a
   mouse click never leaves a lingering halo, but every interactive control —
   buttons, tabs, list rows, menu items, links — gets a clear, theme-aware
   indicator. Inputs keep their richer border+ring treatment below; this is the
   baseline for everything that doesn't define its own.
   ========================================================================== */
:focus-visible {
  outline: 2px solid var(--y-accent);
  outline-offset: 2px;
  border-radius: var(--y-r-sm);
}
/* Controls that sit flush against an edge (tabs, segmented rows, list rows)
   read better with the ring tucked just inside rather than floating outside. */
.y-tab:focus-visible,
.y-sheet-tab:focus-visible,
.y-ctx-item:focus-visible,
.y-menu-item:focus-visible,
.y-filter-row:focus-visible,
.y-ac-item:focus-visible,
.y-ds-item:focus-visible,
.y-home-recent:focus-visible {
  outline-offset: -2px;
}
/* Inputs already render an accent border + ring on focus; suppress the generic
   outline so they don't get a doubled indicator. */
.y-input:focus-visible, .y-select:focus-visible, .y-textarea:focus-visible {
  outline: none;
}
/* Honour users who ask the OS to minimise motion: drop the decorative
   transitions/animations the chrome uses, keeping the UI fully functional. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* Smooth the theme flip so it doesn't feel like a hard cut. */
html, body, .y-ribbon, .y-titlebar, .y-formulabar, .y-sidepanel, .y-aipanel,
.y-status, .y-modal, .y-ctx-menu, .y-btn, .y-input, .y-select, .y-textarea {
  transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}

#root, .y-app { height: 100%; }

/* ============================ App shell ================================== */
.y-app {
  display: flex;
  flex-direction: column;
  height: 100vh;
  overflow: hidden;
}

.y-titlebar {
  display: flex;
  align-items: center;
  gap: var(--y-s3);
  height: 36px;
  padding: 0 var(--y-s4);
  background: linear-gradient(180deg, var(--y-titlebar-from) 0%, var(--y-titlebar-to) 100%);
  color: var(--y-titlebar-ink);
  border-bottom: 1px solid var(--y-border);
  flex: 0 0 auto;
}
.y-titlebar .y-logo {
  font-weight: 700;
  letter-spacing: .3px;
  font-size: var(--y-fs-lg);
  display: flex; align-items: center; gap: 7px;
}
.y-titlebar .y-logo .y-mark {
  display: inline-grid; place-items: center;
  width: 22px; height: 22px;
  background: var(--y-accent); color: var(--y-accent-ink);
  border-radius: var(--y-r-sm); font-weight: 800;
}
.y-titlebar .y-doc { color: var(--y-titlebar-doc); font-size: var(--y-fs-sm); }
.y-titlebar .y-spacer { flex: 1; }

/* Discreet "Éditions / À propos" link in the title bar (informational only). */
.y-titlebar-link {
  appearance: none; background: transparent; border: 0; cursor: pointer;
  color: var(--y-titlebar-doc); font: inherit; font-size: var(--y-fs-sm);
  padding: 4px 10px; border-radius: 6px; opacity: 0.85;
}
.y-titlebar-link:hover { opacity: 1; background: var(--y-hover-veil); }

/* ⌘K command-palette affordance in the title bar — a subtle pill with a key chip. */
.y-titlebar-cmdk {
  appearance: none; cursor: pointer; font: inherit; font-size: var(--y-fs-sm);
  display: inline-flex; align-items: center; gap: 7px;
  color: var(--y-titlebar-ink, var(--y-titlebar-doc));
  background: rgba(255, 255, 255, .10);
  border: 1px solid rgba(255, 255, 255, .20);
  border-radius: 999px; padding: 3px 10px 3px 8px; opacity: .92;
}
.y-titlebar-cmdk:hover { opacity: 1; background: rgba(255, 255, 255, .18); }
.y-titlebar-cmdk .y-cmdk-chip {
  font-size: var(--y-fs-xs); font-weight: 600; letter-spacing: .02em;
  padding: 1px 6px; border-radius: 5px; line-height: 1.4;
  background: rgba(255, 255, 255, .16); border: 1px solid rgba(255, 255, 255, .22);
}

/* 🎥 Live-conference primary action in the title bar — the obvious, one-click
   way to start a live collaboration session (was buried in the Partager menu).
   A filled accent pill so it reads as the primary call-to-action up here. */
.y-titlebar-conf {
  appearance: none; cursor: pointer; font: inherit; font-size: var(--y-fs-sm);
  font-weight: 600; display: inline-flex; align-items: center; gap: 6px;
  color: var(--y-accent-ink); background: var(--y-accent);
  border: 1px solid var(--y-accent); border-radius: 999px;
  padding: 4px 12px; box-shadow: var(--y-shadow-1);
  transition: background .1s, box-shadow .12s, transform .06s;
}
.y-titlebar-conf:hover { background: var(--y-accent-hover); box-shadow: var(--y-shadow-2); }
.y-titlebar-conf:active { transform: translateY(.5px); box-shadow: var(--y-shadow-1); }
/* "Session en cours": switch to a calm green-lit state so the live status reads
   at a glance (matches the 🟢 presence chip language). */
.y-titlebar-conf.is-live {
  background: var(--y-ok); border-color: var(--y-ok); color: #fff;
  animation: y-conf-pulse 2.4s ease-in-out infinite;
}
@keyframes y-conf-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(63, 191, 117, .45); }
  50%      { box-shadow: 0 0 0 4px rgba(63, 191, 117, 0); }
}

/* "À propos / Éditions" modal body. */
.y-about-intro { margin: 0 0 12px; }
.y-about-list { margin: 0 0 12px; padding-left: 18px; }
.y-about-list li { margin: 6px 0; }

/* compact theme controls that can live in the title bar */
.y-titlebar .y-theme-controls { display: flex; align-items: center; gap: var(--y-s2); }
.y-theme-toggle {
  appearance: none; cursor: pointer; font: inherit; font-size: var(--y-fs-sm);
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--y-titlebar-ink);
  background: rgba(255, 255, 255, .12);
  border: 1px solid rgba(255, 255, 255, .22);
  border-radius: var(--y-r-sm); padding: 3px 9px;
}
.y-theme-toggle:hover { background: rgba(255, 255, 255, .20); }

/* ============================ Ribbon ==================================== */
.y-ribbon { flex: 0 0 auto; background: var(--y-surface); border-bottom: 1px solid var(--y-border); }

.y-ribbon-tabs {
  display: flex; gap: 2px;
  padding: 0 var(--y-s4);
  background: var(--y-surface);
  border-bottom: 1px solid var(--y-border);
}
.y-tab {
  appearance: none; border: 0; background: transparent;
  padding: 8px var(--y-s4) 7px;
  font: inherit; font-size: var(--y-fs-md); color: var(--y-ink-soft);
  cursor: pointer; border-radius: var(--y-r-sm) var(--y-r-sm) 0 0;
  border-bottom: 2px solid transparent;
}
.y-tab:hover { background: var(--y-hover-veil); color: var(--y-ink); }
.y-tab.is-active {
  background: var(--y-surface); color: var(--y-accent);
  border-bottom-color: var(--y-accent); font-weight: 600;
}

/* Compact WRAPPING toolbar (Notion/Linear style): a tab's groups flow left to
   right and WRAP onto 2–3 short rows instead of scrolling off-screen on one
   endless horizontal line. Captions are gone (the button `title=`/`aria-label`
   carry the meaning as tooltips); clusters are separated by a single hairline.
   The ⌘K palette still covers the long tail. */
.y-ribbon-body {
  display: flex; align-items: center; gap: 0 2px;
  flex-wrap: wrap; row-gap: 3px;
  padding: 5px var(--y-s3);
  justify-content: flex-start;
}
.y-group {
  display: inline-flex; flex-direction: row; align-items: center;
  gap: var(--y-s2); padding: 0 var(--y-s3); position: relative; flex: 0 0 auto;
}
/* A single faint hairline between clusters (not an "Office wall of separators"):
   one per group except the first in its row. */
.y-group + .y-group { border-left: 1px solid var(--y-border); }
.y-group-controls { display: inline-flex; align-items: center; gap: var(--y-s2); }
/* Captions are now tooltips — hide the inline label entirely to reclaim the
   vertical space that made the old ribbon feel dense-yet-empty. */
.y-group-label { display: none; }

/* In the slim bar, the toggle-button clusters sit inline (side by side) rather
   than stacked, and any block/margin a group used for the old tall layout is
   neutralised so the whole tab stays on one 32px-tall line. */
.y-ribbon-body .y-toggle-row { display: inline-flex; vertical-align: middle; }
.y-ribbon-body .y-group-controls > label[style*="block"],
.y-ribbon-body .y-group-controls > .y-muted[style*="block"] { display: none !important; }
.y-ribbon-body .y-group-controls [style*="margin-top"] { margin-top: 0 !important; }
/* The verbose, rarely-used custom-number-format input + live preview is dropped
   from the bar (it lives in the Format-Cells dialog "Plus de formats…" + ⌘K).
   Detect it by its free-text input and hide that sub-row + the preview muted
   text, keeping the quick presets/toggles/steppers that people actually click. */
.y-ribbon-body .y-group-controls > .y-toggle-row:has(> input.y-input) { display: none; }
/* Advisory muted text (the Insertion "astuce" tip, the Options tagline) is pure
   chrome noise on a slim bar — hide whole groups whose only content is a caption
   span (and thus their separator), keeping every actual control. */
.y-ribbon-body .y-group:has(> .y-group-controls > .y-muted:only-child) { display: none; }
/* Keep icon-buttons tight in the bar. */
.y-ribbon-body .y-btn { padding: 4px 7px; }
.y-ribbon-body .y-btn.y-icon { padding: 4px 6px; min-width: 28px; }
.y-ribbon-body .y-select { padding: 3px 6px; }

/* buttons & inputs shared */
.y-btn {
  appearance: none; display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid transparent; background: transparent;
  padding: 5px 9px; border-radius: var(--y-r-sm);
  font: inherit; font-size: var(--y-fs-md); color: var(--y-ink);
  cursor: pointer; transition: background .08s, border-color .08s, box-shadow .12s, transform .06s;
}
.y-btn:hover { background: var(--y-hover-veil); border-color: transparent; }
.y-btn:active { background: var(--y-active-veil); transform: none; }
.y-btn.is-active { background: var(--y-accent-soft); border-color: var(--y-accent); color: var(--y-accent); }
.y-btn.y-icon { padding: 5px 7px; min-width: 30px; justify-content: center; }
.y-btn.y-primary {
  background: var(--y-accent); color: var(--y-accent-ink); border-color: var(--y-accent);
  font-weight: 600; box-shadow: var(--y-shadow-1);
}
.y-btn.y-primary:hover { background: var(--y-accent-hover); border-color: var(--y-accent-hover); box-shadow: var(--y-shadow-2); }
.y-btn.y-primary:active { box-shadow: var(--y-shadow-1); }
.y-btn.y-danger { color: var(--y-error); }
.y-btn.y-danger:hover { background: var(--y-danger-soft); border-color: var(--y-danger-line); }
/* Disabled controls: clearly inert — no hover/active affordance, no pointer. */
.y-btn:disabled { opacity: .5; cursor: not-allowed; box-shadow: none; }
.y-btn:disabled:hover { background: transparent; border-color: transparent; }
.y-btn.y-primary:disabled:hover { background: var(--y-accent); border-color: var(--y-accent); }
.y-btn:disabled:active { transform: none; }

.y-toggle-row { display: inline-flex; }
.y-toggle-row .y-btn { border-radius: 0; border-left-width: 0; }
.y-toggle-row .y-btn:first-child { border-radius: var(--y-r-sm) 0 0 var(--y-r-sm); border-left-width: 1px; }
.y-toggle-row .y-btn:last-child { border-radius: 0 var(--y-r-sm) var(--y-r-sm) 0; }
.y-toggle-row .y-btn { border-color: var(--y-border); }

.y-input, .y-select, .y-textarea {
  font: inherit; font-size: var(--y-fs-md); color: var(--y-ink);
  background: var(--y-surface); border: 1px solid var(--y-border);
  border-radius: var(--y-r-sm); padding: 5px 8px; outline: none;
  transition: border-color .1s, box-shadow .1s;
}
.y-input:focus, .y-select:focus, .y-textarea:focus {
  border-color: var(--y-accent); box-shadow: 0 0 0 3px var(--y-accent-ring);
}
.y-textarea { font-family: var(--y-mono); font-size: var(--y-fs-sm); resize: vertical; min-height: 64px; width: 100%; }
.y-color-swatch { width: 22px; height: 22px; border-radius: var(--y-r-sm); border: 1px solid var(--y-border-strong); padding: 0; cursor: pointer; }
.y-label { font-size: var(--y-fs-sm); color: var(--y-ink-soft); display: block; margin-bottom: 3px; }

/* ====================== Theme switcher (Options tab) ==================== */
.y-swatch-row { display: inline-flex; gap: 6px; align-items: center; }
.y-accent-swatch {
  appearance: none; width: 24px; height: 24px; padding: 0; cursor: pointer;
  border-radius: 50%; border: 2px solid var(--y-border);
  box-shadow: var(--y-shadow-1);
}
.y-accent-swatch:hover { transform: translateY(-1px); }
.y-accent-swatch.is-active { border-color: var(--y-ink); box-shadow: 0 0 0 3px var(--y-accent-ring); }

/* ====================== Formula bar / name box ========================== */
.y-formulabar {
  display: flex; align-items: stretch; gap: var(--y-s2);
  flex: 0 0 auto; height: var(--y-formula-h);
  padding: 0 var(--y-s2); background: var(--y-surface);
  border-bottom: 1px solid var(--y-border);
}
.y-namebox {
  width: 96px; flex: 0 0 auto; font-family: var(--y-mono);
  text-align: left; border-radius: var(--y-r-sm); align-self: center;
}
.y-ybtn {
  align-self: center; font-weight: 800; font-style: italic;
  width: 30px; height: 24px; border-radius: var(--y-r-sm);
  background: var(--y-accent); color: var(--y-accent-ink); border: 0; cursor: pointer;
  font-size: var(--y-fs-lg); line-height: 1;
}
.y-ybtn:hover { background: var(--y-accent-hover); }
.y-fx { align-self: center; color: var(--y-ink-faint); font-style: italic; font-family: var(--y-mono); padding: 0 4px; }
.y-formula-input { flex: 1; align-self: center; font-family: var(--y-mono); }

/* ====================== Work area (grid + panels) ======================= */
.y-work { display: flex; flex: 1; min-height: 0; }
.y-center { display: flex; flex-direction: column; flex: 1; min-width: 0; position: relative; }

.y-gridwrap { position: relative; flex: 1; min-height: 0; overflow: hidden; background: var(--y-surface); }
.y-grid-canvas { display: block; width: 100%; height: 100%; }

/* Custom scrollbars for the canvas grid (it has no native scroll). The
   horizontal bar is deliberately thick/easy to grab; both overlay the far
   edges and sit above the canvas but below the editor/overlays. */
.y-sb { position: absolute; z-index: 30; background: var(--y-surface-2); }
.y-sb-h { left: 0; right: 14px; bottom: 0; height: 14px; border-top: 1px solid var(--y-border); }
.y-sb-v { top: 0; bottom: 14px; right: 0; width: 14px; border-left: 1px solid var(--y-border); }
.y-sb-thumb { position: absolute; background: var(--y-border-strong); border-radius: 7px; transition: background .12s ease; }
.y-sb-h .y-sb-thumb { top: 2px; bottom: 2px; min-width: 28px; cursor: ew-resize; }
.y-sb-v .y-sb-thumb { left: 2px; right: 2px; min-height: 28px; cursor: ns-resize; }
.y-sb-thumb:hover { background: var(--y-ink-soft); }

/* the live cell editor floats over the canvas at the active cell */
.y-cell-editor {
  position: absolute; z-index: 20; font-family: var(--y-font); font-size: var(--y-fs-md);
  border: 2px solid var(--y-accent); background: var(--y-cell-editor-bg); color: var(--y-ink);
  padding: 1px 4px; outline: none;
  box-shadow: var(--y-shadow-2);
}

/* ====================== Left data panel (Données) ======================= */
.y-sidepanel {
  width: 300px; flex: 0 0 auto; background: var(--y-surface);
  border-right: 1px solid var(--y-border); display: flex; flex-direction: column; min-height: 0;
}
.y-sidepanel.is-collapsed { width: 0; overflow: hidden; border: 0; }
.y-panel-head { display: flex; align-items: center; justify-content: space-between; padding: var(--y-s2) var(--y-s3); border-bottom: 1px solid var(--y-border); }
.y-panel-title { font-weight: 600; font-size: var(--y-fs-md); }
.y-panel-body { flex: 1; overflow: auto; padding: var(--y-s3); }

.y-ds-list { display: flex; flex-direction: column; gap: 5px; }
.y-ds-item {
  display: flex; align-items: center; gap: 8px; padding: 6px 9px;
  border: 1px solid var(--y-border); border-radius: var(--y-r-md); cursor: pointer; background: var(--y-surface-2);
  transition: border-color .12s ease, background .12s ease, box-shadow .12s ease;
}
.y-ds-item:hover { border-color: var(--y-border-strong); box-shadow: var(--y-shadow-1); }
.y-ds-item.is-active { border-color: var(--y-accent); background: var(--y-accent-soft); box-shadow: none; }
.y-ds-item .y-ds-dot {
  width: 8px; height: 8px; border-radius: 50%; background: var(--y-ok); flex: 0 0 auto;
  box-shadow: 0 0 0 0 color-mix(in srgb, var(--y-ok) 50%, transparent);
}
/* The active source's live dot gets a soft, slow halo — a calm "this is live" cue. */
.y-ds-item.is-active .y-ds-dot { animation: y-ds-pulse 2.4s ease-in-out infinite; }
@keyframes y-ds-pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--y-ok) 45%, transparent); }
  50%      { box-shadow: 0 0 0 3px color-mix(in srgb, var(--y-ok) 0%, transparent); }
}
/* Source name stays on one line and ellipsizes — never wraps to a tall row. */
.y-ds-item .y-ds-name { flex: 1 1 auto; min-width: 0; font-weight: 500; cursor: pointer; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Add-source actions: full-width, stacked, never wrapping. Primary "add" + a
   quiet "browse the catalogue". */
.y-ds-actions { display: flex; flex-direction: column; gap: 6px; margin-top: 10px; }
.y-ds-actions .y-btn { width: 100%; white-space: nowrap; justify-content: center; }
.y-ds-browse { background: transparent; border: 1px solid var(--y-border); color: var(--y-ink-soft); }
.y-ds-browse:hover { border-color: var(--y-accent); color: var(--y-accent); background: var(--y-accent-soft); }
.y-ds-item .y-ds-kind {
  flex: 0 0 auto; font-size: var(--y-fs-xs); text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--y-ink-faint); border: 1px solid var(--y-border); border-radius: var(--y-r-sm); padding: 1px 6px;
}
.y-ds-item .y-ds-del { flex: 0 0 auto; opacity: 0; transition: opacity .12s ease; }
.y-ds-item:hover .y-ds-del, .y-ds-item:focus-within .y-ds-del { opacity: .65; }
.y-ds-item .y-ds-del:hover, .y-ds-item .y-ds-del:focus-visible { opacity: 1; }

/* Per-source AI access toggle: ✦ when allowed (accent), ⊘ when blocked (faint).
   Quiet by default (revealed like the delete affordance), but a BLOCKED source
   always shows its ⊘ so the off state is never hidden. */
.y-ds-item .y-ds-ai { flex: 0 0 auto; opacity: 0; color: var(--y-accent); transition: opacity .12s ease; }
.y-ds-item:hover .y-ds-ai, .y-ds-item:focus-within .y-ds-ai { opacity: .75; }
.y-ds-item .y-ds-ai:hover, .y-ds-item .y-ds-ai:focus-visible { opacity: 1; }
.y-ds-item .y-ds-ai.is-off { opacity: .85; color: var(--y-ink-faint); }
.y-ds-item .y-ds-ai.is-off:hover, .y-ds-item .y-ds-ai.is-off:focus-visible { opacity: 1; }

/* Step 2b: an INCOMPLETE source (travelled secret-free) — greyed, with a
   "compléter" affordance. Scoped to .y-ds-incomplete so it never affects live
   sources. */
.y-ds-item.y-ds-incomplete { opacity: 0.6; border-style: dashed; }
.y-ds-item.y-ds-incomplete .y-ds-name { font-style: italic; cursor: default; }
.y-ds-item.y-ds-incomplete .y-ds-complete {
  flex: 0 0 auto; white-space: nowrap; font-size: var(--y-fs-xs);
  color: var(--y-warn, #b8860b); width: auto; padding: 0 6px;
}

/* Source list grouped by kind: a small header per group, items nested below. */
.y-ds-group { display: flex; flex-direction: column; gap: 6px; }
.y-ds-group + .y-ds-group { margin-top: 10px; }
.y-ds-group-title {
  display: flex; align-items: center; gap: 6px;
  font-size: var(--y-fs-xs); font-weight: 600; color: var(--y-ink-soft);
  text-transform: uppercase; letter-spacing: 0.04em;
}

/* Add-source kind picker: wrap the segmented buttons so all four kinds fit. */
.y-ds-kinds { display: flex; flex-wrap: wrap; }
.y-ds-badge {
  display: inline-block; font-size: 10px; font-weight: 700; letter-spacing: 0.05em;
  background: var(--y-surface-3); border-radius: var(--y-r-sm); padding: 0 3px; margin-right: 2px;
}
/* Key/value (headers) editor in the add-source form. */
.y-kv { display: flex; flex-direction: column; gap: 4px; }

.y-tree { list-style: none; margin: 0; padding: 0; font-family: var(--y-mono); font-size: var(--y-fs-sm); }
.y-tree li { padding: 3px 6px; border-radius: var(--y-r-sm); cursor: pointer; }
.y-tree li:hover { background: var(--y-surface-3); }
.y-tree .y-tree-table { font-weight: 600; }
.y-tree .y-tree-col { padding-left: 20px; color: var(--y-ink-soft); }
.y-tree .y-tree-col .y-coltype { color: var(--y-ink-faint); }

/* WYSIWYG field picker (schema tree). Each row shows a label, a type chip and a
   muted sample on the right. Leaf rows are clickable (bind to the active cell);
   parent (object/array) rows are non-interactive headers. */
.y-field-tree { font-family: inherit; }
/* A field row is three tidy columns: label (flexes, ellipsis), a quiet type
   tag (fixed), and the sample value (fixed, right-aligned) — so types and
   samples line up vertically instead of floating mid-row. */
.y-field-row-item {
  display: flex; align-items: center; gap: 8px;
  padding: 3px 6px; border-radius: var(--y-r-sm);
}
.y-field-row-item.is-leaf { cursor: pointer; }
.y-field-row-item.is-leaf:hover { background: var(--y-accent-soft); }
.y-field-row-item.is-parent { cursor: default; color: var(--y-ink-soft); font-weight: 600; }
.y-field-row-item.is-parent:hover { background: transparent; }
.y-field-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.y-type-chip {
  flex: 0 0 40px; text-align: right;
  font-size: 9px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--y-ink-faint); background: transparent; padding: 0;
}
.y-field-sample {
  flex: 0 0 76px; min-width: 0; text-align: right;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-family: var(--y-mono); font-size: var(--y-fs-xs); color: var(--y-ink-soft);
}

/* Visual query builder ("blindé ergonomique", no hand-typed queries): an entity
   search list, a typed field list (checkbox = include as column, ⧩ = filter),
   click-built filter rows, selected-column chips, and a sort/limit row. Reuses
   the design tokens + .y-tree / .y-field-row-item / .y-chip primitives. */
.y-qb-entities, .y-qb-fields { max-height: 168px; overflow-y: auto; }
.y-qb-entities .y-tree-table { cursor: pointer; }
.y-qb-entities .y-tree-table.is-active,
.y-qb-fields .y-field-row-item.is-active { background: var(--y-accent-soft); }
.y-qb-field { gap: 6px; }
.y-qb-col-toggle { flex: 0 0 auto; display: flex; align-items: center; cursor: pointer; }
.y-qb-flt-add { flex: 0 0 auto; padding: 0 5px; line-height: 1.4; opacity: .65; }
.y-qb-field:hover .y-qb-flt-add { opacity: 1; }
.y-qb-filter {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  padding: 4px 6px; border-radius: var(--y-r-sm); background: var(--y-surface-sunken);
  margin-bottom: 4px;
}
.y-qb-filter .y-field-label { flex: 0 1 auto; font-weight: 600; }
.y-qb-val { flex: 1 1 70px; min-width: 60px; }
.y-qb-limit { flex: 0 0 64px; width: 64px; }
.y-qb-col-chips { display: flex; flex-wrap: wrap; gap: 4px; }
.y-qb-error { display: flex; flex-direction: column; gap: 6px; }
.y-qb-error-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.y-qb-retry { flex: 0 0 auto; }

/* Semantic browser: role-grouped, unit-aware field picker (prefers the
   /api/metamodel view). Reuses .y-field-tree / .y-field-row-item rows; adds a
   role glyph, a role-group header, a quiet unit chip and a muted stat hint. */
.y-sem-coll { margin-bottom: var(--y-s2); }
.y-sem-coll-title {
  font-size: var(--y-fs-sm); font-weight: 600; color: var(--y-ink);
  padding: 2px 6px; margin-bottom: 2px;
}
.y-sem-group { margin-bottom: 6px; }
.y-sem-group-title {
  display: flex; align-items: center; gap: 6px; padding: 0 6px; margin-bottom: 1px;
}
.y-sem-group-label {
  font-size: var(--y-fs-xs); text-transform: uppercase; letter-spacing: .5px;
  color: var(--y-ink-faint); font-weight: 600;
}
.y-sem-group-count {
  font-size: 9px; color: var(--y-ink-faint);
  border: 1px solid var(--y-border); border-radius: 999px; padding: 0 5px; line-height: 14px;
}
/* The role glyph: fixed, dim, centred so labels align across rows. */
.y-sem-role-icon {
  flex: 0 0 16px; text-align: center; color: var(--y-ink-faint);
  font-size: var(--y-fs-xs);
}
.y-sem-group-title .y-sem-role-icon { color: var(--y-accent); }
/* Quiet unit chip (e.g. €, °C) — a tasteful pill next to the label. */
.y-unit-chip {
  flex: 0 0 auto; font-size: 9px; font-weight: 600;
  color: var(--y-ink-soft); background: var(--y-accent-soft);
  border-radius: var(--y-r-sm); padding: 0 5px; line-height: 15px;
}
/* Muted tabular stat hint (min–max / n distinct). */
.y-field-hint {
  flex: 0 0 auto; font-size: 9px; color: var(--y-ink-faint);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 80px;
}
/* Relations footnote (foreign keys). */
.y-sem-relations {
  margin-top: 6px; padding: 6px; border-top: 1px solid var(--y-border);
}
.y-sem-rel {
  font-family: var(--y-mono); font-size: var(--y-fs-xs); color: var(--y-ink-soft);
  padding: 1px 6px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.y-results { width: 100%; border-collapse: collapse; font-size: var(--y-fs-sm); }
.y-results th, .y-results td { border: 1px solid var(--y-border); padding: 4px 7px; text-align: left; white-space: nowrap; }
.y-results th { background: var(--y-surface-3); position: sticky; top: 0; }

.y-section { margin-bottom: var(--y-s4); }
.y-section-title { font-size: var(--y-fs-xs); text-transform: uppercase; letter-spacing: .5px; color: var(--y-ink-faint); margin-bottom: 6px; }

/* ============== Contextual cell inspector (top of Données) ============== */
/* Leads the panel with "what is this cell": Format + Provenance, reacting to
   every selection change. */
.y-cellctx { border-bottom: 1px solid var(--y-border); }
.y-cellctx-title { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.y-cellctx-addr { font-family: var(--y-mono); text-transform: none; letter-spacing: 0; font-size: var(--y-fs-xs); }
.y-cellctx-grid { display: flex; flex-direction: column; gap: 3px; margin-bottom: 6px; }
.y-cellctx-row { display: flex; align-items: baseline; gap: 8px; font-size: var(--y-fs-sm); }
.y-cellctx-key { flex: 0 0 38%; font-size: var(--y-fs-xs); }
.y-cellctx-val { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.y-cellctx-fill { display: inline-flex; align-items: center; gap: 6px; }
.y-cellctx-swatch { width: 12px; height: 12px; border-radius: 3px; border: 1px solid var(--y-border); display: inline-block; }
.y-cellctx-empty { padding: 2px 0; }
.y-cellctx-edit, .y-cellctx-explain { margin-top: 2px; font-size: var(--y-fs-xs); }
/* Contextual cell error readout. */
.y-cellctx-errcode { font-family: var(--y-mono); font-size: var(--y-fs-xs); color: var(--y-error); font-weight: 700; }
.y-cellctx-errmsg { font-size: var(--y-fs-sm); color: var(--y-ink); line-height: 1.45; margin: 2px 0 4px; }
/* Source-management blocks live in the left panel only on a ⚡ source sheet. */
.y-hide-unless-source { display: none !important; }
/* Generic hide utility (e.g. the AI compose box when no provider is set up). */
.y-hidden { display: none !important; }
.y-cellctx-prov { display: flex; flex-direction: column; gap: 4px; margin-bottom: 6px; }
.y-cellctx-prov-row { display: flex; align-items: center; gap: 6px; font-size: var(--y-fs-sm); }
.y-cellctx-prov-val { font-family: var(--y-mono); font-size: var(--y-fs-xs); margin-left: auto; }
.y-cellctx-formula {
  display: block; font-family: var(--y-mono); font-size: var(--y-fs-xs);
  color: var(--y-ink-soft); background: var(--y-surface-2, rgba(0,0,0,.03));
  border-radius: 4px; padding: 4px 6px; max-height: 64px; overflow: auto; white-space: pre-wrap;
}
.y-cellctx-deps { display: flex; flex-direction: column; gap: 4px; }
.y-cellctx-dep-list { display: flex; flex-wrap: wrap; gap: 4px; }
.y-cellctx-dep {
  font-family: var(--y-mono); font-size: var(--y-fs-xs); cursor: pointer;
  border: 1px solid var(--y-border); border-radius: 3px; padding: 0 5px; line-height: 1.6;
  background: transparent; color: var(--y-ink-soft);
}
.y-cellctx-dep:hover { border-color: var(--y-accent, #4c6ef5); color: var(--y-ink); }

/* ====================== Cell flow inspector ============================= */
/* A vertical pipeline of labelled chips connected by a thin accent line,
   revealing the live source behind the active cell. */
.y-flow-section {
  border-top: 1px solid var(--y-border);
  padding-top: var(--y-s3);
  margin-top: var(--y-s2);
}
.y-flow-empty { font-size: var(--y-fs-xs); line-height: 1.4; }

.y-flow { display: flex; flex-direction: column; align-items: stretch; }

.y-flow-node {
  position: relative;
  background: var(--y-surface-2);
  border: 1px solid var(--y-border);
  border-radius: var(--y-r-md);
  padding: 6px 10px 7px;
  display: flex; flex-direction: column; gap: 2px;
}
/* A subtle accent rail down the left edge ties the nodes together. */
.y-flow-node::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0;
  width: 3px; border-radius: var(--y-r-md) 0 0 var(--y-r-md);
  background: var(--y-accent);
}

.y-flow-node-label {
  font-size: var(--y-fs-xs); text-transform: uppercase; letter-spacing: .4px;
  color: var(--y-ink-faint);
}
.y-flow-node-body { display: flex; align-items: center; gap: 6px; min-width: 0; }
.y-flow-node-main {
  font-weight: 600; color: var(--y-ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
.y-flow-glyph { color: var(--y-accent); font-size: 11px; flex: 0 0 auto; }

.y-flow-query {
  font-family: var(--y-mono);
  font-size: var(--y-fs-xs); color: var(--y-ink-soft);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  display: block; min-width: 0; width: 100%;
}

.y-flow-value {
  font-weight: 700; color: var(--y-ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
.y-flow-ref {
  margin-left: auto; flex: 0 0 auto;
  font-size: var(--y-fs-xs); color: var(--y-ink-faint);
  background: var(--y-surface); border: 1px solid var(--y-border);
  border-radius: var(--y-r-sm); padding: 0 5px;
}

.y-flow-refresh-body { justify-content: space-between; gap: 8px; }
.y-flow-refresh { font-size: var(--y-fs-xs); color: var(--y-ink-soft); }

/* The fresh/stale pill reuses .y-pill; the "ok" variant tints it green. */
.y-pill.y-flow-ok { color: var(--y-ok); border-color: var(--y-ok); }
.y-flow-dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--y-ok); flex: 0 0 auto;
  /* A calm, slow breathing halo so the "live" indicator reads as flowing, not
     static. Low-amplitude + slow (matches .y-ds-dot); auto-suppressed by the
     prefers-reduced-motion rule above. */
  animation: y-ds-pulse 2.4s ease-in-out infinite;
}
/* Stale data: no breathing — it isn't flowing — and a muted colour. */
.y-flow-dot.is-stale { background: var(--y-stale); animation: none; }

/* The downward connector between nodes: a thin centred line with an arrow. */
.y-flow-connector {
  width: 0; height: 14px; margin: 0 auto;
  border-left: 2px solid var(--y-border-strong);
  position: relative;
}
.y-flow-connector::after {
  content: ""; position: absolute; left: 50%; bottom: -1px;
  transform: translateX(-50%);
  border-left: 4px solid transparent; border-right: 4px solid transparent;
  border-top: 5px solid var(--y-border-strong);
}

/* ---- Temporal sparkline node ("magic v2": the series behind the cell) ---- */
.y-spark-body { flex-direction: column; align-items: stretch; gap: 4px; }
.y-spark-measure {
  font-weight: 600; color: var(--y-ink);
  font-size: var(--y-fs-xs);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
.y-spark {
  width: 100%; height: 40px; display: block;
  overflow: visible;
}
.y-spark-line {
  fill: none; stroke: var(--y-accent); stroke-width: 1.5;
  stroke-linejoin: round; stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}
.y-spark-base {
  stroke: var(--y-border); stroke-width: 1;
  vector-effect: non-scaling-stroke;
}
.y-spark-mark {
  fill: var(--y-accent); stroke: var(--y-surface-2); stroke-width: 1;
}
.y-spark-stats {
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
  font-size: var(--y-fs-xs); color: var(--y-ink-soft);
}
.y-spark-agg { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.y-spark-count { flex: 0 0 auto; color: var(--y-ink-faint); }

/* ============== Flux reveal (magic v3): the flipping floating card ======= */
/*
 * The overlay layer fills `.y-gridwrap` and is click-through (pointer-events:
 * none) so the canvas keeps receiving clicks; only the card's own controls
 * re-enable pointer events. Each child is absolutely positioned in gridwrap-
 * local px by the component. The card lies flat on the cell then tilts up to
 * face the viewer.
 */
.y-flow-reveal-layer {
  position: absolute; inset: 0; z-index: 35;
  pointer-events: none;            /* never intercept grid clicks */
  overflow: visible;
}

/* The 3D stage: perspective makes the flip read as depth. The card stands up
 * from the cell — origin at the bottom when above the cell, top when below. */
.y-flow-reveal {
  position: absolute;
  perspective: 1200px;
  pointer-events: none;
  /* keep the card above the connector/pin */
  z-index: 2;
}

.y-flow-reveal-card {
  pointer-events: auto;            /* the card itself is interactive */
  background: var(--y-surface);
  border: 1px solid var(--y-border);
  border-radius: var(--y-r-lg);
  box-shadow: var(--y-shadow-3);
  padding: 10px 12px 12px;
  max-height: 232px;
  overflow: hidden;
  transform-origin: bottom center;
  /* start lying flat on the cell, invisible, then flip up */
  animation: y-flow-flip 260ms cubic-bezier(.22,.68,.32,1.2) both;
  /* a thin accent hairline along the top sells the "screen" feel */
  border-top: 2px solid var(--y-accent);
}
/* When the card sits below the cell it pivots from its top edge instead. */
.y-flow-reveal.is-below .y-flow-reveal-card {
  transform-origin: top center;
  animation-name: y-flow-flip-below;
}

@keyframes y-flow-flip {
  from { transform: rotateX(-78deg); opacity: 0; }
  to   { transform: rotateX(0deg);   opacity: 1; }
}
@keyframes y-flow-flip-below {
  from { transform: rotateX(78deg); opacity: 0; }
  to   { transform: rotateX(0deg);  opacity: 1; }
}

/* The card reuses the side-panel flow nodes verbatim; tighten spacing a touch
 * for the floating, compact context. */
.y-flow-reveal-card .y-flow-node { padding: 5px 9px 6px; }
.y-flow-reveal-card .y-flow-connector { height: 12px; }

/* Thin connector line from the cell up/down to the card. */
.y-flow-reveal-connector {
  position: absolute; width: 2px;
  transform: translateX(-1px);
  background: linear-gradient(to bottom,
    var(--y-accent), color-mix(in srgb, var(--y-accent) 25%, transparent));
  pointer-events: none;
  z-index: 1;
  border-radius: 2px;
}
/* The pin where the flow emerges from the cell. */
.y-flow-reveal-pin {
  position: absolute; width: 9px; height: 9px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: var(--y-accent);
  box-shadow: 0 0 0 3px var(--y-accent-ring);
  pointer-events: none;
  z-index: 1;
}

/* magic v4: secondary (non-active) cards are dimmed + scaled down a touch so the
 * active cell's card stays the hero. They still flip up and stay upright/legible;
 * z-index (set inline, staggered by row) handles their cascade. */
.y-flow-reveal.is-secondary { opacity: .82; }
.y-flow-reveal.is-secondary .y-flow-reveal-card {
  transform-origin: bottom center;
  scale: .92;                         /* slightly smaller than the active card */
  border-top-color: color-mix(in srgb, var(--y-accent) 55%, transparent);
  box-shadow: var(--y-shadow-2);
}
.y-flow-reveal.is-secondary:hover { opacity: 1; }   /* lift on hover to read it */
.y-flow-reveal.is-active .y-flow-reveal-card { box-shadow: var(--y-shadow-3); }
/* Secondary connectors/pins are quieter so the active flow's line reads first. */
.y-flow-reveal-connector.is-secondary { opacity: .5; }
.y-flow-reveal-pin.is-secondary { opacity: .6; box-shadow: 0 0 0 2px var(--y-accent-ring); }

/* "Pivoter" presentation tilt (magic v4): while BOTH Flux + Pivoter are on, the
 * gridwrap becomes a 3D stage and the CANVAS pivots back, so the upright flow
 * cards (in the overlay, NOT transformed) read as floating above a tilted grid.
 * CRITICAL: a transform on the canvas desyncs pointer hit-testing (the canvas
 * reads its transformed getBoundingClientRect), so this mode is view-only — the
 * editor is suppressed and a "présentation" hint is shown. Toggling off removes
 * the class → flat & fully interactive again. We never tilt unless on. */
.y-gridwrap.y-flow-pivot-on { perspective: 1400px; perspective-origin: 50% 0%; }
.y-gridwrap.y-flow-pivot-on .y-grid-canvas {
  transform: rotateX(8deg) scale(.96);
  transform-origin: 50% 12%;
  transition: transform .35s cubic-bezier(.22,.68,.32,1.2);
  /* The 3D transform desyncs mouse->cell hit-testing, so pivot mode is honestly
     view-only: the canvas ignores pointer input (no misleading offset selection).
     Exit via the toggle. */
  pointer-events: none;
}
/* The overlay (flow cards) is explicitly NOT tilted — it floats flat & upright
 * above the pivoted canvas. (It already sits above via its own z-index.) */

/* Présentation hint badge, pinned bottom-centre of the grid while pivoted. */
.y-flow-pivot-hint {
  position: absolute; left: 50%; bottom: 12px; transform: translateX(-50%);
  z-index: 1100;                       /* above all flow cards */
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 12px; border-radius: 999px;
  background: var(--y-accent-soft); color: var(--y-accent);
  border: 1px solid var(--y-accent);
  box-shadow: var(--y-shadow-2);
  font-size: 12px; font-weight: 600;
  pointer-events: none;
  animation: y-flow-flip 220ms ease both;
}
.y-flow-pivot-hint-glyph { font-size: 11px; line-height: 1; }

/* The status-bar Flux toggle. */
.y-flux-toggle {
  cursor: pointer; display: inline-flex; align-items: center; gap: 4px;
  background: var(--y-surface-2); color: var(--y-ink-soft);
  transition: color .12s, border-color .12s, background .12s;
}
.y-flux-toggle:hover { border-color: var(--y-border-strong); color: var(--y-ink); }
.y-flux-toggle.is-on {
  background: var(--y-accent-soft); color: var(--y-accent);
  border-color: var(--y-accent);
}
.y-flux-glyph { font-size: 11px; line-height: 1; }

/* The status-bar Pivoter sub-toggle (only enabled while Flux is on). */
.y-pivot-toggle {
  cursor: pointer; display: inline-flex; align-items: center; gap: 4px;
  background: var(--y-surface-2); color: var(--y-ink-soft);
  transition: color .12s, border-color .12s, background .12s;
}
.y-pivot-toggle:hover:not(:disabled) { border-color: var(--y-border-strong); color: var(--y-ink); }
.y-pivot-toggle.is-on {
  background: var(--y-accent-soft); color: var(--y-accent);
  border-color: var(--y-accent);
}
.y-pivot-toggle:disabled { opacity: .45; cursor: default; }
.y-pivot-glyph { font-size: 11px; line-height: 1; }

/* ====================== Right AI panel ================================== */
.y-aipanel {
  width: var(--y-ai-w); flex: 0 0 auto; background: var(--y-surface);
  border-left: 1px solid var(--y-border); display: flex; flex-direction: column; min-height: 0;
}
.y-aipanel.is-collapsed { width: 36px; }
.y-ai-head {
  display: flex; align-items: center; gap: 8px; padding: var(--y-s2) var(--y-s3);
  border-bottom: 1px solid var(--y-border); background: linear-gradient(180deg, var(--y-aihead-from), var(--y-aihead-to));
}
.y-ai-head .y-ai-spark { color: var(--y-accent); font-size: var(--y-fs-lg); align-self: flex-start; margin-top: 1px; }
.y-ai-head .y-ai-sub { font-size: var(--y-fs-xs); color: var(--y-ink-soft); line-height: 1.3; overflow: hidden; text-overflow: ellipsis; }
/* Subtle running-engine label (provider · model) under the subtitle. */
.y-ai-head .y-ai-engine {
  display: flex; align-items: center; gap: 5px; margin-top: 2px;
  font-size: var(--y-fs-xs); color: var(--y-ink-faint); font-family: var(--y-mono);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.y-ai-head .y-ai-engine-dot {
  flex: 0 0 auto; width: 6px; height: 6px; border-radius: 50%;
  background: var(--y-ok, #3ba776); box-shadow: 0 0 0 2px var(--y-accent-soft);
}
.y-ai-body { flex: 1; overflow: auto; padding: var(--y-s3); display: flex; flex-direction: column; gap: var(--y-s3); }
.y-ai-card { border: 1px solid var(--y-border); border-radius: var(--y-r-md); padding: var(--y-s3); background: var(--y-surface-2); }
.y-ai-sql { font-family: var(--y-mono); font-size: var(--y-fs-sm); white-space: pre-wrap; background: var(--y-code-bg); color: var(--y-code-ink); padding: 10px; border-radius: var(--y-r-sm); }
.y-ai-provider { font-size: var(--y-fs-xs); color: var(--y-ink-faint); margin-top: 6px; }
.y-collapse-tab {
  writing-mode: vertical-rl; text-orientation: mixed; cursor: pointer;
  padding: 10px 6px; color: var(--y-ink-soft);
  border-radius: var(--y-r-sm); transition: color .12s ease, background .12s ease;
}
.y-collapse-tab:hover { color: var(--y-accent); background: var(--y-accent-soft); }

/* ---- agentic assistant (chat thread + compose) ---- */
.y-agent { min-height: 0; }
/* scrollable message thread */
.y-ai-thread {
  flex: 1; min-height: 0; overflow-y: auto; padding: var(--y-s3);
  display: flex; flex-direction: column; gap: 10px;
}
.y-ai-empty {
  color: var(--y-ink-soft); font-size: var(--y-fs-sm); line-height: 1.55;
  padding: var(--y-s4) var(--y-s3); border: 1px dashed var(--y-border); border-radius: var(--y-r-md);
  background: var(--y-surface-2); text-align: center;
}
/* A friendly spark glyph leads the AI empty state. */
.y-ai-empty::before {
  content: "✦"; display: block; font-size: var(--y-fs-xl);
  color: var(--y-accent); margin-bottom: 6px;
}
.y-ai-msg { display: flex; }
.y-ai-msg.y-ai-user { justify-content: flex-end; }
.y-ai-msg.y-ai-asst { justify-content: flex-start; }
.y-ai-bubble {
  max-width: 90%; padding: 8px 11px; border-radius: var(--y-r-md);
  font-size: var(--y-fs-sm); line-height: 1.5; white-space: pre-wrap; word-break: break-word;
}
.y-ai-user .y-ai-bubble { background: var(--y-accent); color: var(--y-accent-ink); border-bottom-right-radius: 3px; }
.y-ai-asst .y-ai-bubble { background: var(--y-surface-2); color: var(--y-ink); border: 1px solid var(--y-border); border-bottom-left-radius: 3px; }
/* compact tool-action chip */
.y-ai-chip {
  display: inline-flex; align-items: center; gap: 6px; align-self: flex-start;
  padding: 3px 9px; border-radius: 999px; background: var(--y-surface-2);
  border: 1px solid var(--y-border); color: var(--y-ink-soft); font-size: var(--y-fs-xs);
}
.y-ai-chip-icon { color: var(--y-accent); }
.y-ai-chip-ref { font-family: var(--y-mono); color: var(--y-ink-faint); }
/* Clickable cell citation inside an assistant reply: a subtle monospace accent
   link that jumps the grid to the cited cell/range. */
.y-cell-cite {
  font-family: var(--y-mono); color: var(--y-accent); cursor: pointer;
  border-radius: 4px; padding: 0 2px;
  text-decoration: underline; text-decoration-style: dotted;
  text-underline-offset: 2px; text-decoration-thickness: 1px;
}
.y-cell-cite:hover { background: var(--y-accent-soft); text-decoration-style: solid; }
.y-cell-cite:focus-visible { outline: 2px solid var(--y-accent-ring); outline-offset: 1px; }
.y-ai-notice {
  font-size: var(--y-fs-sm); line-height: 1.5; color: var(--y-ink);
  background: var(--y-accent-soft); border: 1px solid var(--y-accent);
  border-radius: var(--y-r-md); padding: 9px 11px;
}
/* thinking indicator */
.y-ai-thinking { display: flex; align-items: center; gap: 8px; color: var(--y-ink-soft); font-size: var(--y-fs-sm); }
.y-ai-dots { display: inline-flex; gap: 3px; }
.y-ai-dots i { width: 5px; height: 5px; border-radius: 50%; background: var(--y-accent); opacity: .35; animation: y-ai-blink 1.2s infinite; }
.y-ai-dots i:nth-child(2) { animation-delay: .2s; }
.y-ai-dots i:nth-child(3) { animation-delay: .4s; }
@keyframes y-ai-blink { 0%,80%,100% { opacity: .25; } 40% { opacity: 1; } }
/* bottom compose box */
.y-ai-compose {
  flex: 0 0 auto; border-top: 1px solid var(--y-border); padding: var(--y-s3);
  display: flex; flex-direction: column; gap: var(--y-s2); background: var(--y-surface);
}
.y-ai-input { resize: vertical; min-height: 44px; max-height: 160px; }
/* Compact per-conversation token counter, just above the compose box. */
.y-ai-tokens {
  flex: 0 0 auto; display: flex; align-items: baseline; gap: 5px;
  padding: 2px var(--y-s3); font-size: var(--y-fs-xs); color: var(--y-ink-faint);
}
.y-ai-tokens .y-ai-tokens-n { font-weight: 600; color: var(--y-ink-soft); font-variant-numeric: tabular-nums; }
.y-ai-tokens .y-ai-tokens-split { margin-left: auto; font-family: var(--y-mono); opacity: .8; }
.y-ai-compose-row { display: flex; align-items: center; gap: var(--y-s2); }
.y-ai-attach { flex: 0 0 auto; }
.y-ai-send { flex: 1 1 auto; }
/* attached-document chips, shown just above the compose box */
.y-ai-attachments {
  flex: 0 0 auto; display: flex; flex-wrap: wrap; gap: 6px;
  padding: var(--y-s2) var(--y-s3) 0; background: var(--y-surface);
}
.y-ai-attach-chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 6px 3px 9px; border-radius: 999px; background: var(--y-surface-2);
  border: 1px solid var(--y-border); color: var(--y-ink-soft); font-size: var(--y-fs-xs);
  max-width: 100%;
}
.y-ai-attach-icon { color: var(--y-accent); }
.y-ai-attach-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 160px; }
.y-ai-attach-x {
  border: none; background: transparent; cursor: pointer; color: var(--y-ink-faint);
  font-size: 14px; line-height: 1; padding: 0 2px; border-radius: 4px;
}
.y-ai-attach-x:hover { color: var(--y-ink); background: var(--y-border); }

/* ====================== Autocomplete popover ============================ */
.y-autocomplete {
  position: absolute; z-index: 40; min-width: 280px; max-height: 260px; overflow: auto;
  background: var(--y-surface); border: 1px solid var(--y-border-strong);
  border-radius: var(--y-r-md); box-shadow: var(--y-shadow-3); padding: 4px;
  /* Always drop BELOW the anchor (the formula bar, or the in-cell editor's
     zero-height wrapper) instead of overlapping it at the static position. */
  top: 100%; left: 0;
}
.y-ac-item { display: flex; flex-direction: column; padding: 6px 9px; border-radius: var(--y-r-sm); cursor: pointer; transition: background .08s ease; }
.y-ac-item:hover { background: var(--y-surface-2); }
.y-ac-item.is-active { background: var(--y-accent-soft); }
.y-ac-item.is-active .y-ac-summary { color: var(--y-ink-soft); }
.y-ac-item .y-ac-name { font-family: var(--y-mono); font-weight: 600; color: var(--y-accent); }
.y-ac-item .y-ac-sig { font-family: var(--y-mono); font-size: var(--y-fs-xs); color: var(--y-ink-soft); }
.y-ac-item .y-ac-name-tag {
  margin-left: auto; font-family: inherit; font-size: 9px; text-transform: uppercase;
  letter-spacing: .4px; color: var(--y-accent); background: var(--y-accent-soft);
  padding: 0 5px; border-radius: var(--y-r-sm); align-self: center;
}
.y-ac-item .y-ac-summary { font-size: var(--y-fs-xs); color: var(--y-ink-faint); margin-top: 2px; }
.y-ac-cat { font-size: 9px; text-transform: uppercase; letter-spacing: .5px; color: var(--y-ink-faint); padding: 4px 9px 2px; }

/* ====================== Context menu =================================== */
.y-ctx-scrim { position: fixed; inset: 0; z-index: 90; }
.y-ctx-menu {
  position: fixed; min-width: 220px; padding: 5px;
  background: var(--y-surface); border: 1px solid var(--y-border-strong);
  border-radius: var(--y-r-md); box-shadow: var(--y-shadow-3);
  font-size: var(--y-fs-md); color: var(--y-ink);
}
.y-ctx-item {
  appearance: none; width: 100%; display: flex; align-items: center; gap: var(--y-s4);
  border: 0; background: transparent; cursor: pointer; text-align: left;
  padding: 6px 10px; border-radius: var(--y-r-sm); font: inherit; color: inherit;
}
.y-ctx-item:hover:not(:disabled) { background: var(--y-accent-soft); }
.y-ctx-item:disabled { color: var(--y-ink-faint); cursor: default; }
.y-ctx-item .y-ctx-label { flex: 1; }
.y-ctx-item .y-ctx-accel { color: var(--y-ink-faint); font-size: var(--y-fs-xs); font-family: var(--y-mono); }
.y-ctx-sep { height: 1px; background: var(--y-border); margin: 4px 2px; }
.y-ctx-heading {
  padding: 4px 10px 6px; font-size: var(--y-fs-xs); font-weight: 600;
  color: var(--y-ink-faint); text-transform: uppercase; letter-spacing: 0.04em;
}

/* ====================== Table AutoFilter popover ======================= */
.y-filter-popover {
  position: fixed; min-width: 220px; max-width: 280px; padding: 5px;
  background: var(--y-surface); border: 1px solid var(--y-border-strong);
  border-radius: var(--y-r-md); box-shadow: var(--y-shadow-3);
  font-size: var(--y-fs-md); color: var(--y-ink); z-index: 91;
}
.y-filter-list { max-height: 220px; overflow: auto; margin: 4px 0; }
.y-filter-row {
  display: flex; align-items: center; gap: var(--y-s4);
  padding: 4px 8px; border-radius: var(--y-r-sm); cursor: pointer;
}
.y-filter-row:hover { background: var(--y-accent-soft); }
.y-filter-row span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.y-filter-foot { display: flex; gap: var(--y-s4); justify-content: flex-end; margin-top: 4px; }

/* ====================== Sheet tabs (bottom) ============================= */
.y-sheet-tabs {
  flex: 0 0 auto; display: flex; align-items: stretch; gap: var(--y-s2);
  height: 30px; padding: 0 var(--y-s3); background: var(--y-surface-3);
  border-top: 1px solid var(--y-border); overflow-x: auto; overflow-y: hidden;
}
.y-sheet-tablist { display: flex; align-items: stretch; gap: 2px; }
.y-sheet-tab {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 0 10px; max-width: 220px; cursor: pointer; user-select: none;
  font-size: var(--y-fs-sm); color: var(--y-ink-soft);
  background: var(--y-surface-2); border: 1px solid var(--y-border);
  border-bottom: none; border-radius: var(--y-r-sm) var(--y-r-sm) 0 0;
  margin-top: 4px; white-space: nowrap;
}
.y-sheet-tab:hover { background: var(--y-surface); }
.y-sheet-tab.active {
  background: var(--y-surface); color: var(--y-ink); font-weight: 600;
  border-top: 2px solid var(--y-accent); margin-top: 3px;
}
.y-sheet-name { overflow: hidden; text-overflow: ellipsis; max-width: 160px; }
/* Source sheets (materialised data sources) read distinctly from ordinary
   sheets: an accent-tinted tab + a ⚡ bolt glyph, so live-data sheets stand
   apart from the user's own sheets. Pushed to the right of the tab list. */
.y-sheet-tab.source {
  color: var(--y-accent); background: var(--y-accent-soft);
  border-color: var(--y-accent-ring); order: 1;
}
.y-sheet-tab.source.active {
  background: var(--y-accent-soft); color: var(--y-accent);
  border-top: 2px solid var(--y-accent); font-weight: 600;
}
.y-sheet-bolt { font-size: 12px; line-height: 1; color: var(--y-accent); }

/* Source-sheet wizard (Données panel): a lightly-accented block so the
   "create a source sheet" affordance reads as the live-data action. */
.y-source-builder {
  border: 1px solid var(--y-accent-ring); border-radius: var(--y-r-sm);
  padding: 8px; background: var(--y-accent-soft);
}
.y-source-builder .y-section-title { color: var(--y-accent); }

/* --- Source-sheet metamodel explorer (data_panel.rs SourceExplorer) --- */
.y-source-explorer {
  border: 1px solid var(--y-accent-ring); border-radius: var(--y-r-sm);
  padding: 8px; background: var(--y-accent-soft);
}
.y-source-explorer .y-section-title { color: var(--y-accent); }
.y-source-rawsample { margin: 4px 0 6px; }
.y-source-json {
  margin: 4px 0 0; padding: 6px 8px; max-height: 180px; overflow: auto;
  font-family: var(--y-mono, ui-monospace, monospace); font-size: var(--y-fs-xs);
  background: var(--y-surface); color: var(--y-ink-soft);
  border: 1px solid var(--y-border); border-radius: var(--y-r-sm); white-space: pre;
}
/* The "+" / "✓" add markers on a discovered-path row. */
.y-field-add-mark { margin-left: auto; color: var(--y-accent); font-weight: 700; }
.y-field-added-mark { margin-left: auto; color: var(--y-ink-faint); }
.y-field-row-item.is-added { opacity: 0.6; cursor: default; }
.y-field-row-item.is-added:hover { background: transparent; }
.y-field-row-item.is-leaf:focus-visible {
  outline: 2px solid var(--y-accent); outline-offset: -2px; border-radius: var(--y-r-sm);
}
/* Per-path config rows. The left data panel is narrow (~270px) and a path packs
   a lot (label · reference chip · depth · subsampling · window · chart · stats),
   so the row is a deliberate TWO-LINE layout that never overflows:
     line 1: [☑ label .......................... Binance_prix]
     line 2: [depth · subsampling · window ............ 📈 📊]
   Line 2 right-aligns its controls; everything wraps gracefully if narrower. */
.y-source-path-row {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px; row-gap: 4px;
  padding: 4px 2px; border-top: 1px solid var(--y-border);
}
.y-source-path-toggle {
  display: flex; align-items: center; gap: 5px; flex: 1 1 auto; min-width: 0; cursor: pointer;
}
.y-source-path-toggle .y-field-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Reference chip ends line 1 (pushed to the right of the label). */
.y-source-path-row > .y-source-ref-chip { margin-left: auto; }
/* Controls take their own line (right-aligned). Keep them on ONE line and let
   the subsampling select shrink rather than letting the 📈/📊 actions wrap off. */
.y-source-path-controls { display: flex; flex-wrap: nowrap; align-items: center; gap: 6px; flex: 1 1 100%; min-width: 0; justify-content: flex-end; }
.y-source-path-controls .y-source-sub-select { flex: 0 1 auto; min-width: 56px; }
.y-source-path-controls .y-source-chart-btn { flex: 0 0 auto; }
.y-source-path-depth { display: inline-flex; align-items: center; gap: 3px; font-size: var(--y-fs-xs); }
.y-source-depth-input { width: 42px; padding: 1px 4px; text-align: right; }
.y-source-sub-select { padding: 1px 4px; font-size: var(--y-fs-xs); max-width: 110px; }
/* Click-to-copy formula reference name for a captured path (e.g. Binance_prix). */
.y-source-ref-chip {
  font-size: var(--y-fs-xs); padding: 0 5px; line-height: 16px; cursor: pointer;
  color: var(--y-accent); background: var(--y-accent-soft);
  border: 1px solid var(--y-accent-ring); border-radius: var(--y-r-sm);
  max-width: 130px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-family: var(--y-mono, ui-monospace, monospace);
}
.y-source-ref-chip:hover { background: var(--y-accent); color: var(--y-surface); }
.y-source-ref-chip:focus-visible { outline: 2px solid var(--y-accent); outline-offset: 1px; }
.y-source-chart-btn { font-size: 13px; padding: 0 3px; line-height: 18px; }

/* Name manager table. */
.y-names-table { width: 100%; border-collapse: collapse; font-size: var(--y-fs-sm); }
.y-names-table th { text-align: left; font-weight: 600; color: var(--y-ink-faint);
  font-size: var(--y-fs-xs); text-transform: uppercase; letter-spacing: .4px;
  padding: 2px 6px; border-bottom: 1px solid var(--y-border); }
.y-names-table td { padding: 3px 6px; border-bottom: 1px solid var(--y-border-soft, var(--y-border)); vertical-align: middle; }
.y-names-name code { font-family: var(--y-mono); color: var(--y-accent); font-weight: 600; }
.y-names-target code { font-family: var(--y-mono); font-size: var(--y-fs-xs); }
.y-names-actions { white-space: nowrap; text-align: right; }
.y-names-actions .y-btn { padding: 0 5px; }
.y-names-rename { width: 130px; padding: 1px 4px; font-family: var(--y-mono); }
.y-names-auto-badge { font-size: 9px; text-transform: uppercase; letter-spacing: .4px;
  color: var(--y-ink-faint); background: var(--y-surface-3); border: 1px solid var(--y-border);
  border-radius: var(--y-r-sm); padding: 0 5px; }
.y-names-create { display: inline-flex; gap: 4px; align-items: center; margin-right: auto; }
.y-names-create .y-input { width: 160px; }

/* Inline spinner for async loading states. */
.y-spinner {
  display: inline-block; width: 11px; height: 11px; margin-right: 6px;
  vertical-align: -1px; border: 2px solid var(--y-accent-ring);
  border-top-color: var(--y-accent); border-radius: 50%;
  animation: y-spin 0.7s linear infinite;
}
@keyframes y-spin { to { transform: rotate(360deg); } }
.y-sheet-rename {
  font: inherit; width: 110px; padding: 1px 3px; color: var(--y-ink);
  background: var(--y-surface); border: 1px solid var(--y-accent);
  border-radius: var(--y-r-sm); outline: none;
}
.y-sheet-actions { display: inline-flex; align-items: center; gap: 1px; }
.y-sheet-mv, .y-sheet-del, .y-sheet-add {
  display: inline-grid; place-items: center; width: 18px; height: 18px;
  padding: 0; border: none; background: transparent; cursor: pointer;
  color: var(--y-ink-faint); border-radius: var(--y-r-sm); font-size: 12px; line-height: 1;
}
.y-sheet-mv:hover, .y-sheet-del:hover, .y-sheet-add:hover {
  background: var(--y-accent-soft); color: var(--y-accent);
}
.y-sheet-add {
  align-self: center; width: 22px; height: 22px; font-size: 16px;
  color: var(--y-ink-soft); border: 1px solid transparent;
}
.y-sheet-add:hover { border-color: var(--y-border); }

/* ====================== Status bar ====================================== */
.y-status {
  flex: 0 0 auto; height: var(--y-status-h); display: flex; align-items: center; gap: var(--y-s4);
  padding: 0 var(--y-s4); background: var(--y-surface-3); border-top: 1px solid var(--y-border);
  font-size: var(--y-fs-xs); color: var(--y-ink-soft);
}
.y-status .y-spacer { flex: 1; }
.y-pill { display: inline-flex; align-items: center; gap: 5px; padding: 1px 8px; border-radius: 999px; background: var(--y-surface); border: 1px solid var(--y-border); white-space: nowrap; }
/* An empty status pill (no transient message) shouldn't show a bare chip. */
.y-status .y-pill:empty { display: none; }
.y-pill.y-stale { color: var(--y-stale); border-color: var(--y-stale-line); background: var(--y-stale-bg); }
/* Interactive status-bar pills (Flux toggle) get a clear hit affordance. */
.y-status button.y-pill { font: inherit; font-size: var(--y-fs-xs); }

/* Assertions / invariants badge in the status bar. Always visible when ≥1 rule
   is pinned; colour encodes the worst current state, click opens the panel. */
.y-assert-badge { cursor: pointer; gap: 4px; font-weight: 600; }
.y-assert-badge-ok   { color: var(--y-ok);    border-color: var(--y-ok); }
.y-assert-badge-warn { color: var(--y-warn);  border-color: var(--y-warn); }
.y-assert-badge-grey { color: var(--y-muted, #888); border-color: var(--y-border); }
.y-assert-badge-fail {
  color: #fff; background: var(--y-error); border-color: var(--y-error);
  /* a subtle pulse so a broken invariant flashes for attention */
  animation: y-assert-pulse 1.4s ease-in-out infinite;
}
@keyframes y-assert-pulse { 0%,100% { opacity: 1; } 50% { opacity: .62; } }

/* Per-row status glyph colours inside the assertions panel. */
.y-assert-pass { color: var(--y-ok); }
.y-assert-fail { color: var(--y-error); }
.y-assert-err  { color: var(--y-muted, #888); }
/* Click-to-jump cell chips in an assertion row. */
.y-chip { border: 1px solid var(--y-border); background: var(--y-surface); border-radius: 999px; cursor: pointer; color: var(--y-ink, inherit); }
.y-chip:hover { border-color: var(--y-accent, #1668e3); color: var(--y-accent, #1668e3); }

/* ====================== Modal (Y editor / DS add) ======================= */
.y-modal-scrim {
  position: fixed; inset: 0; background: var(--y-scrim); display: grid; place-items: center; z-index: 100;
  animation: y-scrim-in .14s ease both;
  /* soften the backdrop so the dialog floats above a blurred page */
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
}
@keyframes y-scrim-in { from { opacity: 0; } to { opacity: 1; } }
.y-modal {
  width: min(560px, 92vw); background: var(--y-surface);
  border-radius: var(--y-r-xl); box-shadow: var(--y-shadow-3);
  border: 1px solid var(--y-border-soft, var(--y-border)); overflow: hidden;
  /* a subtle rise-in so the dialog feels presented, not popped */
  animation: y-modal-in .18s cubic-bezier(.22,.68,.32,1.1) both;
}
@keyframes y-modal-in {
  from { opacity: 0; transform: translateY(8px) scale(.985); }
  to   { opacity: 1; transform: none; }
}
.y-modal-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--y-s3) var(--y-s4); border-bottom: 1px solid var(--y-border);
  background: linear-gradient(180deg, var(--y-aihead-from), var(--y-aihead-to));
}
.y-modal-title { font-size: var(--y-fs-lg); font-weight: 600; }
.y-modal-body { padding: var(--y-s4); display: flex; flex-direction: column; gap: var(--y-s3); max-height: 70vh; overflow: auto; }
.y-modal-foot { display: flex; justify-content: flex-end; gap: var(--y-s2); padding: var(--y-s3) var(--y-s4); border-top: 1px solid var(--y-border); background: var(--y-surface-2); }

/* In-app HTML-doc overlay (privacy policy etc.): a large near-fullscreen modal
   whose body is an <iframe> serving a local /assets page. */
.y-webdoc { width: min(880px, 96vw); height: min(88vh, 1000px); display: flex; flex-direction: column; }
.y-webdoc-head-actions { display: flex; gap: var(--y-s2); align-items: center; }
.y-webdoc-frame { flex: 1 1 auto; width: 100%; border: 0; background: #fff; }

/* ===================== ⌘K command palette ============================== */
/* Notion / Linear / Raycast-style "type to do anything" overlay. Tokens only,
   so it follows light + dark + every accent. Sits above modals (z-index 110). */
.y-cmdk-scrim {
  position: fixed; inset: 0; z-index: 110; background: var(--y-scrim);
  display: flex; justify-content: center; align-items: flex-start;
  padding-top: 14vh;
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
  animation: y-scrim-in .12s ease both;
}
.y-cmdk {
  width: min(560px, 92vw); max-height: 64vh; display: flex; flex-direction: column;
  background: var(--y-surface); border: 1px solid var(--y-border-soft, var(--y-border));
  border-radius: var(--y-r-xl); box-shadow: var(--y-shadow-3); overflow: hidden;
  animation: y-modal-in .18s cubic-bezier(.22,.68,.32,1.1) both;
}
/* search row */
.y-cmdk-search {
  display: flex; align-items: center; gap: var(--y-s2);
  padding: var(--y-s3) var(--y-s4); border-bottom: 1px solid var(--y-border);
}
.y-cmdk-glyph { color: var(--y-ink-soft); font-size: var(--y-fs-lg); flex: 0 0 auto; }
.y-cmdk-input {
  flex: 1 1 auto; border: 0; outline: none; background: transparent;
  font: inherit; font-size: var(--y-fs-lg); color: var(--y-ink);
  padding: 2px 0;
}
.y-cmdk-input::placeholder { color: var(--y-ink-soft); opacity: .8; }
.y-cmdk-count { flex: 0 0 auto; font-size: var(--y-fs-xs); color: var(--y-ink-soft); white-space: nowrap; }
/* results */
.y-cmdk-list { flex: 1 1 auto; overflow-y: auto; padding: var(--y-s2) var(--y-s2) var(--y-s2); }
.y-cmdk-group {
  font-size: var(--y-fs-xs); font-weight: 600; letter-spacing: .03em;
  text-transform: uppercase; color: var(--y-ink-soft);
  padding: var(--y-s2) var(--y-s2) 4px; margin-top: 2px;
}
.y-cmdk-item {
  display: flex; align-items: center; gap: var(--y-s3); width: 100%;
  appearance: none; border: 0; background: transparent; cursor: pointer;
  text-align: left; font: inherit; font-size: var(--y-fs-md); color: var(--y-ink);
  padding: 8px 10px; border-radius: var(--y-r-md);
}
.y-cmdk-item:hover { background: var(--y-hover-veil); }
.y-cmdk-item.is-active { background: var(--y-accent-soft); color: var(--y-ink); }
.y-cmdk-label { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.y-cmdk-kbd {
  flex: 0 0 auto; font-family: inherit; font-size: var(--y-fs-xs); color: var(--y-ink-soft);
  background: var(--y-surface-2); border: 1px solid var(--y-border);
  border-bottom-width: 2px; border-radius: 5px; padding: 1px 6px; line-height: 1.5;
}
.y-cmdk-empty { padding: var(--y-s5) var(--y-s4); text-align: center; color: var(--y-ink-soft); font-size: var(--y-fs-md); }
/* footer hint */
.y-cmdk-foot {
  flex: 0 0 auto; display: flex; align-items: center; gap: var(--y-s2);
  padding: var(--y-s2) var(--y-s4); border-top: 1px solid var(--y-border);
  background: var(--y-surface-2);
}
.y-cmdk-hint { display: inline-flex; align-items: center; gap: 5px; font-size: var(--y-fs-xs); color: var(--y-ink-soft); }
/* on a phone the palette is full-width near the top */
@media (max-width: 560px) {
  .y-cmdk-scrim { padding-top: 6vh; align-items: stretch; }
  .y-cmdk { width: 94vw; max-height: 80vh; }
}

.y-field { display: flex; flex-direction: column; gap: 3px; }
.y-field-row { display: flex; gap: var(--y-s3); }
.y-field-row > .y-field { flex: 1; }
.y-seg { display: inline-flex; border: 1px solid var(--y-border); border-radius: var(--y-r-sm); overflow: hidden; }
.y-seg button {
  border: 0; background: var(--y-surface); color: var(--y-ink-soft);
  padding: 5px 12px; cursor: pointer; font: inherit; font-size: var(--y-fs-sm);
  transition: background .1s ease, color .1s ease;
}
.y-seg button + button { border-left: 1px solid var(--y-border); }
.y-seg button:hover:not(.is-active) { background: var(--y-surface-2); color: var(--y-ink); }
.y-seg button.is-active { background: var(--y-accent); color: var(--y-accent-ink); }

/* ====================== Add-source WIZARD =============================== */
/* Fixed dialog size: width AND height stay constant across kinds. Only the
   body scrolls internally when a kind has many fields. This is the whole
   point — the window must never resize per data-source type. */
.y-wizard { width: 760px; max-width: 94vw; height: 580px; max-height: 90vh; display: flex; flex-direction: column; }
.y-wizard .y-modal-head { flex: 0 0 auto; }
/* A calm, uncramped footer: a touch more breathing room and a soft top hairline
   on a clean (non-gray) surface so the action row reads as Notion-light. */
.y-wizard .y-modal-foot {
  flex: 0 0 auto; align-items: center; gap: var(--y-s2);
  padding: var(--y-s3) var(--y-s4); background: var(--y-surface);
}
/* Body fills the remaining height and scrolls; override the modal's max-height
   cap so the box height is driven purely by the fixed dialog dimensions. */
.y-wizard .y-wiz-body { flex: 1 1 auto; min-height: 0; max-height: none; }

/* Tabbed wizard surfaces (Setup, Extensions): the `.y-seg` tab strip must stay
   fully visible at the top and never be squeezed/cropped by the scrolling body
   below it. Before this, the AI/Modules tab strip could be clipped at the bottom
   of the flex column. Lay the body out as: a non-shrinking tab strip + a single
   scrolling region underneath. */
.y-wizard .y-wiz-body > .y-seg {
  flex: 0 0 auto; align-self: flex-start;
  margin-bottom: var(--y-s3); flex-wrap: wrap;
}
/* When the wizard body hosts an embedded surface that brings its OWN head/body/
   foot (the AI config body in the Setup/Settings "Agent IA" pane), let that inner
   trio drive the height: head + foot pinned, only the inner body scrolls. This is
   what keeps the Test/Save footer from being pushed off the bottom. */
.y-wizard .y-wiz-body > .y-modal-head,
.y-settings-aiwrap > .y-modal-head { flex: 0 0 auto; }
.y-wizard .y-wiz-body > .y-modal-foot,
.y-settings-aiwrap > .y-modal-foot { flex: 0 0 auto; }

/* ====================== Full-screen SETTINGS panel ====================== */
/* A real app-style Settings surface: large dialog, fixed size, a left section
   nav + a scrolling content pane. Replaces the cramped "Options" ribbon tab. */
.y-settings-modal {
  width: min(1080px, 96vw); max-width: 96vw; height: min(760px, 94vh); max-height: 94vh;
  display: flex; flex-direction: column;
}
/* Clean, calm chrome — no gray header gradient / gray footer; just hairlines and
   a slightly larger title, so Settings reads as a real surface (Notion-style). */
.y-settings-modal .y-modal-head {
  flex: 0 0 auto; background: none;
  padding: var(--y-s4) var(--y-s5);
}
.y-settings-modal .y-modal-title { font-size: var(--y-fs-xl); font-weight: 650; letter-spacing: -.01em; }
.y-settings-modal .y-modal-foot { flex: 0 0 auto; background: none; padding: var(--y-s3) var(--y-s5); }
.y-settings-shell {
  flex: 1 1 auto; min-height: 0; display: flex; align-items: stretch;
}
/* Left section nav. */
.y-settings-nav {
  flex: 0 0 232px; min-width: 232px;
  display: flex; flex-direction: column; gap: 2px;
  padding: var(--y-s3); overflow-y: auto;
  border-right: 1px solid var(--y-border); background: var(--y-surface-2);
}
.y-settings-navitem {
  display: flex; align-items: center; gap: 10px;
  width: 100%; text-align: left; padding: 9px 11px;
  border: 0; background: transparent; border-radius: var(--y-r-md);
  color: var(--y-ink-soft); font: inherit; font-size: var(--y-fs-md);
  cursor: pointer; transition: background .1s ease, color .1s ease;
}
.y-settings-navitem:hover { background: var(--y-hover-veil); color: var(--y-ink); }
.y-settings-navitem.is-active {
  background: var(--y-accent-soft); color: var(--y-accent); font-weight: 600;
}
.y-settings-navitem:focus-visible {
  outline: none; box-shadow: 0 0 0 3px var(--y-accent-ring);
}
.y-settings-navicon { width: 1.2em; text-align: center; opacity: .9; }
/* Content pane (scrolls) — generous padding + a readable measure so the panes
   don't sprawl edge-to-edge on a wide surface. */
.y-settings-content {
  flex: 1 1 auto; min-width: 0; min-height: 0;
  overflow-y: auto; padding: var(--y-s5) 40px;
  display: flex; flex-direction: column;
}
.y-settings-content > * { max-width: 680px; width: 100%; }
/* The AI config body lives inside the content pane: give it its own scroll so its
   pinned Test/Save footer stays visible (mirrors the wizard fix). */
.y-settings-aiwrap {
  flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column;
}
.y-settings-aiwrap > .y-modal-head { padding-left: 0; padding-right: 0; background: none; border: 0; }
.y-settings-aiwrap > .y-modal-body { padding-left: 0; padding-right: 0; }
.y-settings-aiwrap > .y-modal-foot { background: none; padding-left: 0; padding-right: 0; }
/* A titled block within a pane. */
.y-settings-block { margin-bottom: 34px; }
.y-settings-block:last-child { margin-bottom: 0; }
.y-settings-h {
  font-size: var(--y-fs-lg); font-weight: 650; margin: 0 0 5px;
  color: var(--y-ink); letter-spacing: -.01em;
}
.y-settings-hint { font-size: var(--y-fs-sm); color: var(--y-ink-faint); margin: 0 0 14px; line-height: 1.5; }
.y-settings-wrap { display: flex; flex-wrap: wrap; gap: var(--y-s2); align-items: center; }

/* Responsive: stack the nav above the content on a narrow viewport. */
@media (max-width: 720px) {
  .y-settings-modal { width: 96vw; height: 90vh; max-height: 90vh; }
  .y-settings-shell { flex-direction: column; }
  .y-settings-nav {
    flex: 0 0 auto; min-width: 0; width: 100%;
    flex-direction: row; flex-wrap: nowrap; overflow-x: auto;
    border-right: 0; border-bottom: 1px solid var(--y-border);
  }
  .y-settings-navitem { white-space: nowrap; }
}

/* Configure-AI: the post-save confirmation note (esp. the Ollama installed/
   not-installed state). A quiet card with a left accent bar per state. */
.y-save-note {
  margin-top: 10px; padding: 8px 10px; border-radius: var(--y-r-md);
  font-size: var(--y-fs-sm); border: 1px solid var(--y-border);
}
.y-save-note-ok   { background: var(--y-accent-soft); border-color: var(--y-accent-ring, var(--y-border)); }
.y-save-note-warn { background: var(--y-surface-2); }

/* Import manager: the pick/drop zone (a big clickable dashed target). */
.y-import-drop { border: 2px dashed var(--y-border); border-radius: var(--y-r-md); padding: var(--y-s4); text-align: center; cursor: pointer; background: var(--y-surface-2); transition: border-color 0.12s ease, background 0.12s ease; }
.y-import-drop:hover { border-color: var(--y-accent); background: var(--y-accent-soft); }
.y-import-drop:focus-visible { outline: none; border-color: var(--y-accent); box-shadow: 0 0 0 3px var(--y-accent-ring); }
.y-import-drop-icon { font-size: 22px; line-height: 1; margin-bottom: 4px; opacity: .75; }
.y-import-drop-hint { color: var(--y-ink-faint); font-size: var(--y-fs-sm); }
.y-import-drop-file { margin-top: 6px; font-size: var(--y-fs-sm); font-weight: 600; color: var(--y-ink); word-break: break-all; }

/* Import manager: the "added ✓" success row under the add button. */
.y-import-done { display: flex; align-items: flex-start; gap: 8px; margin-top: 8px; font-size: var(--y-fs-xs); line-height: 1.4; color: var(--y-ok); }
.y-import-done-mark { flex: 0 0 auto; font-weight: 700; }

/* A small inline spinner for in-flight async states (loading rows). */
.y-spinner {
  display: inline-block; width: 12px; height: 12px; vertical-align: -1px;
  border: 2px solid var(--y-border); border-top-color: var(--y-accent);
  border-radius: 50%; animation: y-spin 0.7s linear infinite;
}
@keyframes y-spin { to { transform: rotate(360deg); } }

/* Inline "waiting" row: a spinner + a hint, used by the GoCardless consent poll. */
.y-wait-row { display: flex; align-items: center; gap: 8px; margin-top: 8px; }

/* File-group dropdowns: Save split-button (main + caret) + Export/Share menus. */
.y-split { position: relative; display: inline-flex; }
.y-split-main { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.y-split-caret { padding: 0 5px; border-top-left-radius: 0; border-bottom-left-radius: 0; margin-left: -1px; }
.y-menu-wrap { position: relative; display: inline-flex; }
.y-menu-backdrop { position: fixed; inset: 0; z-index: 60; }
.y-menu {
  position: absolute; top: calc(100% + 4px); left: 0; z-index: 61;
  /* Stable width: a dropdown's contents change with context (conditional items
     by read-only / share state), and a content-sized menu visibly jumps width as
     items appear/disappear. Pin a fixed width so the menu stays put. Long labels
     wrap or ellipsize via the items rather than widening the menu. */
  width: 232px; padding: 4px;
  background: var(--y-surface); border: 1px solid var(--y-border);
  border-radius: 10px; box-shadow: var(--y-shadow-3);
}
.y-menu-item { overflow: hidden; text-overflow: ellipsis; }
.y-menu-right { left: auto; right: 0; }
.y-menu-item {
  display: block; width: 100%; text-align: left; padding: 7px 10px;
  border: 0; background: transparent; border-radius: 6px; cursor: pointer;
  color: var(--y-ink); font-size: var(--y-fs-sm); white-space: nowrap;
}
.y-menu-item:hover { background: var(--y-hover-veil); }

/* Report builder: the "+ Block" add bar buttons (quiet, secondary). */
.y-report-addbtn { background: var(--y-surface); border: 1px solid var(--y-border); color: var(--y-ink-soft); }
.y-report-addbtn:hover { border-color: var(--y-accent); color: var(--y-accent); background: var(--y-accent-soft); }

/* Sharing: public-key (safe) vs private-key (secret) emphasis boxes. */
.y-copyfield { margin-bottom: 4px; }
.y-copyfield-safe, .y-copyfield-secret {
  border-radius: var(--y-r-md); padding: var(--y-s2) var(--y-s3);
  border: 1px solid var(--y-border);
}
.y-copyfield-safe { border-color: var(--y-ok); background: var(--y-accent-soft); }
.y-copyfield-secret { border-color: var(--y-danger-line); background: var(--y-danger-soft); }
.y-copyfield-note { display: block; font-size: var(--y-fs-xs); line-height: 1.4; margin: 0 0 12px; padding: 0 2px; }
.y-copyfield-note-safe { color: var(--y-ok); }
.y-copyfield-note-secret { color: var(--y-error); font-weight: 600; }

/* Template gallery + wizard */
.y-tpl-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: var(--y-s3); margin-top: var(--y-s3); }
.y-tpl-card {
  display: flex; flex-direction: column; gap: var(--y-s2); padding: var(--y-s3);
  border: 1px solid var(--y-border); border-radius: var(--y-r-md); background: var(--y-surface);
  transition: border-color .12s ease, box-shadow .12s ease, transform .12s ease;
}
.y-tpl-card:hover { border-color: var(--y-border-strong); box-shadow: var(--y-shadow-1); transform: translateY(-1px); }
.y-tpl-card-top { display: flex; align-items: center; justify-content: space-between; gap: var(--y-s2); }
.y-tpl-cat { font-size: var(--y-fs-xs); color: var(--y-ink-faint); text-transform: uppercase; letter-spacing: 0.04em; }
.y-tpl-badge { font-size: var(--y-fs-xs); padding: 1px 8px; border-radius: 999px; font-weight: 600; }
.y-tpl-badge.is-free { color: var(--y-accent); background: var(--y-accent-soft); }
.y-tpl-badge.is-paid {
  color: color-mix(in srgb, var(--y-warn) 78%, #000);
  background: var(--y-stale-bg); border: 1px solid var(--y-stale-line);
}
:root[data-theme="dark"] .y-tpl-badge.is-paid { color: var(--y-warn); }
.y-tpl-name { font-weight: 600; }
.y-tpl-desc { font-size: var(--y-fs-xs); line-height: 1.4; flex: 1 1 auto; }
.y-tpl-card-foot { display: flex; justify-content: flex-end; }
.y-tpl-err { color: var(--y-error); font-size: var(--y-fs-xs); }
.y-tpl-section { margin-top: var(--y-s3); }
.y-tpl-section-head { margin: var(--y-s3) 0 0 0; font-size: var(--y-fs-sm, 13px); font-weight: 700; color: var(--y-ink); border-bottom: 1px solid var(--y-border); padding-bottom: 4px; }

.y-wiz-steps { display: flex; align-items: center; gap: var(--y-s2); font-size: var(--y-fs-xs); color: var(--y-ink-faint); }
.y-wiz-step { padding: 2px 8px; border-radius: 999px; border: 1px solid transparent; }
.y-wiz-step.is-active { color: var(--y-accent); border-color: var(--y-accent); background: var(--y-accent-soft); font-weight: 600; }
.y-wiz-sep { color: var(--y-ink-faint); }

/* Step 1 — type cards grid (Notion-style clean cards, responsive). */
.y-wiz-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: var(--y-s3); }
.y-wiz-card {
  display: flex; flex-direction: column; gap: 6px; text-align: left; cursor: pointer;
  padding: var(--y-s3) var(--y-s4); border: 1px solid var(--y-border); border-radius: var(--y-r-lg);
  background: var(--y-surface); color: var(--y-ink); font: inherit;
  box-shadow: var(--y-shadow-1);
  transition: border-color .12s ease, background .12s ease, box-shadow .12s ease, transform .12s ease;
}
.y-wiz-card:hover {
  border-color: var(--y-accent); background: var(--y-accent-soft);
  box-shadow: var(--y-shadow-2); transform: translateY(-1px);
}
.y-wiz-card:focus-visible { outline: none; border-color: var(--y-accent); box-shadow: 0 0 0 3px var(--y-accent-ring); }
/* Selected resource card in the MCP-resource picker. */
.y-wiz-card.is-active { border-color: var(--y-accent); background: var(--y-accent-soft); box-shadow: 0 0 0 1px var(--y-accent) inset; }
/* The MCP resource list scrolls (a server may expose ~100 resources). */
.y-mcpres-list { max-height: 320px; overflow-y: auto; padding-right: 2px; margin-top: var(--y-s3); }
.y-wiz-card-head { display: flex; align-items: center; gap: var(--y-s2); }
/* The card's leading glyph becomes a soft icon badge. */
.y-wiz-card-head .y-ds-badge {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; font-size: 13px; margin-right: 0;
  background: var(--y-surface-2); border: 1px solid var(--y-border);
  border-radius: var(--y-r-md);
}
.y-wiz-card:hover .y-ds-badge { background: var(--y-surface); border-color: var(--y-accent); }
.y-wiz-card-name { font-weight: 600; font-size: var(--y-fs-md); }
.y-wiz-card-desc { font-size: var(--y-fs-xs); color: var(--y-ink-soft); line-height: 1.4; }
.y-live-badge {
  margin-left: auto; flex: 0 0 auto; white-space: nowrap;
  font-size: 9px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--y-ok); border: 1px solid var(--y-ok); border-radius: 999px; padding: 1px 6px;
}
/* "key required" badge on community cards that need an API key. */
.y-key-badge {
  flex: 0 0 auto; white-space: nowrap;
  font-size: 9px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--y-ink-faint); border: 1px solid var(--y-border-strong); border-radius: 999px; padding: 1px 6px;
}

/* ---- External MCP servers (Configure-AI → "MCP servers" section) -----------
   A separated section with a server list (status dot + name + transport badge +
   meta + toggle + remove) and the add-form below. Built on --y-* tokens to match
   the provider/local panels. */
.y-mcp-panel { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--y-border); }
.y-mcp-row {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 6px 0; border-bottom: 1px solid var(--y-border);
}
.y-mcp-dot {
  flex: 0 0 auto; width: 8px; height: 8px; border-radius: 999px;
  background: var(--y-ok, #2e7d32);
}
.y-mcp-dot.is-off { background: var(--y-ink-faint, #999); }
.y-mcp-dot:not(.is-on):not(.is-off) { background: var(--y-warn, #b26a00); }
.y-mcp-name { font-weight: 600; font-size: var(--y-fs-md); }
.y-mcp-meta { font-size: var(--y-fs-xs); color: var(--y-ink-soft); margin-left: auto; }
.y-mcp-toggle { flex: 0 0 auto; display: inline-flex; align-items: center; cursor: pointer; }
/* Let a long source name shrink/ellipsize so the badge stays on one line. */
.y-wiz-card-head .y-wiz-card-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.y-wiz-card-head .y-live-badge + .y-key-badge { margin-left: 6px; }

/* ---- Step 1 — browsable two-pane KIND PICKER --------------------------------
   A left category sidebar (counted, in catalog order, + an "All" total) and a
   right pane with a live search box over a responsive grid of logo-badge cards.
   The pane is laid out to FILL the fixed wizard body; only the right pane (and
   the sidebar, if tall) scrolls — the search stays pinned. Built on --y-* tokens;
   per-category color comes from a calm palette (see `.y-cat-*` below). */
.y-picker {
  display: grid; grid-template-columns: 196px 1fr;
  gap: var(--y-s4); height: 100%; min-height: 0;
}
.y-picker-side {
  display: flex; flex-direction: column; gap: 2px;
  overflow-y: auto; min-height: 0;
  padding-right: var(--y-s2);
  border-right: 1px solid var(--y-border);
}
.y-cat-item {
  display: flex; align-items: center; gap: var(--y-s2);
  width: 100%; text-align: left; cursor: pointer; font: inherit;
  padding: 6px var(--y-s2); border: 1px solid transparent; border-radius: var(--y-r-md);
  background: transparent; color: var(--y-ink-soft);
  transition: background .12s ease, color .12s ease;
}
.y-cat-item:hover { background: var(--y-hover-veil); color: var(--y-ink); }
.y-cat-item.is-active { background: var(--y-accent-soft); color: var(--y-ink); font-weight: 600; }
.y-cat-item:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--y-accent-ring); }
.y-cat-item-name {
  flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: var(--y-fs-sm);
}
.y-cat-count {
  flex: 0 0 auto; font-size: 10px; font-weight: 700; color: var(--y-ink-faint);
  background: var(--y-surface-2); border-radius: 999px; padding: 1px 7px; min-width: 16px; text-align: center;
}
.y-cat-item.is-active .y-cat-count { color: var(--y-accent); background: var(--y-surface); }
/* The small color dot that ties a sidebar row to its category hue. */
.y-cat-dot { flex: 0 0 auto; width: 8px; height: 8px; border-radius: 999px; background: var(--y-cat); }

.y-picker-main {
  display: flex; flex-direction: column; gap: var(--y-s3);
  min-height: 0; min-width: 0;
}
.y-picker-search { flex: 0 0 auto; }
.y-picker-main > .y-wiz-cards,
.y-picker-main > .y-empty { overflow-y: auto; min-height: 0; padding-right: 2px; }

/* Logo-like colored badge: keeps the descriptor's 2-letter `icon` but renders it
   as a soft, deliberate tinted tile (the modern stand-in for per-vendor SVGs). */
.y-wiz-card-head .y-cat-badge {
  background: var(--y-cat-soft); border-color: var(--y-cat-line);
  color: var(--y-cat-ink); font-weight: 700;
}
.y-wiz-card:hover .y-cat-badge { background: var(--y-cat-soft); border-color: var(--y-cat); }

/* ---- Calm per-category palette ---------------------------------------------
   Each class only sets three vars (soft fill / line / ink) consumed by the badge
   and a base hue for the sidebar dot. Soft, Notion/Linear-leaning — never garish.
   Tints are mixed against white so they stay light; the ink stays legible. */
.y-cat-dot.y-cat-indigo { --y-cat: #6366f1; } .y-cat-badge.y-cat-indigo  { --y-cat: #6366f1; --y-cat-soft: #eef0fe; --y-cat-line: #d7dbfb; --y-cat-ink: #4f46c4; }
.y-cat-dot.y-cat-blue   { --y-cat: #2383e2; } .y-cat-badge.y-cat-blue    { --y-cat: #2383e2; --y-cat-soft: #e8f1fb; --y-cat-line: #cfe2f7; --y-cat-ink: #1a6fc4; }
.y-cat-dot.y-cat-cyan   { --y-cat: #0e9bb5; } .y-cat-badge.y-cat-cyan    { --y-cat: #0e9bb5; --y-cat-soft: #e4f5f8; --y-cat-line: #c4e9ef; --y-cat-ink: #0b7a8f; }
.y-cat-dot.y-cat-violet { --y-cat: #8b5cf6; } .y-cat-badge.y-cat-violet  { --y-cat: #8b5cf6; --y-cat-soft: #f2ecfe; --y-cat-line: #e2d4fb; --y-cat-ink: #6d3fce; }
.y-cat-dot.y-cat-teal   { --y-cat: #0ea58f; } .y-cat-badge.y-cat-teal   { --y-cat: #0ea58f; --y-cat-soft: #e3f6f1; --y-cat-line: #c2eae0; --y-cat-ink: #0b8473; }
.y-cat-dot.y-cat-green  { --y-cat: #2c8c5a; } .y-cat-badge.y-cat-green   { --y-cat: #2c8c5a; --y-cat-soft: #e6f4ec; --y-cat-line: #c8e6d4; --y-cat-ink: #237049; }
.y-cat-dot.y-cat-emerald{ --y-cat: #10996b; } .y-cat-badge.y-cat-emerald { --y-cat: #10996b; --y-cat-soft: #e4f5ee; --y-cat-line: #c3e9d8; --y-cat-ink: #0c7a55; }
.y-cat-dot.y-cat-amber  { --y-cat: #b7791f; } .y-cat-badge.y-cat-amber   { --y-cat: #b7791f; --y-cat-soft: #fbf2e0; --y-cat-line: #f0dfb6; --y-cat-ink: #8f5e15; }
.y-cat-dot.y-cat-slate  { --y-cat: #6b7280; } .y-cat-badge.y-cat-slate   { --y-cat: #6b7280; --y-cat-soft: #f0f1f3; --y-cat-line: #dcdee2; --y-cat-ink: #565c66; }
.y-cat-dot.y-cat-rose   { --y-cat: #e0566f; } .y-cat-badge.y-cat-rose    { --y-cat: #e0566f; --y-cat-soft: #fdebef; --y-cat-line: #f6ccd5; --y-cat-ink: #c23a53; }
.y-cat-dot.y-cat-orange { --y-cat: #ea7a3c; } .y-cat-badge.y-cat-orange  { --y-cat: #ea7a3c; --y-cat-soft: #fdefe4; --y-cat-line: #f6d6bf; --y-cat-ink: #c25e26; }
.y-cat-dot.y-cat-pink   { --y-cat: #d6549e; } .y-cat-badge.y-cat-pink    { --y-cat: #d6549e; --y-cat-soft: #fceaf4; --y-cat-line: #f4cbe3; --y-cat-ink: #b53b83; }
.y-cat-dot.y-cat-sky    { --y-cat: #3b9fe0; } .y-cat-badge.y-cat-sky     { --y-cat: #3b9fe0; --y-cat-soft: #e8f3fb; --y-cat-line: #cce5f6; --y-cat-ink: #2a7fbb; }

/* Catalogue gallery cards: like the wizard cards but non-clickable containers
   with their own "Ajouter" action at the bottom. */
.y-gallery { display: grid; grid-template-columns: 1fr 1fr; gap: var(--y-s3); }
.y-gallery-card {
  display: flex; flex-direction: column; gap: 6px;
  padding: var(--y-s3); border: 1px solid var(--y-border); border-radius: var(--y-r-md);
  background: var(--y-surface-2);
  transition: border-color .12s ease, box-shadow .12s ease, transform .12s ease;
}
.y-gallery-card:hover { border-color: var(--y-border-strong); box-shadow: var(--y-shadow-1); transform: translateY(-1px); }
/* Calm the gallery: the per-card add is a quiet outline-accent button, not a
   wall of solid blue across every card. */
.y-gallery-add {
  margin-top: auto; align-self: flex-start;
  background: transparent; color: var(--y-accent);
  border: 1px solid var(--y-accent);
}
.y-gallery-add:hover:not(:disabled) { background: var(--y-accent-soft); }

/* Community catalogue: section + per-category headers. */
.y-wiz-section-title {
  font-size: var(--y-fs-xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--y-ink-faint); margin: 14px 0 8px; padding-bottom: 4px; border-bottom: 1px solid var(--y-border);
}
.y-wiz-section-title:first-of-type { margin-top: 0; }
.y-wiz-cat { margin-bottom: 12px; }
.y-wiz-cat-title { font-size: var(--y-fs-xs); font-weight: 600; color: var(--y-ink-soft); margin-bottom: 6px; }
.y-mono-inline { font-family: var(--y-mono); background: var(--y-surface-2); padding: 1px 5px; border-radius: var(--y-r-sm); }

/* ---- Step 2 — Notion-style descriptor form -----------------------------
   A breathable, soft-surface form: a card-style banner identifying the chosen
   source, fields grouped under quiet section labels (Connexion / Authentif.),
   comfortable full-width inputs that lift on focus, and a calm helper line
   under each input. Built entirely on the existing --y-* tokens. */
.y-wiz-form { display: flex; flex-direction: column; gap: var(--y-s4); }

/* Header banner: large icon badge + name + one-line description. */
.y-wiz-form-banner {
  display: flex; align-items: center; gap: var(--y-s3);
  padding: var(--y-s3) var(--y-s4);
  background: var(--y-surface-2); border: 1px solid var(--y-border);
  border-radius: var(--y-r-lg);
}
.y-wiz-form-banner-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.y-wiz-form-banner-name { font-size: var(--y-fs-lg); font-weight: 600; color: var(--y-ink); }
.y-wiz-form-banner-desc { font-size: var(--y-fs-sm); color: var(--y-ink-soft); line-height: 1.4; }
.y-wiz-form-banner .y-live-badge { margin-left: auto; align-self: flex-start; }
/* A bigger, calmer badge for the banner (the inline list one is tiny). */
.y-ds-badge-lg {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; font-size: 16px; margin-right: 0;
  background: var(--y-surface); border: 1px solid var(--y-border);
  border-radius: var(--y-r-md); box-shadow: var(--y-shadow-1);
}

/* A field group under one quiet section label, with generous internal rhythm. */
.y-wiz-form-section { display: flex; flex-direction: column; gap: var(--y-s3); }
.y-wiz-section-label {
  font-size: var(--y-fs-xs); font-weight: 700; letter-spacing: 0.05em;
  text-transform: uppercase; color: var(--y-ink-faint);
  padding-bottom: var(--y-s1); border-bottom: 1px solid var(--y-border);
}

/* Comfortable, full-width fields with a quiet helper line. */
.y-wiz-form .y-field { gap: var(--y-s1); }
.y-wiz-form .y-field > .y-label { font-weight: 600; color: var(--y-ink); margin-bottom: 0; }
.y-wiz-form .y-input,
.y-wiz-form .y-select,
.y-wiz-form .y-textarea { width: 100%; padding: 8px 10px; border-radius: var(--y-r-md); }
.y-wiz-form .y-input:focus,
.y-wiz-form .y-select:focus,
.y-wiz-form .y-textarea:focus { box-shadow: 0 0 0 3px var(--y-accent-ring); }
/* Quiet helper text under an input (label/help line). */
.y-field-help { font-size: var(--y-fs-xs); color: var(--y-ink-faint); line-height: 1.4; }

/* Step 2 — Tester result line. */
.y-test-result { font-size: var(--y-fs-sm); padding: 6px 10px; border-radius: var(--y-r-sm); }
.y-test-ok { color: var(--y-ok); background: var(--y-accent-soft); border: 1px solid color-mix(in srgb, var(--y-ok) 35%, transparent); }
.y-test-err { color: var(--y-error); background: var(--y-danger-soft); border: 1px solid var(--y-danger-line); }

/* In-wizard sample preview (Aperçu): discovered paths + raw payload. */
.y-preview { margin-top: 8px; display: flex; flex-direction: column; gap: 6px; }
.y-preview-head { font-size: var(--y-fs-xs); }
.y-preview-paths { max-height: 160px; overflow: auto; margin: 0; }
.y-preview-raw {
  max-height: 200px; overflow: auto; margin: 0; padding: 8px;
  font-family: var(--y-font-mono, monospace); font-size: var(--y-fs-xs);
  background: var(--y-bg-elev, rgba(0,0,0,.04)); border-radius: var(--y-r-sm);
  white-space: pre; tab-size: 2;
}

/* ====================== Charts ========================================== */
.y-chart {
  position: absolute; z-index: 15; background: var(--y-surface);
  border: 1px solid var(--y-border-strong); border-radius: var(--y-r-md);
  box-shadow: var(--y-shadow-2); overflow: hidden; display: flex; flex-direction: column;
}
.y-chart-head { display: flex; align-items: center; gap: 8px; padding: 4px 8px; background: var(--y-surface-3); border-bottom: 1px solid var(--y-border); cursor: move; }
.y-chart-title { font-size: var(--y-fs-sm); font-weight: 600; flex: 1; }
.y-chart-svg { flex: 1; display: block; }
.y-chart-x { color: var(--y-ink-faint); }

.y-muted { color: var(--y-ink-faint); }
.y-empty { padding: var(--y-s5) var(--y-s4); text-align: center; color: var(--y-ink-faint); line-height: 1.5; }
/* Error variant of an empty/placeholder block: a calm danger card rather than
   bare red text floating in the layout. */
.y-empty.is-error {
  color: var(--y-error); background: var(--y-danger-soft);
  border: 1px solid var(--y-danger-line); border-radius: var(--y-r-md);
  padding: var(--y-s3) var(--y-s4); text-align: left;
}
.y-scroll-thin::-webkit-scrollbar { width: 10px; height: 10px; }
.y-scroll-thin::-webkit-scrollbar-thumb { background: var(--y-border-strong); border-radius: 999px; border: 2px solid var(--y-surface); }

/* App-wide quiet, theme-aware scrollbars on the scrolling chrome surfaces, so
   they read as part of the design rather than the OS default. Hidden until the
   surface is hovered/scrolled where supported, but always usable. */
.y-panel-body, .y-ai-body, .y-ai-thread, .y-modal-body, .y-home,
.y-report-preview, .y-report-editor, .y-filter-list, .y-autocomplete,
.y-ctx-menu, .y-menu, .y-onb-terms {
  scrollbar-width: thin;
  scrollbar-color: var(--y-border-strong) transparent;
}
.y-panel-body::-webkit-scrollbar, .y-ai-body::-webkit-scrollbar,
.y-ai-thread::-webkit-scrollbar, .y-modal-body::-webkit-scrollbar,
.y-home::-webkit-scrollbar, .y-report-preview::-webkit-scrollbar,
.y-report-editor::-webkit-scrollbar, .y-filter-list::-webkit-scrollbar,
.y-autocomplete::-webkit-scrollbar, .y-onb-terms::-webkit-scrollbar {
  width: 10px; height: 10px;
}
.y-panel-body::-webkit-scrollbar-thumb, .y-ai-body::-webkit-scrollbar-thumb,
.y-ai-thread::-webkit-scrollbar-thumb, .y-modal-body::-webkit-scrollbar-thumb,
.y-home::-webkit-scrollbar-thumb, .y-report-preview::-webkit-scrollbar-thumb,
.y-report-editor::-webkit-scrollbar-thumb, .y-filter-list::-webkit-scrollbar-thumb,
.y-autocomplete::-webkit-scrollbar-thumb, .y-onb-terms::-webkit-scrollbar-thumb {
  background: var(--y-border-strong); border-radius: 999px;
  border: 2px solid transparent; background-clip: padding-box;
}
.y-panel-body::-webkit-scrollbar-thumb:hover, .y-ai-body::-webkit-scrollbar-thumb:hover,
.y-ai-thread::-webkit-scrollbar-thumb:hover, .y-modal-body::-webkit-scrollbar-thumb:hover,
.y-home::-webkit-scrollbar-thumb:hover {
  background: var(--y-ink-faint);
}
.y-panel-body::-webkit-scrollbar-track, .y-ai-body::-webkit-scrollbar-track,
.y-ai-thread::-webkit-scrollbar-track, .y-modal-body::-webkit-scrollbar-track,
.y-home::-webkit-scrollbar-track { background: transparent; }

/* Shared read-only view: a thin banner under the title bar. */
.y-share-banner {
  padding: 6px var(--y-s4);
  background: var(--y-accent-soft);
  color: var(--y-accent);
  font-weight: 600;
  font-size: var(--y-fs-sm, 13px);
  text-align: center;
  border-bottom: 1px solid var(--y-accent-ring);
}

/* Read-only cloud EMBED viewer (app.rs embed mode): chrome-less, the grid fills
   the iframe; a single thin status line carries the loading / error states. */
.y-app.y-embed { height: 100vh; display: flex; flex-direction: column; }
.y-app.y-embed .y-center { flex: 1; min-height: 0; }
.y-embed-status {
  padding: 4px var(--y-s4);
  font-size: var(--y-fs-xs, 12px);
  border-top: 1px solid var(--y-border);
  background: var(--y-surface, #fff);
}

/* In-app self-update banner (components/update_banner.rs). Non-blocking strip
   under the title bar, styled like the share banner but with inline actions. */
.y-update-banner {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--y-s3);
  padding: 7px var(--y-s4);
  background: var(--y-surface-2);
  color: var(--y-ink-soft);
  font-weight: 500;
  font-size: var(--y-fs-sm, 13px);
  border-bottom: 1px solid var(--y-border);
}
.y-update-actions { display: inline-flex; gap: var(--y-s2); }
.y-update-banner button {
  font: inherit;
  font-weight: 500;
  cursor: pointer;
  border-radius: var(--y-r-sm);
  padding: 3px 11px;
  border: 1px solid var(--y-border);
  background: var(--y-surface);
  color: var(--y-ink);
}
.y-update-banner .y-update-go {
  background: var(--y-accent);
  color: var(--y-accent-ink);
  border-color: var(--y-accent);
}
.y-update-banner .y-update-later:hover,
.y-update-banner .y-update-go:hover { filter: brightness(1.05); }

/* Incoming access-request banner(s) — one row per pending request, styled like
   the update banner but with an accent (attention) left stripe. */
.y-access-reqs { display: flex; flex-direction: column; }
.y-access-req {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--y-s3);
  padding: 7px var(--y-s4);
  background: var(--y-surface-2);
  color: var(--y-ink-soft);
  font-weight: 500;
  font-size: var(--y-fs-sm, 13px);
  border-bottom: 1px solid var(--y-border);
  border-left: 3px solid var(--y-accent);
}
.y-access-req-msg strong { color: var(--y-ink); }
.y-access-req-actions { display: inline-flex; gap: var(--y-s2); }
.y-access-req button {
  font: inherit;
  font-weight: 500;
  cursor: pointer;
  border-radius: var(--y-r-sm);
  padding: 3px 11px;
  border: 1px solid var(--y-border);
  background: var(--y-surface);
  color: var(--y-ink);
}
.y-access-req .y-access-approve-editor {
  background: var(--y-accent);
  color: var(--y-accent-ink);
  border-color: var(--y-accent);
}
.y-access-req button:hover { filter: brightness(1.05); }
.y-update-link { color: var(--y-accent); font-weight: 600; text-decoration: underline; }

/* ============================================================
   Report builder (report_builder.rs) — two-pane modal + the
   rendered report preview, plus a print stylesheet for PDF export.
   ============================================================ */
.y-report-modal { width: min(1080px, 96vw); height: min(760px, 92vh); display: flex; flex-direction: column; }
.y-report-modal .y-modal-head, .y-report-modal .y-modal-foot { flex: 0 0 auto; }
.y-report-body { flex: 1 1 auto; flex-direction: row; gap: 0; padding: 0; overflow: hidden; max-height: none; }
.y-report-editor { flex: 0 0 42%; max-width: 460px; padding: var(--y-s4); overflow: auto; border-right: 1px solid var(--y-border); display: flex; flex-direction: column; gap: var(--y-s3); }
.y-report-blocklist { display: flex; flex-direction: column; gap: var(--y-s2); }
.y-report-block { border: 1px solid var(--y-border); border-radius: var(--y-r-md, 8px); padding: var(--y-s2) var(--y-s3); background: var(--y-surface-2); }
.y-report-block-bar { display: flex; align-items: center; justify-content: space-between; margin-bottom: 4px; }
.y-report-block-kind { font-size: var(--y-fs-xs); font-weight: 600; color: var(--y-ink-faint); text-transform: uppercase; letter-spacing: .04em; }
.y-report-block-ctrls { display: flex; gap: 2px; }
.y-report-addbar { display: flex; flex-wrap: wrap; gap: var(--y-s2); }
.y-report-preview-wrap { flex: 1 1 auto; display: flex; flex-direction: column; background: var(--y-surface-2); min-width: 0; }
.y-report-preview-head { flex: 0 0 auto; display: flex; align-items: center; justify-content: space-between; padding: var(--y-s2) var(--y-s4); border-bottom: 1px solid var(--y-border); }
.y-report-preview { flex: 1 1 auto; overflow: auto; padding: var(--y-s5); }

/* The rendered report itself (shared by the in-app preview and the standalone
   HTML export shell, which inlines an equivalent of these rules). */
.y-report { max-width: 820px; margin: 0 auto; background: #fff; color: #1a1a1a; padding: 48px 56px; box-shadow: 0 1px 4px rgba(0,0,0,.12); }
.y-report-title { font-size: 28px; margin: 0 0 24px; border-bottom: 2px solid #222; padding-bottom: 8px; }
.y-report h2 { font-size: 20px; margin: 24px 0 8px; }
.y-report h3 { font-size: 16px; margin: 18px 0 6px; }
.y-report p { line-height: 1.55; margin: 8px 0; }
.y-report-ref { font-weight: 600; }
.y-report .y-metric { display: inline-block; min-width: 160px; margin: 8px 12px 8px 0; padding: 14px 18px; border: 1px solid #e2e2e6; border-radius: 8px; background: #fafafa; vertical-align: top; }
.y-report .y-metric-label { font-size: 12px; text-transform: uppercase; letter-spacing: .04em; color: #666; }
.y-report .y-metric-value { font-size: 26px; font-weight: 700; margin-top: 4px; }
.y-report .y-metric-unit { font-size: 14px; font-weight: 500; color: #666; margin-left: 4px; }
.y-report-table { border-collapse: collapse; width: 100%; margin: 12px 0; font-size: 14px; }
.y-report-table th, .y-report-table td { border: 1px solid #d9d9de; padding: 6px 10px; text-align: left; }
.y-report-table th { background: #f0f0f2; font-weight: 600; }
.y-report-bad { color: #b00020; font-style: italic; margin: 8px 0; }
.y-page-break { break-after: page; page-break-after: always; height: 0; }

/* ===== Print / PDF preview (print_preview.rs) ===== */
.y-print-modal .y-report-editor { gap: var(--y-s2); }
.y-print-page { background: #fff; color: #1a1a1a; padding: 24px; box-shadow: 0 1px 4px rgba(0,0,0,.12); max-width: 900px; margin: 0 auto; }
.y-print-sheet { background: #fff; color: #1a1a1a; }
.y-print-table { border-collapse: collapse; width: 100%; table-layout: fixed; font-size: 12px; }
.y-print-table th, .y-print-table td { padding: 3px 6px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: top; }
.y-print-table thead th { background: #f0f0f2; font-weight: 600; text-align: left; }
.y-print-grid th, .y-print-grid td { border: 1px solid #c8c8cc; }
.y-print-table tr { break-inside: avoid; page-break-inside: avoid; }
.y-print-table thead { display: table-header-group; }
.y-print-header, .y-print-footer { display: flex; justify-content: space-between; font-size: 11px; color: #444; padding: 4px 0; gap: 8px; }
.y-print-header { border-bottom: 1px solid #ddd; margin-bottom: 6px; }
/* Page-setup options column: group eyebrows + consistent spacing (design system). */
.y-print-opts { display: flex; flex-direction: column; gap: var(--y-s2); }
.y-print-section {
  font-size: var(--y-fs-xs);
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--y-ink-faint);
  font-weight: 600;
  margin: var(--y-s3) 0 2px;
}
.y-print-opts .y-print-section:first-child { margin-top: 0; }
/* Printed row/column headings (A,B,C… / 1,2,3…) — Excel-like grey gutters. */
.y-print-rownum-col { width: 30px; }
.y-print-table th.y-print-corner,
.y-print-table th.y-print-colletter,
.y-print-table th.y-print-rownum {
  background: #f0f0f2;
  color: #555;
  font-weight: 600;
  font-size: 10px;
  text-align: center;
  border: 1px solid #d9d9de;
}
.y-print-table th.y-print-rownum { text-align: right; }
/* Center the printed block on the page (visible when it's narrower than the page). */
.y-print-center-h .y-print-table { width: auto; min-width: 40%; margin-left: auto; margin-right: auto; }
.y-print-center-v { display: flex; flex-direction: column; justify-content: center; min-height: 100%; }
.y-print-footer { border-top: 1px solid #ddd; margin-top: 6px; }
.y-print-hf-c { text-align: center; flex: 1; }
.y-print-hf-r { text-align: right; }
.y-print-logo { font-weight: 700; margin-left: 6px; color: var(--y-accent, #6b46c1); }

/* While printing the preview, reveal only the print page (reuses the
   `printing-report` body class + the report builder's @media print rules
   which already hide app chrome and show the modal preview). */
@media print {
  body.printing-report .y-print-page { box-shadow: none; padding: 0; margin: 0; max-width: none; zoom: 1; }
}

/* PDF export: while `body.printing-report` is set we hide all app chrome and
   print only the report preview at full width. */
@media print {
  body.printing-report > *:not(.y-modal-scrim) { display: none !important; }
  body.printing-report .y-modal-scrim { position: static; background: none; display: block; }
  body.printing-report .y-modal-scrim > .y-report-modal { box-shadow: none; width: auto; height: auto; display: block; }
  body.printing-report .y-modal-head,
  body.printing-report .y-modal-foot,
  body.printing-report .y-report-editor,
  body.printing-report .y-report-preview-head { display: none !important; }
  body.printing-report .y-report-body { display: block; overflow: visible; }
  body.printing-report .y-report-preview-wrap { display: block; background: #fff; }
  body.printing-report .y-report-preview { overflow: visible; padding: 0; }
  body.printing-report .y-report { box-shadow: none; margin: 0; max-width: none; padding: 0; }
  .y-page-break { break-after: page; page-break-after: always; }
}

/* --------------------------------------------------------------------------
   First-run onboarding stepper (components/onboarding.rs) + Home launcher
   (components/home.rs). Reuses the app's tokens (surfaces, accent, spacing).
   -------------------------------------------------------------------------- */

/* Onboarding overlay: a two-pane card (brand rail + step) over a dimmed shell.
   The aurora accents below are intentionally brand-coloured (myrtille / mauve /
   electric-teal from branding/logo.svg) and read on both light and dark themes;
   everything else reuses the app's --y-* tokens. */
.y-onb-scrim {
  position: fixed; inset: 0; z-index: 200;
  display: grid; place-items: center;
  background: var(--y-scrim);
  /* match the modals: float above a softened page */
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
}
.y-onb {
  width: min(820px, 95vw); max-height: 92vh;
  background: var(--y-surface);
  border-radius: var(--y-r-xl);
  box-shadow: var(--y-shadow-3);
  border: 1px solid var(--y-border);
  overflow: hidden;
  display: grid; grid-template-columns: 260px 1fr;
}

/* ----- left brand rail: aurora gradient + logo + vertical step list ----- */
.y-onb-rail {
  position: relative; overflow: hidden;
  display: flex; flex-direction: column; gap: var(--y-s4);
  padding: var(--y-s5) var(--y-s4);
  color: #f3ecff;
  /* deep myrtille night-sky, matching the logo's cell */
  background: linear-gradient(160deg, #1B1140 0%, #120A2E 55%, #0A0620 100%);
}
/* a soft aurora bloom drifting behind the content */
.y-onb-rail-glow {
  position: absolute; inset: -30% -20% auto -20%; height: 80%;
  pointer-events: none; filter: blur(36px); opacity: .7;
  background:
    radial-gradient(60% 60% at 25% 20%, rgba(200,131,255,.55), transparent 70%),
    radial-gradient(55% 55% at 80% 35%, rgba(57,226,255,.35), transparent 70%),
    radial-gradient(50% 50% at 55% 80%, rgba(178,58,134,.45), transparent 70%);
}
.y-onb-brand { position: relative; display: flex; align-items: center; gap: var(--y-s3); }
.y-onb-logo {
  width: 56px; height: 56px; border-radius: var(--y-r-lg);
  box-shadow: 0 6px 20px rgba(8,4,28,.55);
}
.y-onb-wordmark {
  font-size: 1.5rem; font-weight: 800; letter-spacing: .2px;
  color: #fff;
}
.y-onb-steplist {
  position: relative; list-style: none; margin: var(--y-s3) 0 0; padding: 0;
  display: flex; flex-direction: column; gap: 2px;
}
.y-onb-stepitem {
  display: flex; align-items: center; gap: var(--y-s3);
  padding: 9px 10px; border-radius: var(--y-r-md);
  font-size: var(--y-fs-md); color: rgba(243,236,255,.6);
  transition: background .18s ease, color .18s ease;
}
.y-onb-stepitem.is-hidden { display: none; }
.y-onb-stepitem.is-done { color: rgba(243,236,255,.85); }
.y-onb-stepitem.is-active {
  color: #fff; background: rgba(255,255,255,.10);
}
.y-onb-stepnum {
  flex: 0 0 auto; width: 24px; height: 24px; border-radius: 50%;
  display: inline-grid; place-items: center;
  font-size: var(--y-fs-sm); font-weight: 700; font-variant-numeric: tabular-nums;
  background: rgba(255,255,255,.10); color: rgba(243,236,255,.8);
  border: 1px solid rgba(255,255,255,.18);
  transition: background .18s ease, color .18s ease, border-color .18s ease;
}
.y-onb-stepitem.is-active .y-onb-stepnum {
  background: linear-gradient(135deg, #C883FF, #46ECFF);
  color: #14082b; border-color: transparent;
  box-shadow: 0 0 0 4px rgba(200,131,255,.22);
}
.y-onb-stepitem.is-done .y-onb-stepnum {
  background: rgba(70,236,255,.18); color: #9af3ff; border-color: rgba(70,236,255,.4);
}
.y-onb-tagline {
  position: relative; margin: auto 0 0; padding: 0;
  font-size: var(--y-fs-sm); line-height: 1.5; color: rgba(243,236,255,.62);
}

/* ----- right pane: slim progress bar, step body, nav footer ----- */
.y-onb-main { display: flex; flex-direction: column; min-width: 0; background: var(--y-surface); }
.y-onb-progress {
  height: 3px; background: var(--y-surface-3); flex: 0 0 auto;
}
.y-onb-progress-fill {
  display: block; height: 100%;
  background: linear-gradient(90deg, #C883FF, #46ECFF);
  transition: width .35s cubic-bezier(.4,0,.2,1);
}
.y-onb-body {
  padding: var(--y-s5) var(--y-s5) var(--y-s4);
  min-height: 300px; overflow: auto; flex: 1 1 auto;
}
.y-onb-foot {
  display: flex; align-items: center; gap: var(--y-s2);
  padding: var(--y-s3) var(--y-s5);
  border-top: 1px solid var(--y-border); background: var(--y-surface-2);
}
.y-onb-count {
  font-size: var(--y-fs-sm); color: var(--y-ink-faint);
  font-variant-numeric: tabular-nums;
}

.y-onb-step { display: flex; flex-direction: column; gap: var(--y-s3); }
.y-onb-eyebrow {
  font-size: var(--y-fs-xs); font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--y-accent);
}
.y-onb-title { font-size: var(--y-fs-xl); font-weight: 700; margin: 0; line-height: 1.25; }
.y-onb-lede { margin: 0; color: var(--y-ink-soft); font-size: var(--y-fs-md); line-height: 1.55; }
.y-onb-link { color: var(--y-accent); font-size: var(--y-fs-sm); font-weight: 600; text-decoration: none; }
.y-onb-link:hover { text-decoration: underline; }

/* Language picker — a responsive grid of selectable cards. */
.y-onb-langgrid {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--y-s2);
  margin-top: var(--y-s2);
}
.y-onb-langcard {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  padding: 10px 12px; cursor: pointer; text-align: left;
  background: var(--y-surface); color: var(--y-ink);
  border: 1px solid var(--y-border); border-radius: var(--y-r-md);
  font: inherit; transition: border-color .15s ease, background .15s ease, box-shadow .15s ease;
}
.y-onb-langcard:hover { border-color: var(--y-border-strong); background: var(--y-surface-2); }
.y-onb-langcard.is-active {
  border-color: var(--y-accent); background: var(--y-accent-soft);
  box-shadow: 0 0 0 3px var(--y-accent-ring);
}
.y-onb-langcode { font-size: var(--y-fs-sm); font-weight: 700; color: var(--y-accent); }
.y-onb-langcard.is-active .y-onb-langcode { color: var(--y-accent); }
.y-onb-langname { font-size: var(--y-fs-sm); color: var(--y-ink-soft); }
.y-onb-langcard.is-active .y-onb-langname { color: var(--y-ink); }

/* CGU terms scroll area. */
.y-onb-terms {
  max-height: 210px; overflow: auto;
  background: var(--y-surface-2); border: 1px solid var(--y-border);
  border-radius: var(--y-r-md); padding: var(--y-s4);
  font-size: var(--y-fs-sm); line-height: 1.55; color: var(--y-ink-soft);
  display: flex; flex-direction: column; gap: var(--y-s2);
}
.y-onb-terms p { margin: 0; }

/* Telemetry honesty list with yes/no markers. */
.y-onb-facts {
  margin: 0; padding: 0; list-style: none;
  display: flex; flex-direction: column; gap: 6px; font-size: var(--y-fs-sm);
}
.y-onb-facts li {
  position: relative; padding-left: 26px; line-height: 1.5; color: var(--y-ink-soft);
}
.y-onb-facts li::before {
  position: absolute; left: 0; top: -1px;
  width: 18px; height: 18px; border-radius: 50%;
  display: inline-grid; place-items: center; font-size: 11px; font-weight: 700;
}
.y-onb-facts li.is-yes::before { content: "\2713"; background: var(--y-accent-soft); color: var(--y-accent); }
.y-onb-facts li.is-no { color: var(--y-ink); }
.y-onb-facts li.is-no::before { content: "\2715"; background: var(--y-danger-soft); color: var(--y-error); }

/* Small label introducing the "what we send" list. */
.y-onb-facts-label { margin: var(--y-s2) 0 6px; font-size: var(--y-fs-sm); font-weight: 600; color: var(--y-ink); }

/* Positive privacy guarantee — a reassuring shielded badge, NOT a red ✕ in the
   honesty checklist (which read like a failing item). Accent-toned, with a lock. */
.y-onb-guard {
  display: flex; align-items: flex-start; gap: 10px;
  margin: var(--y-s3) 0 0; padding: 11px 12px;
  border-radius: var(--y-r-md);
  border: 1px solid var(--y-accent); background: var(--y-accent-soft);
  font-size: var(--y-fs-sm); line-height: 1.5; color: var(--y-ink);
}
.y-onb-guard::before {
  content: "\1F512"; font-size: 15px; line-height: 1.4; flex: 0 0 auto;
}
.y-onb-guard strong { font-weight: 600; }

/* Inline privacy-policy accordion (replaces a modal that stacked behind the
   onboarding scrim). Expands the policy iframe in place. */
.y-onb-accordion {
  margin-top: var(--y-s3); border: 1px solid var(--y-border);
  border-radius: var(--y-r-md); background: var(--y-surface); overflow: hidden;
}
.y-onb-accordion > summary {
  cursor: pointer; padding: 10px 12px; list-style: none;
  font-size: var(--y-fs-sm); font-weight: 600; color: var(--y-accent);
  display: flex; align-items: center; gap: 6px;
}
.y-onb-accordion > summary::-webkit-details-marker { display: none; }
.y-onb-accordion > summary::before { content: "\25B8"; transition: transform .15s ease; }
.y-onb-accordion[open] > summary::before { transform: rotate(90deg); }
.y-onb-accordion-frame {
  width: 100%; height: 300px; border: 0; border-top: 1px solid var(--y-border);
  background: var(--y-surface); display: block;
}

/* Consent row used by CGU / telemetry / the desktop-only assoc hint. */
.y-onb-consent {
  display: flex; align-items: center; gap: var(--y-s2); cursor: pointer;
  padding: 11px 12px; border-radius: var(--y-r-md);
  border: 1px solid var(--y-border); background: var(--y-surface);
  font-size: var(--y-fs-sm); transition: border-color .15s ease, background .15s ease;
}
.y-onb-consent:hover { border-color: var(--y-border-strong); }
.y-onb-consent.is-on { border-color: var(--y-accent); background: var(--y-accent-soft); }
.y-onb-consent.is-disabled { opacity: .6; cursor: not-allowed; }
.y-onb-consent input { width: 17px; height: 17px; accent-color: var(--y-accent); flex: 0 0 auto; }

/* File-association toggle cards: extension badge + name/description + switch. */
.y-onb-assoc { display: flex; flex-direction: column; gap: var(--y-s2); }
.y-onb-fmt {
  display: flex; align-items: center; gap: var(--y-s3);
  padding: 10px 12px; cursor: pointer;
  border: 1px solid var(--y-border); border-radius: var(--y-r-md);
  background: var(--y-surface); transition: border-color .15s ease, background .15s ease;
}
.y-onb-fmt:hover { border-color: var(--y-border-strong); }
.y-onb-fmt.is-on { border-color: var(--y-accent); background: var(--y-accent-soft); }
.y-onb-fmt.is-reco { border-color: var(--y-accent); }
.y-onb-fmt-ext {
  flex: 0 0 auto; min-width: 52px; text-align: center;
  padding: 6px 8px; border-radius: var(--y-r-sm);
  font-family: var(--y-mono); font-size: var(--y-fs-xs); font-weight: 700;
  background: var(--y-surface-3); color: var(--y-ink-soft);
}
.y-onb-fmt.is-reco .y-onb-fmt-ext {
  background: linear-gradient(135deg, #C883FF, #46ECFF); color: #14082b;
}
.y-onb-fmt-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1 1 auto; }
.y-onb-fmt-name { font-size: var(--y-fs-sm); font-weight: 600; color: var(--y-ink); }
.y-onb-fmt-desc { font-size: var(--y-fs-xs); color: var(--y-ink-faint); }
.y-onb-reco {
  margin-left: 6px; padding: 1px 6px; border-radius: 999px;
  font-size: 10px; font-weight: 700; vertical-align: middle;
  background: var(--y-accent-soft); color: var(--y-accent);
}
.y-onb-switch { width: 18px; height: 18px; accent-color: var(--y-accent); flex: 0 0 auto; }

/* Generic checkbox+label row, reused by the ribbon's Options>Privacy toggle
   (components/ribbon.rs). Kept after the onboarding redesign moved to .y-onb-*. */
.y-onboard-check { display: flex; align-items: center; gap: var(--y-s2); cursor: pointer; font-size: var(--y-fs-sm); }
.y-onboard-check.is-disabled { opacity: .55; cursor: not-allowed; }
.y-onboard-check input { width: 16px; height: 16px; }

/* Home launcher: hero + a responsive grid of section cards. */
.y-home { flex: 1 1 auto; overflow: auto; padding: var(--y-s5) var(--y-s4); background: var(--y-bg); }
.y-home-hero { text-align: center; margin: var(--y-s4) 0 var(--y-s5); }
.y-home-hero .y-logo-lg { font-size: 2.4rem; letter-spacing: .3px; justify-content: center; }
.y-home-hero .y-logo-lg .y-mark {
  width: 1.5em; height: 1.5em; border-radius: var(--y-r-md);
  background: var(--y-accent); color: var(--y-accent-ink);
  display: inline-grid; place-items: center; font-weight: 800;
  margin-right: .15em; box-shadow: var(--y-shadow-1);
}
.y-home-hero .y-muted { margin: var(--y-s3) 0 0; font-size: var(--y-fs-lg); }
.y-logo-lg { font-size: 2.2rem; }
.y-home-grid {
  display: grid; gap: var(--y-s4);
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  max-width: 980px; margin: 0 auto;
}
.y-home-card {
  background: var(--y-surface); border: 1px solid var(--y-border-soft, var(--y-border));
  border-radius: var(--y-r-xl); padding: var(--y-s4);
  display: flex; flex-direction: column; gap: var(--y-s2);
  box-shadow: var(--y-shadow-2);
  transition: box-shadow .15s ease, border-color .15s ease, transform .15s ease;
}
.y-home-card:hover { box-shadow: var(--y-shadow-3); border-color: var(--y-border-strong); transform: translateY(-1px); }
.y-home-section {
  font-size: var(--y-fs-xs); font-weight: 600; margin: 0 0 var(--y-s2);
  text-transform: uppercase; letter-spacing: .06em; color: var(--y-ink-soft);
}
.y-home-action { width: 100%; justify-content: flex-start; padding: 7px 11px; }
.y-home-empty {
  font-size: var(--y-fs-sm); line-height: 1.5; color: var(--y-ink-faint);
  padding: var(--y-s2) 0;
}
.y-home-recent {
  display: flex; align-items: center; gap: var(--y-s2);
  width: 100%; text-align: left; padding: 7px 9px;
  background: transparent; border: 1px solid transparent; border-radius: var(--y-r-sm);
  cursor: pointer; color: var(--y-ink); font: inherit;
  transition: background .1s ease, border-color .1s ease;
}
.y-home-recent:hover { background: var(--y-accent-soft); border-color: var(--y-accent); }
.y-home-recent-icon { color: var(--y-ink-soft); flex: 0 0 auto; }
.y-home-recent:hover .y-home-recent-icon { color: var(--y-accent); }
.y-home-recent-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.y-home-source {
  display: flex; align-items: center; justify-content: space-between; gap: var(--y-s2);
  padding: 6px 9px; border-radius: var(--y-r-sm); background: var(--y-surface-2);
  border: 1px solid var(--y-border);
}
.y-home-source + .y-home-source { margin-top: 4px; }
.y-home-source-name { font-size: var(--y-fs-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.y-home-source-kind {
  font-size: var(--y-fs-xs); color: var(--y-ink-soft);
  background: var(--y-surface-3); border-radius: 999px; padding: 1px 8px;
}

/* --- collaboration presence (titlebar) --- */
.y-presence { display: inline-flex; align-items: center; gap: 8px; margin-left: 12px; }
/* "🟢 Session · N participant·s" indicator — the clear at-a-glance status that a
   live collab session is running, design-system styled (light + dark). */
.y-session-chip {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: var(--y-fs-xs, 11px); font-weight: 600; color: var(--y-ink);
  padding: 1px 9px; border-radius: 11px;
  background: var(--y-surface-2); border: 1px solid var(--y-border);
}
.y-session-live { font-size: 8px; line-height: 1; }
.y-session-count { font-variant-numeric: tabular-nums; }
.y-presence-peer {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: var(--y-fs-xs, 11px); color: var(--y-ink);
  padding: 1px 7px 1px 3px; border-radius: 10px;
  background: var(--y-surface); border: 1px solid var(--y-border);
}
.y-presence-dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; flex: 0 0 auto; }
.y-presence-name { font-variant-numeric: tabular-nums; }
.y-presence-owner { color: var(--y-warn); }
.y-presence-cell { color: var(--y-ink-soft); font-variant-numeric: tabular-nums; }

/* ============================================================================
   AUDIO BAR — full-duplex WebRTC voice in a live collab session
   ----------------------------------------------------------------------------
   Sits next to the presence panel in the titlebar. All tokens are --y-* so it
   adapts to light + dark. Speaking indicator = a pulsing ring on the dot.
   ============================================================================ */
.y-audio-bar { display: inline-flex; align-items: center; gap: 8px; margin-left: 10px; }

.y-audio-join {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: var(--y-fs-xs, 11px); line-height: 1;
  padding: 4px 10px; border-radius: 12px; cursor: pointer;
  color: var(--y-accent-ink); background: var(--y-accent);
  border: 1px solid var(--y-accent-hover);
}
.y-audio-join:hover { background: var(--y-accent-hover); }

.y-audio-controls { display: inline-flex; align-items: center; gap: 6px; }

.y-audio-mute, .y-audio-leave {
  font-size: var(--y-fs-xs, 11px); line-height: 1; cursor: pointer;
  padding: 3px 8px; border-radius: 10px;
  color: var(--y-text, #1b1b1b); background: var(--y-surface);
  border: 1px solid var(--y-border-strong);
}
.y-audio-mute:hover, .y-audio-leave:hover { background: var(--y-surface-2); }
.y-audio-mute.y-audio-muted {
  color: var(--y-danger, #c0392b);
  border-color: var(--y-danger-line, #f5c6c0);
  background: var(--y-danger-soft, #fdecea);
}
.y-audio-leave {
  color: var(--y-danger, #c0392b);
  border-color: var(--y-danger-line, #f5c6c0);
}

.y-audio-people { display: inline-flex; align-items: center; gap: 5px; }
.y-audio-peer {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: var(--y-fs-xs, 11px);
  color: var(--y-text, #1b1b1b);
  padding: 1px 7px 1px 4px; border-radius: 10px;
  background: var(--y-surface); border: 1px solid var(--y-border);
}
.y-audio-me .y-audio-name { font-weight: 600; }
.y-audio-dot {
  width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto;
  box-shadow: 0 0 0 0 rgba(46, 204, 113, 0.0);
}
/* Speaking indicator: green ring that pulses while the participant talks. */
.y-audio-speaking .y-audio-dot {
  box-shadow: 0 0 0 3px rgba(46, 204, 113, 0.55);
  animation: y-audio-pulse 0.9s ease-in-out infinite;
}
.y-audio-speaking {
  border-color: rgba(46, 204, 113, 0.6);
}
@keyframes y-audio-pulse {
  0%, 100% { box-shadow: 0 0 0 2px rgba(46, 204, 113, 0.35); }
  50%      { box-shadow: 0 0 0 4px rgba(46, 204, 113, 0.65); }
}

.y-audio-error {
  font-size: var(--y-fs-xs, 11px);
  color: var(--y-danger, #c0392b);
  background: var(--y-danger-soft, #fdecea);
  border: 1px solid var(--y-danger-line, #f5c6c0);
  padding: 2px 8px; border-radius: 8px; max-width: 320px;
}

/* ===================== In-app notifications (toasts) ===================== */
/* A calm, stacked, bottom-right column of auto-dismissing cards wired to collab
   session events. Tokens only → light + dark + every accent. The slide/fade-in
   reuses the shared `y-modal-in` keyframe; the global prefers-reduced-motion
   block near the top of this file already neutralises the animation. */
.y-toast-host {
  position: fixed; right: var(--y-s4, 16px); bottom: var(--y-s4, 16px);
  z-index: 130;                      /* above modals (100) + ⌘K (110) */
  display: flex; flex-direction: column; gap: var(--y-s2, 8px);
  width: min(360px, calc(100vw - 2 * var(--y-s4, 16px)));
  pointer-events: none;              /* let clicks fall through the gaps */
}
.y-toast {
  pointer-events: auto;              /* but the cards themselves are clickable */
  display: flex; align-items: center; gap: var(--y-s2, 8px);
  padding: var(--y-s2, 8px) var(--y-s3, 12px);
  background: var(--y-surface); color: var(--y-ink);
  border: 1px solid var(--y-border-soft, var(--y-border));
  border-left: 3px solid var(--y-accent);   /* kind-tinted accent stripe */
  border-radius: var(--y-r-lg, 10px); box-shadow: var(--y-shadow-3);
  animation: y-modal-in .18s cubic-bezier(.22,.68,.32,1.1) both;
}
.y-toast--info    { border-left-color: var(--y-accent); }
.y-toast--success { border-left-color: var(--y-ok); }
.y-toast--warn    { border-left-color: var(--y-warn); }
.y-toast-icon {
  flex: 0 0 auto; width: 18px; height: 18px;
  display: grid; place-items: center; border-radius: 50%;
  font-size: 11px; font-weight: 700; line-height: 1;
  color: var(--y-accent-ink, #fff); background: var(--y-accent);
}
.y-toast--info .y-toast-icon    { background: var(--y-accent); }
.y-toast--success .y-toast-icon { background: var(--y-ok); }
.y-toast--warn .y-toast-icon    { background: var(--y-warn); }
.y-toast-text {
  flex: 1 1 auto; font-size: var(--y-fs-sm, 13px); line-height: 1.35;
  min-width: 0; overflow-wrap: anywhere;
}
.y-toast-action { flex: 0 0 auto; }
.y-toast-close {
  flex: 0 0 auto; border: 0; background: transparent; cursor: pointer;
  color: var(--y-ink-soft); font-size: 12px; line-height: 1;
  padding: 4px; border-radius: 6px;
}
.y-toast-close:hover { background: var(--y-surface-2); color: var(--y-ink); }

/* ============================================================================
   RESPONSIVE + TOUCH ADAPTATION
   ----------------------------------------------------------------------------
   ycell was built desktop-first (mouse, wide screens). The native Android/iOS
   shells embed this exact UI in a WebView, so it must also work on a narrow
   portrait phone with a finger. Every rule below is ADDITIVE and gated behind
   either a width media query or a `pointer: coarse` / `hover: none` query, so
   the desktop layout at wide widths + with a mouse is left untouched.

   Breakpoints:
     - 760px : tablet / small-laptop — start collapsing chrome
     - 560px : phone — side panels become overlays, full-width dialogs
   ========================================================================== */

/* ---- Safe-area insets (iOS notch / home indicator). The shell paints to the
   screen edges (viewport-fit=cover); pad the outer chrome so nothing hides
   under the notch or the home bar. Zero on devices without insets. -------- */
.y-app {
  padding-top: env(safe-area-inset-top, 0px);
  padding-left: env(safe-area-inset-left, 0px);
  padding-right: env(safe-area-inset-right, 0px);
  /* The grid box uses 100vh; account for the inset so the last row + sheet
     tabs aren't swallowed by the home indicator. */
  height: 100dvh;
}
@supports not (height: 100dvh) { .y-app { height: 100vh; } }
.y-sheet-tabs, .y-status {
  padding-bottom: env(safe-area-inset-bottom, 0px);
}

/* ---- Touch: smooth momentum scrolling + sane touch-action on every scroll
   surface, and a comfortable default for tap-only affordances. These only
   bite on coarse pointers, so desktop scrolling/selection is unchanged. --- */
@media (pointer: coarse) {
  .y-panel-body, .y-ai-body, .y-ai-thread, .y-modal-body, .y-home,
  .y-onb-terms, .y-ctx-menu, .y-menu, .y-ribbon-body, .y-sheet-tabs,
  .y-source-explorer, .y-autocomplete, .y-report-preview {
    -webkit-overflow-scrolling: touch;
  }
  /* The canvas grid handles its own panning via touch handlers (see
     grid/canvas.rs). Tell the browser we own vertical+horizontal gestures so
     it doesn't also scroll the page / fire a 300ms click delay, while still
     allowing a two-finger pinch-zoom of the whole page. */
  .y-gridwrap, .y-grid-canvas {
    touch-action: pan-x pan-y pinch-zoom;
  }
  .y-grid-canvas { cursor: default; }

  /* Tap targets ≥44px on touch. We bump padding/min-size rather than font so
     the desktop look is preserved; these selectors are touch-only. */
  .y-btn { min-height: 44px; }
  .y-btn.y-icon { min-width: 44px; }
  .y-tab { padding-top: 12px; padding-bottom: 11px; min-height: 44px; }
  .y-sheet-tab { padding: 0 14px; min-height: 44px; }
  .y-sheet-add { min-width: 44px; min-height: 44px; }
  .y-ctx-item, .y-menu-item { min-height: 44px; }
  .y-seg button { padding: 9px 14px; }
  .y-modal-foot .y-btn, .y-onb-foot .y-btn { min-height: 44px; }
  /* Inputs at ≥16px avoid iOS auto-zoom-on-focus. */
  .y-input, .y-select, .y-textarea, .y-formula-input, .y-cell-editor,
  .y-ai-input { font-size: 16px; }
}

/* ---- Tablet / small width: let the ribbon + formula bar wrap or scroll
   instead of overflowing. Width-based (independent of pointer). ---------- */
@media (max-width: 760px) {
  /* Ribbon body already scrolls horizontally; make its tabs scroll too so a
     long tab row never overflows the viewport. */
  .y-ribbon-tabs { overflow-x: auto; flex-wrap: nowrap; }
  .y-ribbon-tabs::-webkit-scrollbar { height: 0; }
  /* Trim the chrome a touch to give the grid more of a small screen. */
  .y-titlebar .y-doc { display: none; }
}

/* ---- Phone: the big layout shift. Side panels stop eating the row width and
   become full-width overlays; dialogs go full-bleed bottom-sheet-ish. ----- */
@media (max-width: 560px) {
  /* Title bar: keep it compact, allow the links to shrink. */
  .y-titlebar { gap: var(--y-s2); padding: 0 var(--y-s2); }
  .y-titlebar-link { padding: 4px 6px; }

  /* The work area keeps the grid full-width; panels overlay it on demand. */
  .y-work { position: relative; }
  .y-center { width: 100%; }

  /* Left data panel + right AI panel: pulled OUT of the flex row and shown as
     fixed full-width drawers over the grid. When collapsed they're hidden
     entirely (the ribbon's Données / IA buttons reopen them). This means the
     grid always gets the full screen width — no horizontal page scroll. */
  .y-sidepanel, .y-aipanel {
    position: fixed;
    left: env(safe-area-inset-left, 0px);
    right: env(safe-area-inset-right, 0px);
    /* Sit below the formula bar; above the grid + sheet tabs. */
    top: auto; bottom: 0;
    width: auto !important;
    max-height: 70vh;
    z-index: 80;
    box-shadow: var(--y-shadow-3);
    border: 1px solid var(--y-border);
    border-radius: var(--y-r-xl) var(--y-r-xl) 0 0;
  }
  .y-sidepanel.is-collapsed, .y-aipanel.is-collapsed {
    display: none;
  }
  /* The AI panel collapse-tab (vertical sliver) makes no sense as a drawer;
     hidden via is-collapsed above. When open it fills the drawer normally. */
  .y-aipanel .y-collapse-tab { display: none; }

  /* Dialogs: near-full-width, with the body free to grow taller (a phone has
     little width but plenty of height). Keep the min() so very small phones
     still get a margin. */
  .y-modal { width: min(560px, 96vw); }
  .y-modal-body { max-height: 76vh; }
  .y-wizard { width: 96vw; height: 88vh; max-height: 88vh; }
  /* Step-1 picker: collapse the two panes to a single column. The category
     sidebar becomes a horizontal, scrollable chip rail above the cards. */
  .y-picker { grid-template-columns: 1fr; gap: var(--y-s3); }
  .y-picker-side {
    flex-direction: row; overflow-x: auto; overflow-y: hidden;
    border-right: none; border-bottom: 1px solid var(--y-border);
    padding: 0 0 var(--y-s2); gap: var(--y-s1);
  }
  .y-cat-item { width: auto; flex: 0 0 auto; }
  /* Onboarding: collapse the two-pane card to a single column; the rail becomes
     a compact header so the brand stays visible without eating vertical space. */
  .y-onb { width: 96vw; grid-template-columns: 1fr; max-height: 94vh; }
  .y-onb-rail {
    flex-direction: row; align-items: center; flex-wrap: wrap;
    gap: var(--y-s3); padding: var(--y-s4);
  }
  .y-onb-steplist { display: none; }
  .y-onb-tagline { display: none; }
  .y-onb-logo { width: 44px; height: 44px; }
  .y-onb-body { padding: var(--y-s4); min-height: 0; }
  .y-onb-foot { padding: var(--y-s3) var(--y-s4); }
  .y-onb-langgrid { grid-template-columns: repeat(2, 1fr); }

  /* Formula bar: the name box is a luxury on a phone; shrink it so the actual
     formula field keeps room. Keep the fx affordance. */
  .y-namebox { width: 64px; }

  /* Sheet tabs: a touch taller so they're tappable, names can ellipsize more. */
  .y-sheet-name { max-width: 110px; }
}

/* ---- Virtual-keyboard handling. When the soft keyboard opens, iOS/Android
   shrink the visual viewport but NOT the layout viewport, so a bottom-anchored
   element (and the formula field while editing) can hide behind the keyboard.
   `100dvh` (dynamic viewport) on the shell already tracks the keyboard on
   modern WebViews; combined with the grid editor floating over the canvas this
   keeps the active cell editor on-screen. The formula input also scrolls into
   view on focus via the browser default. No JS needed for the common case. */
@media (max-width: 760px) {
  .y-formulabar { position: relative; z-index: 30; }
}

/* --- Pivot-table builder (Modal::PivotBuilder) ------------------------------ */
.y-pivot-body { display: flex; gap: var(--y-s4); padding: var(--y-s4); min-width: 560px; }
.y-pivot-col { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--y-s3); }
.y-pivot-fields-head, .y-pivot-bucket-head {
  font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .03em; color: var(--y-ink-soft); margin-bottom: 2px;
}
.y-pivot-fields {
  border: 1px solid var(--y-border); border-radius: var(--y-radius);
  max-height: 280px; overflow-y: auto; background: var(--y-surface);
}
.y-pivot-field {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--y-s2); padding: 4px 8px; border-bottom: 1px solid var(--y-border);
}
.y-pivot-field:last-child { border-bottom: none; }
.y-pivot-field-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.y-pivot-field-acts { display: flex; gap: 2px; flex: 0 0 auto; }
.y-btn.y-mini { padding: 1px 6px; font-size: 12px; line-height: 1.4; min-width: 0; }
.y-pivot-bucket {
  border: 1px dashed var(--y-border-strong); border-radius: var(--y-radius);
  padding: 6px; min-height: 40px; display: flex; flex-wrap: wrap; gap: 4px;
  align-content: flex-start; background: var(--y-surface-2);
}
.y-pivot-bucket .y-pivot-bucket-head { flex: 0 0 100%; }
.y-pivot-chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 6px; border-radius: 10px; background: var(--y-accent-soft);
  border: 1px solid var(--y-border); font-size: 12px;
}
.y-chip-x { border: none; background: transparent; cursor: pointer; color: var(--y-ink-soft); padding: 0 2px; font-size: 13px; }
.y-chip-x:hover { color: var(--y-danger, #c0392b); }
.y-mini-select { font-size: 11px; padding: 0 2px; border: 1px solid var(--y-border); border-radius: 4px; background: var(--y-surface); }
.y-pivot-anchor { margin-top: var(--y-s2); }
.y-pivot-status { color: var(--y-ink-soft); font-size: 12px; flex: 0 0 auto; }

/* --- Audit: "Expliquer la cellule" provenance panel --- */
.y-explain { min-width: 460px; max-width: 640px; }
.y-explain-body { max-height: 60vh; overflow: auto; }
.y-explain-tree, .y-explain-children { list-style: none; margin: 0; padding: 0; }
.y-explain-children { margin-left: 14px; padding-left: 10px; border-left: 1px dashed var(--y-border); }
.y-explain-node { padding: 1px 0; }
.y-explain-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.y-explain-cell {
  display: inline-flex; align-items: baseline; gap: 8px; cursor: pointer;
  border: 1px solid transparent; border-radius: 6px; padding: 2px 8px;
  background: var(--y-surface-2); font: inherit; color: inherit; text-align: left;
}
.y-explain-cell:hover { border-color: var(--y-accent); background: var(--y-accent-soft); }
.y-explain-cell.is-error { border-color: var(--y-danger-line, #f3bcbc); }
.y-explain-addr { font-weight: 600; font-variant-numeric: tabular-nums; }
.y-explain-val { color: var(--y-ink-faint); font-size: var(--y-fs-xs); }
.y-explain-val.is-error { color: var(--y-error); font-weight: 600; }
.y-explain-badge {
  display: inline-flex; align-items: center; gap: 3px;
  font-size: 11px; color: var(--y-ink-faint); padding: 1px 6px;
  border-radius: 10px; border: 1px solid var(--y-border); white-space: nowrap;
}
.y-kind-external { color: var(--y-accent); border-color: var(--y-accent); }
.y-kind-cycle, .y-kind-blank { color: var(--y-ink-faint); }
.y-explain-dig { font-size: 11px; cursor: pointer; background: none; border: none; color: var(--y-accent); padding: 0; text-decoration: underline; }

/* --- live collaboration session ("RDV") --- */
/* GUEST waiting room: full-screen overlay covering the blank doc until admitted. */
.y-waiting-scrim {
  position: fixed; inset: 0; z-index: 1200;
  display: flex; align-items: center; justify-content: center;
  background: rgba(20, 22, 28, 0.55); backdrop-filter: blur(3px);
}
.y-waiting-box {
  background: var(--y-bg, #fff); color: var(--y-ink, #222);
  border: 1px solid var(--y-border); border-radius: 14px;
  padding: 28px 34px; max-width: 420px; text-align: center;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.25);
}
.y-waiting-spinner {
  width: 34px; height: 34px; margin: 0 auto 16px;
  border: 3px solid var(--y-accent-soft); border-top-color: var(--y-accent);
  border-radius: 50%; animation: y-spin 0.9s linear infinite;
}
@keyframes y-spin { to { transform: rotate(360deg); } }
.y-waiting-title { font-size: 16px; font-weight: 600; margin-bottom: 6px; }
.y-waiting-sub { font-size: 13px; color: var(--y-ink-faint, #777); line-height: 1.45; }

/* HOST admit panel: docked bottom-right, lists join requests with Admit/Refuse. */
.y-admit-panel {
  position: fixed; right: 18px; bottom: 64px; z-index: 1100;
  width: 320px; background: var(--y-bg, #fff);
  border: 1px solid var(--y-border-strong, #dcdbd7); border-radius: 12px;
  box-shadow: 0 10px 32px rgba(0, 0, 0, 0.2); padding: 12px 14px;
}
.y-admit-head { font-size: 13px; font-weight: 600; margin-bottom: 8px; }
.y-admit-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px; padding: 6px 0; border-top: 1px solid var(--y-border);
}
.y-admit-row:first-of-type { border-top: none; }
.y-admit-name { font-size: 13px; }
.y-admit-actions { display: inline-flex; gap: 6px; }
.y-btn.y-sm { padding: 3px 9px; font-size: 12px; }
.y-admit-cap { margin-top: 8px; font-size: 11px; color: var(--y-ink-faint, #888); }

/* --- Contacts & identity panel (ADR 0006) ------------------------------- */
/* The ribbon's top-level Contacts action: a button, visually distinct from the
   tabs (it never shows an active state). */
.y-tab.y-tab-action {
  font-weight: 500;
  color: var(--y-ink-soft);
  border-radius: var(--y-r-sm);
}
.y-tab.y-tab-action:hover { color: var(--y-ink); background: var(--y-hover-veil); }

.y-modal.y-contacts { width: min(560px, 94vw); }
.y-modal.y-contacts .y-modal-body { display: flex; flex-direction: column; gap: var(--y-s5); }
.y-modal.y-contacts section { display: flex; flex-direction: column; gap: var(--y-s3); }

.y-row { display: flex; align-items: center; }

/* A monospace, copy-friendly fingerprint / id chip. */
.y-fingerprint {
  display: inline-block;
  align-self: flex-start;
  width: fit-content;
  font-family: var(--y-mono);
  font-size: var(--y-fs-xs);
  color: var(--y-code-ink);
  background: var(--y-code-bg);
  padding: 1px 7px;
  border-radius: var(--y-r-sm);
  letter-spacing: 0.02em;
}

/* One row per contact. */
.y-contact-row {
  display: flex;
  align-items: center;
  gap: var(--y-s3);
  padding: 7px 4px;
  border-top: 1px solid var(--y-border);
}
.y-contact-row:last-child { border-bottom: 1px solid var(--y-border); }
.y-contact-main { display: flex; flex-direction: column; gap: 3px; flex: 1; min-width: 0; }
.y-contact-name { font-weight: 500; color: var(--y-ink); }

.y-badge {
  font-size: var(--y-fs-xs);
  color: var(--y-ink-soft);
  background: var(--y-surface);
  border: 1px solid var(--y-border);
  padding: 1px 8px;
  border-radius: 999px;
  white-space: nowrap;
}

.y-ok { color: var(--y-ok); font-size: var(--y-fs-sm); }
.y-err { color: var(--y-error); font-size: var(--y-fs-sm); margin-top: 4px; }

/* Canonical modal tab bar (underline tabs) — shared by every tabbed dialog so
   they all read the same (Contacts hub, Format Cells, …). */
.y-modal-tabs {
  display: flex;
  gap: 2px;
  border-bottom: 1px solid var(--y-border);
  margin-bottom: 4px;
}
.y-modal-tabs .y-tab {
  flex: 1;
  padding: 8px 10px;
  border: none;
  background: none;
  color: var(--y-ink-soft);
  font-size: var(--y-fs-sm);
  font-weight: 500;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  cursor: pointer;
  white-space: nowrap;
}
.y-modal-tabs .y-tab:hover { color: var(--y-ink); }
.y-modal-tabs .y-tab.is-active { color: var(--y-accent); border-bottom-color: var(--y-accent); }
.y-tab-body { display: flex; flex-direction: column; gap: var(--y-s5); }
.y-tab-body section { display: flex; flex-direction: column; gap: var(--y-s3); }

/* --- Format Cells dialog: aligned to the design system ------------------ */
.y-modal.y-fc { width: min(620px, 95vw); }
/* The tab bar reuses the canonical underline style. */
.y-fc-tabs {
  display: flex;
  gap: 2px;
  border-bottom: 1px solid var(--y-border);
  padding: 0 var(--y-s4);
}
.y-fc-tab {
  padding: 9px 12px;
  border: none;
  background: none;
  color: var(--y-ink-soft);
  font-size: var(--y-fs-sm);
  font-weight: 500;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  cursor: pointer;
}
.y-fc-tab:hover { color: var(--y-ink); }
.y-fc-tab-active { color: var(--y-accent); border-bottom-color: var(--y-accent); }

/* Number tab: a left category rail + right options pane. */
.y-fc-number { display: grid; grid-template-columns: 156px 1fr; gap: var(--y-s5); }
.y-fc-catlist { display: flex; flex-direction: column; gap: 1px; }
.y-fc-catitem {
  text-align: left;
  padding: 7px 10px;
  border: none;
  background: none;
  color: var(--y-ink);
  font-size: var(--y-fs-sm);
  border-radius: var(--y-r-sm);
  cursor: pointer;
}
.y-fc-catitem:hover { background: var(--y-hover-veil); }
.y-fc-catitem-active { background: var(--y-accent-soft); color: var(--y-accent); font-weight: 500; }
.y-fc-catopts { display: flex; flex-direction: column; gap: var(--y-s3); min-width: 0; }

/* A per-option row: label on the left, control on the right. */
.y-fc-row { display: flex; align-items: center; justify-content: space-between; gap: var(--y-s3); }
.y-fc-row > .y-input, .y-fc-row > .y-select { max-width: 220px; }
.y-fc-form { display: flex; flex-direction: column; gap: var(--y-s3); }
.y-fc-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--y-s3); }

/* The live preview: a quiet card with the formatted value. */
.y-fc-preview {
  display: flex;
  flex-direction: column;
  gap: 4px;
  background: var(--y-surface);
  border: 1px solid var(--y-border);
  border-radius: var(--y-r-md);
  padding: 10px 12px;
  margin-top: 4px;
}
.y-fc-preview-val {
  font-family: var(--y-mono);
  font-size: var(--y-fs-lg);
  color: var(--y-ink);
}

/* Received-invitations section (phase 2): a soft-accent callout above the card. */
.y-invites {
  background: var(--y-accent-soft);
  border: 1px solid var(--y-accent-ring);
  border-radius: var(--y-r-md);
  padding: 10px 12px;
}
.y-invite-row {
  display: flex;
  align-items: center;
  gap: var(--y-s3);
  padding: 6px 0;
}
.y-invite-row + .y-invite-row { border-top: 1px solid var(--y-accent-ring); }

/* The findable-by-email opt-in checkbox row. */
.y-check {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  font-size: var(--y-fs-sm);
  color: var(--y-ink);
}
.y-check input { margin: 0; }

/* --- Optimizer + Monte-Carlo panels --- */
/* These render inside .y-modal (Optimizer / Monte-Carlo). Bring the bespoke
   y-opt-* hooks onto the design system: two-column body, calm section heads,
   clean editor rows, monospace values, and a soft-accent "best" pill. */
.y-opt-body { align-items: flex-start; }
.y-opt-col { display: flex; flex-direction: column; gap: var(--y-s2); }
.y-opt-section-head {
  font-size: var(--y-fs-xs);
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--y-ink-faint);
  font-weight: 600;
}
.y-opt-row {
  display: flex;
  align-items: center;
  gap: var(--y-s2);
  flex-wrap: wrap;
  padding: 4px 0;
}
.y-opt-cell { font-family: var(--y-mono); font-size: var(--y-fs-sm); color: var(--y-ink-soft); }
.y-opt-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.y-opt-status { font-size: var(--y-fs-sm); color: var(--y-ink-soft); }
.y-opt-warn { color: var(--y-error); font-size: var(--y-fs-sm); }
.y-opt-best {
  font-family: var(--y-mono);
  font-size: var(--y-fs-xs);
  color: var(--y-accent);
  background: var(--y-accent-soft);
  border: 1px solid var(--y-accent-ring);
  border-radius: var(--y-r-sm);
  padding: 1px 6px;
}

/* --- History panel: snapshots, diff, causal lineage --- */
.y-hist-list { display: flex; flex-direction: column; gap: 2px; }
.y-hist-item {
  display: flex;
  flex-direction: column;
  gap: var(--y-s2);
  padding: 7px 10px;
  border-radius: var(--y-r-sm);
  color: var(--y-ink);
  font-size: var(--y-fs-sm);
  cursor: default;
  transition: background 90ms ease;
}
.y-hist-item:hover { background: var(--y-hover-veil); }
.y-hist-item.is-active,
.y-hist-item[aria-selected="true"] { background: var(--y-accent-soft); color: var(--y-accent); }
.y-hist-item b { font-weight: 600; font-size: var(--y-fs-sm); line-height: 1.3; }
.y-diff-list { display: flex; flex-direction: column; gap: 1px; }
.y-diff-row {
  display: flex;
  align-items: baseline;
  gap: var(--y-s3);
  padding: 3px 6px;
  border-radius: var(--y-r-sm);
  font-family: var(--y-mono);
  font-size: var(--y-fs-xs);
  color: var(--y-ink-soft);
  cursor: pointer;
  transition: background 90ms ease;
}
.y-diff-row:hover { background: var(--y-hover-veil); }
.y-diff-row code { font-family: var(--y-mono); font-size: var(--y-fs-xs); color: var(--y-ink); }
.y-diff-row .y-diff-add { color: var(--y-ok); }
.y-diff-row .y-diff-del { color: var(--y-error); text-decoration: line-through; }
.y-causal-list { display: flex; flex-direction: column; gap: var(--y-s2); color: var(--y-ink); }
.y-causal-list > li { border-radius: var(--y-r-sm); }
.y-causal-list summary { color: var(--y-ink-faint); font-size: var(--y-fs-xs); font-family: var(--y-mono); }
.y-causal-list summary:hover { color: var(--y-ink-soft); }
.y-causal-list code { font-family: var(--y-mono); font-size: var(--y-fs-xs); color: var(--y-ink); }

/* --- modal.rs dialogs: cond-format, extensions, inbox, perms, modules, local-AI, sources-empty --- */
.y-modal .y-cf-list {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--y-border);
  border-radius: var(--y-r-md);
  overflow: hidden;
  background: var(--y-surface);
}
.y-modal .y-cf-list > .y-field-row { align-items: center; gap: var(--y-s3); padding: 8px 10px; margin: 0; }
.y-modal .y-cf-list > .y-field-row + .y-field-row { border-top: 1px solid var(--y-border); }
.y-modal .y-cf-list > .y-field-row:hover { background: var(--y-hover-veil); }
.y-modal .y-ext-header {
  display: flex; align-items: center; gap: var(--y-s2);
  padding-bottom: var(--y-s3); border-bottom: 1px solid var(--y-border); margin-bottom: var(--y-s3);
}
.y-modal .y-ext-section-title {
  font-size: var(--y-fs-xs); text-transform: uppercase; letter-spacing: .04em;
  color: var(--y-ink-faint); font-weight: 600; margin: var(--y-s5) 0 var(--y-s2);
}
.y-modal .y-ext-section-title:first-child { margin-top: 0; }
.y-modal .y-ext-pane { display: flex; flex-direction: column; gap: var(--y-s3); }
.y-modal .y-perm-list {
  list-style: none; margin: var(--y-s2) 0 0; padding: 0;
  display: flex; flex-direction: column; gap: 6px;
}
.y-modal .y-perm-list > li { position: relative; padding-left: 18px; font-size: var(--y-fs-sm); color: var(--y-ink); line-height: 1.4; }
.y-modal .y-perm-list > li::before {
  content: ""; position: absolute; left: 4px; top: .55em;
  width: 5px; height: 5px; border-radius: 50%; background: var(--y-accent);
}
.y-modal .y-modules-list { display: flex; flex-direction: column; gap: var(--y-s2); }
.y-modal .y-module-row { background: var(--y-surface); border-radius: var(--y-r-md); }
.y-modal .y-module-row:hover { background: var(--y-hover-veil); }
.y-modal .y-inbox-row:hover { background: var(--y-hover-veil); }
.y-modal .y-local-wasm { display: flex; flex-direction: column; gap: var(--y-s3); }
.y-modal .y-local-status { display: flex; align-items: center; gap: var(--y-s2); font-size: var(--y-fs-sm); color: var(--y-ink-soft); }
.y-modal .y-local-install { border-radius: var(--y-r-md); background: var(--y-accent-soft); }
.y-modal .y-local-install > div:first-child { font-weight: 600; color: var(--y-ink); }
.y-modal .y-local-install code {
  font-family: var(--y-mono); font-size: var(--y-fs-xs); color: var(--y-ink);
  border: 1px solid var(--y-border); border-radius: var(--y-r-sm);
}
.y-sources-empty-icon { font-size: 32px; line-height: 1; opacity: .45; text-align: center; }
.y-sources-empty-title { font-weight: 500; color: var(--y-ink); text-align: center; font-size: var(--y-fs-md); margin-top: var(--y-s2); }

/* ── Console d'organisation (tenant admin) ─────────────────────────────── */
/* KPI cards (Vue d'ensemble) — on-brand surface cards built from the tokens. */
.y-kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: var(--y-s3);
  margin: var(--y-s3) 0;
}
.y-kpi-card {
  border: 1px solid var(--y-border);
  border-radius: var(--y-r-md);
  background: var(--y-bg-elev);
  padding: var(--y-s3) var(--y-s4);
}
.y-kpi-value { font-size: var(--y-fs-xl); font-weight: 600; color: var(--y-ink); line-height: 1.2; }
.y-kpi-label { font-size: var(--y-fs-xs); margin-top: var(--y-s1); }

/* A list row (espaces) — input + actions on one line. */
.y-list-row {
  display: flex;
  gap: var(--y-s2);
  align-items: center;
  padding: var(--y-s2) 0;
  border-bottom: 1px solid var(--y-border-soft);
}
.y-list-row:last-child { border-bottom: none; }
.y-list-row .y-input { flex: 1; }

/* Compact data table (membres / historique / factures). */
.y-table { width: 100%; border-collapse: collapse; font-size: var(--y-fs-sm); }
.y-table th {
  text-align: left;
  font-weight: 500;
  color: var(--y-ink-soft);
  padding: var(--y-s2);
  border-bottom: 1px solid var(--y-border);
}
.y-table td { padding: var(--y-s2); border-bottom: 1px solid var(--y-border-soft); vertical-align: middle; }
.y-table tr:last-child td { border-bottom: none; }
.y-table .y-input { min-width: 140px; }

/* Plain list + link affordance reused across the billing pane. */
.y-list { list-style: none; padding: 0; margin: 0; }
.y-list li { padding: var(--y-s2) 0; border-bottom: 1px solid var(--y-border-soft); }
.y-list li:last-child { border-bottom: none; }
.y-link { color: var(--y-accent); text-decoration: none; background: none; border: none; cursor: pointer; }
.y-link:hover { text-decoration: underline; }

/* Callout / upsell box. */
.y-callout { font-size: var(--y-fs-sm); color: var(--y-ink); }
