/* ── Saegus brand font : Open Sans ─────────────────────────────────────────
   Loaded from Google Fonts CDN at the top of the file so the @import resolves
   before any rule that references the family. Applied with !important on the
   root + key UI shells because chainlit (and shadcn/Tailwind) set their own
   default `--font-sans` via inline classes that would otherwise win.

   Explicit exclusions:
   - Code blocks / monospace surfaces keep a monospaced family (lisibilité
     du JSON snapshot, du XML, des extraits SQL).
   - bpmn-js icon font (.bpmn-icon-*) reste sur sa propre `font-family: bpmn`
     définie par bpmn-font/css/bpmn.css — sinon les pictos du modeler
     deviennent des carrés. Idem pour les icones diagram-js et lucide.
─────────────────────────────────────────────────────────────────────────── */
@import url('https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,400;1,600&display=swap');

html, body, #root, .chainlit-app, [data-chainlit] {
  font-family: 'Open Sans', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif !important;
}

/* Form/UI elements that often inherit user-agent fonts. */
button, input, select, textarea, label {
  font-family: inherit;
}

/* Preserve monospace for code-y surfaces. */
code, pre, kbd, samp,
.font-mono, [class*="font-mono"],
.cm-editor, .cm-content {
  font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace !important;
}

/* ── Assistant avatar : theme-aware swap ────────────────────────────────────
   chainlit's `default_avatar_file_url` is a fixed URL — no native theme
   switch. We point it at the dark-theme variant in config.toml, then swap
   to the light-theme variant via CSS when the html root does NOT carry the
   `dark` class. `content: url()` on an <img> is supported in all evergreen
   browsers and is the cleanest way to flip an image whose src attribute we
   don't control. */
html:not(.dark) img[src$="/public/images/logomark_dark.png"] {
  content: url('/public/images/logomark_white.png');
}

/* ── Background gradient blobs Saegus ── */
body::before {
  content: '';
  position: fixed;
  top: -20%;
  left: -20%;
  width: 90vw;
  height: 90vh;
  background: radial-gradient(ellipse at center, rgba(79, 110, 247, 0.28) 0%, rgba(79, 110, 247, 0.12) 35%, transparent 70%);
  pointer-events: none;
  z-index: 0;
}

body::after {
  content: '';
  position: fixed;
  bottom: -25%;
  right: -20%;
  width: 90vw;
  height: 90vh;
  background: radial-gradient(ellipse at center, rgba(124, 58, 237, 0.25) 0%, rgba(124, 58, 237, 0.10) 35%, transparent 70%);
  pointer-events: none;
  z-index: 0;
}

/* ── Login right pane : two corner illustrations ──────────────────────────
   Chainlit's native `login_page_image` only supports one image, full-bleed.
   We override that by hiding the rendered <img> and painting two pseudo-
   elements on the pane itself: `prototyping-process` in the top-left
   quadrant, `thought-process` in the bottom-right quadrant.
   The dark-mode filter (invert + hue-rotate) keeps the line-art legible
   on the dark UI while preserving accent colors.
─────────────────────────────────────────────────────────────────────────── */
.grid.min-h-svh.lg\:grid-cols-2 > :nth-child(2) {
  position: relative;
}

/* Hide chainlit's full-bleed splash <img> — we paint the pane ourselves */
.grid.min-h-svh.lg\:grid-cols-2 > :nth-child(2) img {
  display: none !important;
}

/* Top-left: prototyping-process */
.grid.min-h-svh.lg\:grid-cols-2 > :nth-child(2)::before {
  content: '';
  position: absolute;
  top: 2rem;
  left: 2rem;
  width: calc(60% - 2rem);
  height: calc(50% - 2rem);
  background-image: url('/public/images/undraw_prototyping-process_1thp.svg');
  background-size: contain;
  background-repeat: no-repeat;
  background-position: top left;
  filter: invert(1) hue-rotate(180deg) brightness(0.95);
  pointer-events: none;
}

/* Bottom-right: thought-process */
.grid.min-h-svh.lg\:grid-cols-2 > :nth-child(2)::after {
  content: '';
  position: absolute;
  bottom: 2rem;
  right: 2rem;
  width: calc(60% - 2rem);
  height: calc(50% - 2rem);
  background-image: url('/public/images/undraw_thought-process_ze2r.svg');
  background-size: contain;
  background-repeat: no-repeat;
  background-position: bottom right;
  filter: invert(1) hue-rotate(180deg) brightness(0.95);
  pointer-events: none;
}

/* ── Right-pane element sidebar : flip the close arrow from ← to →
   Chainlit renders an <ArrowLeft /> lucide SVG inside the side-view header
   (ElementSideView.tsx). Visually a ← suggests "go back somewhere", but
   here clicking it collapses the side pane — a → ("close to the right")
   maps better to the gesture. We mirror just the icon, not the button. ── */
#side-view-title button svg {
  transform: scaleX(-1);
}

/* ── Pin the side-view title to "Process Snapshot" regardless of what
   chainlit's `sideViewState.title` happens to be.

   Why CSS rather than server-side `set_title`: chainlit's MessagesContainer
   has a useEffect that auto-opens the side view on side-element change with
   `title = sideElements[length-1].name`. That effect fires every time:
     - msg.update() emits new element events,
     - cl.ElementSidebar.set_elements re-emits them,
     - the user navigates to a thread whose persisted elements were created
       before we always appended a "Process Snapshot" Text.
   It races our explicit set_title and wins, so threads with only a
   "BpmnModeler" element show that as the title even after our fix.

   We hide the dynamic text node by zeroing the container's font-size and
   restoring it on children, then add our pinned label via ::after. The
   close button is sized by its icon-button class (h-10 w-10), not text,
   so it's unaffected. ── */
#side-view-title {
  font-size: 0 !important;
}
#side-view-title button,
#side-view-title button * {
  font-size: initial !important;
}
#side-view-title::after {
  content: "Process Snapshot";
  font-size: 1.125rem;       /* matches the original `text-lg` */
  font-weight: 600;          /* matches `font-semibold` */
  color: hsl(var(--foreground));
  margin-left: 0.25rem;
}

/* ── BPMN modeler fullscreen-modal mode ────────────────────────────────────
   When the BpmnModeler component sets `bpmn-modeler-fullscreen-active` on
   itself, two things need to happen:

   1) Chainlit's right-side ResizablePanel has Tailwind classes
      `transform translate-x-0`, which gives it a CSS transform — and an
      element with `transform: <anything>` becomes the containing block
      for any `position: fixed` descendants. So our modal would be sized
      relative to the side panel rather than the viewport (the visual
      bug we're fixing). Setting `transform: none` on that ancestor
      restores the viewport as the containing block.

   2) A backdrop: dim the rest of the page so the modal feels modal.
      We use `html::before` because `body::before/::after` are already
      taken by saegus's gradient blobs above.
─────────────────────────────────────────────────────────────────────────── */
body:has(.bpmn-modeler-fullscreen-active) [class~="transform"][class~="translate-x-0"] {
  transform: none !important;
  transition: none !important;
}

html:has(.bpmn-modeler-fullscreen-active)::before {
  content: '';
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  z-index: 9998;
  pointer-events: none;
}

/* ── BPMN modeler — read-only mode (peeking at the original after a save).
   When `bpmn-modeler-readonly` is on the root, hide the edit affordances
   so the user can pan/zoom/select but the visible UI screams "view only".
   Any keyboard-shortcut edit that sneaks through is silently undone by
   the commandStack.changed listener in BpmnModeler.jsx — this CSS is the
   visual half of that contract. ────────────────────────────────────── */
.bpmn-modeler-readonly .djs-palette,
.bpmn-modeler-readonly .djs-context-pad,
.bpmn-modeler-readonly .djs-popup {
  display: none !important;
}
.bpmn-modeler-readonly .djs-element {
  cursor: default !important;          /* nothing happens on click — match the cursor */
}

/* ── BPMN modeler : restore bpmn.io's default light theme on overlay UI.
   Chainlit's dark theme sets `color: var(--foreground)` (white) on the
   root, and bpmn-js's context-pad / replace-popup inherit that for
   their icons and text — turning them white-on-white = invisible.
   We pin those overlay elements to dark colors so the editor matches
   what users see on demo.bpmn.io. The selectors are bpmn-js-/diagram-js-
   specific so the rules don't leak into chainlit's UI. ─────────────── */
.djs-context-pad .entry {
  color: #333 !important;
}
.djs-popup,
.djs-popup *,
.djs-popup-body,
.djs-popup-header {
  color: #333 !important;
}
.djs-popup,
.djs-popup-body {
  background-color: #fff !important;
}
.djs-popup-search input {
  color: #333 !important;
  background-color: #fff !important;
  border-color: #d4d4d4 !important;
}
.djs-popup-body .entry:hover,
.djs-popup-body .entry.selected {
  background-color: #f0f0f0 !important;
}
.djs-direct-editing-content {
  color: #333 !important;
  background-color: #fff !important;
}
.djs-tooltip {
  color: #333 !important;
  background-color: #fff !important;
}

/* ── Scrollbar : blend with dark surroundings ─────────────────────────────
   Chainlit ships a 4px native scrollbar with thumb
   `hsl(var(--muted-foreground) / .3)`. Against the dark-mode background
   (`hsl(0 0% 13%)`) that resolves to light-grey-on-dark, which makes the
   chat scrollbar conspicuously visible and its "stops at the input"
   boundary jarring. We tighten the thumb in dark mode only so the bar
   sits near-invisible against the surrounding surface while staying
   grabbable on hover. Light mode keeps chainlit's default — UX feedback
   says the issue is barely noticeable there.

   We do NOT touch the scrollable container's height — extending it past
   the input requires class names that change per build and has hidden
   message actions in past attempts. The blended thumb is the safe path. */
html.dark ::-webkit-scrollbar-thumb {
  background-color: hsl(var(--muted-foreground) / .10);
}
html.dark ::-webkit-scrollbar-thumb:hover {
  background-color: hsl(var(--muted-foreground) / .28);
}

/* Firefox: `scrollbar-color` is inherited from the root. We override at
   `html.dark` for global effect AND on `.custom-scrollbar` (the class
   chainlit applies to its tighter-styled scrollable areas) so the value
   wins specificity over chainlit's own rule. */
html.dark,
html.dark .custom-scrollbar {
  scrollbar-color: hsl(0 0% 71% / .10) transparent;
}

/* ── Sticky progress bar : phase tracker ───────────────────────────────────
   Painted by public/scripts/ui-overrides.js (`progressBar` IIFE). Hairline
   gradient bar at the very top of the viewport + small pill in the top-
   right corner with the phase label and percentage. Hidden until the first
   `data-phase` marker is observed in an assistant message.
─────────────────────────────────────────────────────────────────────────── */
#sage-progress {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 9000;
  pointer-events: none;
}

#sage-progress__track {
  height: 3px;
  width: 100%;
  background: rgba(79, 110, 247, 0.10);
}

#sage-progress__fill {
  height: 100%;
  width: 0%;
  background: linear-gradient(90deg, #4f6ef7 0%, #7c3aed 100%);
  box-shadow: 0 0 6px rgba(124, 58, 237, 0.40);
  transition: width 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}

#sage-progress__pill {
  position: absolute;
  /* Centered at top, just below the 3px gradient bar. Top-right was tried
     first but overlapped chainlit's user-avatar dropdown (and its expanded
     menu); top-center is the only zone consistently clear of header chrome
     across chainlit versions. */
  top: 8px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 11px;
  font-weight: 500;
  line-height: 1;
  padding: 5px 10px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.92);
  color: #4a4a6a;
  border: 1px solid rgba(79, 110, 247, 0.18);
  box-shadow: 0 2px 8px rgba(31, 31, 56, 0.08);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  letter-spacing: 0.01em;
  pointer-events: auto;
  user-select: none;
}

html.dark #sage-progress__track {
  background: rgba(255, 255, 255, 0.06);
}

html.dark #sage-progress__pill {
  background: rgba(28, 28, 44, 0.85);
  color: #d8d8e8;
  border-color: rgba(124, 58, 237, 0.28);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.30);
}

/* When the synthesis phase completes, switch the pill to a subtle "done"
   accent so the user sees the run finished without having to read the
   percentage. */
#sage-progress__pill[data-status="complete"] {
  background: linear-gradient(90deg, rgba(79, 110, 247, 0.18), rgba(124, 58, 237, 0.18));
  border-color: rgba(124, 58, 237, 0.40);
}

/* Collapse the chainlit CustomElement wrapper around PhaseMarker — the
   element exists only to carry the phase signal; any chrome (margin,
   padding, "Element" caption) chainlit injects around it would leave a
   visible gap in the message bubble. Modern :has() lets us target the
   nearest ancestor that owns this invisible marker. */
.sage-phase-marker {
  display: none !important;
}
*:has(> .sage-phase-marker),
.element-container:has(.sage-phase-marker),
[class*="element"]:has(> .sage-phase-marker) {
  display: none !important;
  margin: 0 !important;
  padding: 0 !important;
  height: 0 !important;
}

/* ── "Thinking…" loader shimmer ─────────────────────────────────────────────
   `src/n8n_client.py` envoie un `cl.Message(content="Thinking…")` comme
   placeholder pendant l'attente n8n. L'IIFE `sageThinkingShimmer` dans
   `public/scripts/ui-overrides.js` pose la classe `sage-thinking-shimmer`
   sur le parent direct du nœud texte.

   On combine DEUX effets, tous deux en `!important` pour gagner les
   batailles de spécificité contre les règles Chainlit/Tailwind :

   1. Sweep gradient (effet principal) : texte rendu transparent et rempli
      par un gradient horizontal qui défile gauche→droite (`background-clip:
      text`). Très visible mais finicky — certaines règles ancêtres peuvent
      neutraliser `background-clip` ou `-webkit-text-fill-color`.

   2. Pulse d'opacité (fallback bulletproof) : même si le gradient échoue,
      l'opacité bat de 0.3 à 1.0 — l'utilisateur voit le mot "Thinking…"
      respirer. Toujours visible tant que la classe est posée.

   Si vraiment AUCUN des deux n'est visible, c'est que la classe n'est pas
   posée du tout (problème côté JS, pas CSS). */
@keyframes sage-thinking-sweep {
  0%   { background-position: 200% center; }
  100% { background-position: -200% center; }
}
@keyframes sage-thinking-pulse {
  0%, 100% { opacity: 0.30; }
  50%      { opacity: 1.00; }
}
.sage-thinking-shimmer {
  background-image: linear-gradient(
    90deg,
    #9aa0a6 0%,
    #9aa0a6 40%,
    #ffffff 50%,
    #9aa0a6 60%,
    #9aa0a6 100%
  ) !important;
  background-size: 200% 100% !important;
  -webkit-background-clip: text !important;
          background-clip: text !important;
  -webkit-text-fill-color: transparent !important;
  color: transparent !important;
  font-weight: 500 !important;
  animation:
    sage-thinking-sweep 1.8s linear infinite,
    sage-thinking-pulse 1.4s ease-in-out infinite !important;
}
html:not(.dark) .sage-thinking-shimmer {
  background-image: linear-gradient(
    90deg,
    #6b6f76 0%,
    #6b6f76 40%,
    #111111 50%,
    #6b6f76 60%,
    #6b6f76 100%
  ) !important;
}
