/* Scuderia — self-contained dark UI, no framework. Full-height 3-pane layout. */

:root {
  --bg: #0f0f10;
  --pane: #161618;
  --pane-2: #1c1c1f;
  --bd: #2a2a2e;
  --text: #e8e8ea;
  --muted: #8a8a90;
  --accent: #6c8aff;
  --accent-soft: rgba(108, 138, 255, 0.14);
  --danger: #ff6b6b;
  --hover-bg: rgba(255, 255, 255, 0.07);
  --c-folder: #ffe000;
  --c-doc: #4a82d6;
  --c-img: #c084fc;
  --c-csv: #34d399;
  --c-code: #fbbf24;
  --c-zip: #fb923c;
  --c-ppt: #ea580c;
  --c-pdf: #ff6b6b;
  --thinking: #f5b324;
  --rail-w: 52px;
  --rail-bg: var(--pane);
  --rail-border: var(--bd);
  --rail-fg: var(--muted);
  --rail-hover: var(--pane-2);
  --rail-hover-fg: var(--text);
  --rail-active-bg: var(--accent-soft);
  --rail-active-fg: var(--accent);
  --panel-w: 280px;
  --right-w: 360px;
  --radius: 10px;
}

/* ------------------------------------------------------------- themes
   Standard dark is the default (:root above, kept as-is). Scuderia (rosso
   corsa on carbon black) + Scuderia Clair (crema) override the vars here.
   The default mode is "auto": resolves to the Scuderia pair by OS preference
   (dark → scuderia, light → scuderia-clair); Standard stays a manual option.
   PDF keeps a universal red (--c-pdf) so it never collides with the orange
   danger used by the Scuderia themes. */
[data-theme="scuderia"] {
  --bg: #0c0c0e;
  --pane: #141417;
  --pane-2: #1c1c20;
  --bd: #2e2e33;
  --text: #f1eee9;
  --muted: #84807a;
  --accent: #e10600;
  --accent-soft: rgba(225, 6, 0, 0.18);
  --danger: #ff7a1a;
  --hover-bg: rgba(255, 255, 255, 0.07);
  --rail-bg: #e10600;
  --rail-border: transparent;
  --rail-fg: rgba(255, 255, 255, 0.72);
  --rail-hover: rgba(0, 0, 0, 0.16);
  --rail-hover-fg: #fff;
  --rail-active-bg: rgba(0, 0, 0, 0.28);
  --rail-active-fg: #fff;
}
[data-theme="scuderia-clair"] {
  --bg: #f4f4f5;
  --pane: #ffffff;
  --pane-2: #ececef;
  --bd: #d4d4d8;
  --text: #1a1a1c;
  --muted: #6b6b72;
  --accent: #d40000;
  --accent-soft: rgba(212, 0, 0, 0.12);
  --danger: #d9480f;
  --c-folder: #ffe000; /* Modena yellow — matches the logo shield (rail-logo / icon.svg) */
  --hover-bg: rgba(0, 0, 0, 0.06);
  --rail-bg: #d40000;
  --rail-border: transparent;
  --rail-fg: rgba(255, 255, 255, 0.72);
  --rail-hover: rgba(0, 0, 0, 0.16);
  --rail-hover-fg: #fff;
  --rail-active-bg: rgba(0, 0, 0, 0.28);
  --rail-active-fg: #fff;
}

* { box-sizing: border-box; margin: 0; padding: 0; }
/* Dark thin scrollbars everywhere, in theme with the rest of the UI. */
* { scrollbar-width: thin; scrollbar-color: var(--bd) transparent; }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb { background: var(--bd); border-radius: 6px; border: 2px solid transparent; background-clip: padding-box; }
*::-webkit-scrollbar-thumb:hover { background: var(--muted); background-clip: padding-box; }
html, body { height: 100%; }
body {
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background: var(--bg);
  color: var(--text);
  font-size: 15px;
  line-height: 1.5;
  -webkit-text-size-adjust: 100%;
  overflow: hidden;
}
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }
input, textarea {
  font: inherit; color: inherit;
  background: var(--pane-2);
  border: 1px solid var(--bd);
  border-radius: var(--radius);
  padding: 0.55rem 0.7rem;
  width: 100%;
}
input:focus, textarea:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
ul { list-style: none; }
/* [hidden] must win over display:flex/grid rules set on the same element (classic gotcha). */
[hidden] { display: none !important; }
.muted { color: var(--muted); }
.small { font-size: 0.8rem; }
.pad { padding: 0.6rem; }

/* icons */
.ic { width: 1.15em; height: 1.15em; display: inline-block; vertical-align: -0.2em; }

/* ---------------------------------------------------------------- layout */
.app { display: flex; height: 100vh; height: 100dvh; overflow: hidden; }

/* ----------------------------------------------------------- left sidebar */
.sidebar { display: flex; flex: 0 0 auto; height: 100%; z-index: 26; }

.rail {
  width: var(--rail-w); flex: 0 0 var(--rail-w); height: 100%;
  background: var(--rail-bg); border-right: 1px solid var(--rail-border);
  display: flex; flex-direction: column; align-items: center;
  padding: 0.5rem 0; gap: 0.25rem;
}
.rail-logo {
  width: 40px; height: 40px;
  display: inline-flex; align-items: center; justify-content: center;
  margin-bottom: 0.4rem;
}
.rail-logo-svg { width: 30px; height: 30px; display: block; }
.rail-nav { display: flex; flex-direction: column; gap: 0.2rem; width: 100%; align-items: center; }
.rail-btn {
  width: 40px; height: 40px; border-radius: 11px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 1.1rem; color: var(--rail-fg);
}
.rail-btn:hover { background: var(--rail-hover); color: var(--rail-hover-fg); }
.rail-btn.active { background: var(--rail-active-bg); color: var(--rail-active-fg); }
/* Desktop: hide the mobile-only close button and pin versions + settings to
   the bottom of the rail as a centered column (mobile reflows them into a
   bottom bar). Without this, #rail-close leaks into the desktop flow and the
   bottom buttons drift off-center — the wrapper broke the original
   margin-top:auto that pinned them when they were direct rail children. */
.rail-close { display: none; }
.rail-bottom { margin-top: auto; display: flex; flex-direction: column; align-items: center; width: 100%; }
/* Versions (history) + settings pinned to the bottom of the rail. Versions is
   intentionally low-contrast so the primary nav (conversations/memory) stands out;
   it brightens on hover and is full-opacity when active. */
#rail-versions { margin-top: auto; opacity: 0.5; }
#rail-versions:hover { opacity: 0.85; }
#rail-versions.active { opacity: 1; }
#rail-settings { margin-top: 0.2rem; }

.panel {
  width: var(--panel-w); flex: 0 0 var(--panel-w); height: 100%;
  background: var(--pane); border-right: 1px solid var(--bd);
  display: none; flex-direction: column; overflow: hidden;
}
.sidebar.expanded .panel { display: flex; }
.panel-head { flex: 0 0 auto; padding: 0.7rem 0.8rem; border-bottom: 1px solid var(--bd); display: flex; align-items: center; gap: 0.5rem; min-height: calc(32px + 1.4rem); }
.panel-head .brand { font-size: 1.05rem; font-weight: 600; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.navcontent { display: none; flex: 1; min-height: 0; flex-direction: column; overflow: hidden; }
.navcontent.active { display: flex; }
.navlist { flex: 1; overflow-y: auto; padding: 0.3rem; display: flex; flex-direction: column; gap: 2px; }

/* new chat button + archive toggle row */
.head-new {
  flex: 0 0 auto; width: 32px; height: 32px; min-width: 32px; display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--radius); background: var(--accent); color: #fff; font-size: 1rem;
}
.head-new:hover { filter: brightness(1.08); }
.iconbtn { flex: 0 0 auto; width: 38px; display: inline-flex; align-items: center; justify-content: center; border-radius: var(--radius); color: var(--muted); background: var(--pane-2); }
.iconbtn:hover { color: var(--text); background: var(--pane); }
.iconbtn.on { color: var(--accent); background: var(--accent-soft); }

/* project tag bar */
.tagbar { display: flex; flex-wrap: wrap; align-items: center; gap: 0.3rem; padding: 0.5rem; border-bottom: 1px solid var(--bd); flex: 0 0 auto; }
/* Global conversation search: a sticky search field above a result list. Mirrors
   the tagbar layout (border-bottom + flex: 0 0 auto) so the field stays pinned
   while results scroll under it. */
.searchbar { display: flex; align-items: center; gap: 0.4rem; padding: 0.5rem; border-bottom: 1px solid var(--bd); flex: 0 0 auto; }
.searchbar .search-ic { width: 16px; height: 16px; color: var(--muted); flex: 0 0 auto; }
.searchbar input { flex: 1; min-width: 0; background: var(--pane-2); border: 1px solid var(--bd); border-radius: 8px; padding: 0.4rem 0.5rem; font-size: 0.85rem; color: var(--text); }
.searchbar input:focus { outline: none; border-color: var(--accent); }
.search-clear { flex: 0 0 auto; width: 22px; height: 22px; display: inline-flex; align-items: center; justify-content: center; color: var(--muted); border-radius: 6px; }
.search-clear:hover { color: var(--text); background: var(--pane-2); }
/* A result row: a clickable button showing the conversation title (wrapped to
   up to 2 lines so the full title is visible — the essential info) with the
   last-message date discreetly below. Most recent first. Styled like the
   conversations list for visual consistency. */
.search-result { display: flex; flex-direction: column; gap: 0.12rem; width: 100%; text-align: left; padding: 0.5rem 0.6rem; border-radius: 9px; border: 1px solid transparent; background: none; cursor: pointer; font-size: 0.86rem; }
.search-result:hover { background: var(--pane-2); }
.search-label { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.search-date { font-size: 0.72rem; color: var(--muted); }
.search-loading { padding: 0.5rem 0.6rem; }
.tags { display: contents; } /* tag children flow directly into the tagbar flex */
.tag {
  display: inline-flex; align-items: center; gap: 0.28rem;
  padding: 0.2rem 0.55rem; border-radius: 999px; font-size: 0.75rem;
  border: 1px solid var(--bd); background: var(--pane-2);
}
.tag:hover { border-color: var(--accent); }
.tag.on { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }
.tag .tag-dot { display: inline-block; width: 12px; height: 12px; min-width: 12px; border-radius: 50%; border: 1px solid rgba(255,255,255,0.25); cursor: pointer; }
.tag .tag-dot:hover { transform: scale(1.25); }
.tag .tag-del { display: none; margin-left: auto; align-self: center; padding: 0.1rem 0.2rem; color: var(--muted); cursor: pointer; border-radius: 4px; line-height: 0; }
.tag .tag-del svg { width: 13px; height: 13px; }
.tag:hover .tag-del { display: inline-flex; }
.tag .tag-del:hover { color: var(--danger); }

/* color picker popover */
.color-popover { position: fixed; z-index: 60; display: flex; gap: 0.3rem; padding: 0.45rem; background: var(--pane); border: 1px solid var(--bd); border-radius: 10px; box-shadow: 0 8px 24px rgba(0,0,0,0.5); flex-wrap: wrap; max-width: 220px; }
.swatch:hover { transform: scale(1.15); border-color: var(--text); }
.swatch-auto { background: conic-gradient(#6c8aff,#b36cff,#ff6cb5,#ff6b6b,#ff9f40,#f5c518,#5fd17a,#2dd4bf,#6c8aff); }
.swatch { width: 22px; height: 22px; border-radius: 50%; border: 1px solid rgba(255,255,255,0.25); cursor: pointer; }

/* per-conversation tag picker popover */
.tag-popover { position: fixed; z-index: 60; width: 220px; background: var(--pane); border: 1px solid var(--bd); border-radius: 10px; box-shadow: 0 8px 24px rgba(0,0,0,0.5); padding: 0.4rem; display: flex; flex-direction: column; gap: 0.35rem; }
.popover-title { padding: 0.2rem 0.4rem; text-transform: uppercase; letter-spacing: 0.05em; }
.popover-list { display: flex; flex-direction: column; gap: 2px; max-height: 220px; overflow-y: auto; }
.popover-item { display: flex; width: 100%; align-items: center; gap: 0.5rem; padding: 0.4rem 0.5rem; border-radius: 8px; font-size: 0.85rem; text-align: left; }
.popover-item:hover { background: var(--pane-2); }
.popover-item .check { width: 16px; flex: 0 0 16px; color: var(--accent); font-size: 0.85rem; }
.popover-item .tag-dot { width: 10px; height: 10px; min-width: 10px; border: 1px solid rgba(255,255,255,0.2); }
.popover-item .popover-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.popover-form { display: flex; gap: 0.3rem; margin-top: 0.15rem; }
.popover-form .popover-input { flex: 1; min-width: 0; }
.popover-input { padding: 0.35rem 0.5rem; font-size: 0.8rem; }
/* Subtle cancel button used in popover sub-forms (e.g. rename). Full-width,
 *   low-emphasis so the primary action (Save / submit check) stands out. */
.ghostbtn { width: 100%; padding: 0.4rem 0.5rem; border-radius: 8px; font-size: 0.85rem; text-align: center; color: var(--muted); background: transparent; border: 1px solid transparent; }
.ghostbtn:hover { color: var(--text); background: var(--pane-2); }
.popover-sep { height: 1px; background: var(--bd); margin: 0.25rem 0.1rem; }
.popover-action { display: flex; width: 100%; align-items: center; gap: 0.5rem; padding: 0.4rem 0.5rem; border-radius: 8px; font-size: 0.85rem; text-align: left; color: var(--text); }
.popover-action:hover { background: var(--pane-2); }
.popover-action .ic { width: 16px; height: 16px; color: var(--muted); }
.tag-add { padding: 0.2rem; line-height: 0; }
.inline-form { flex: 1 1 100%; display: flex; gap: 0.3rem; }
.inline-form input { flex: 1; padding: 0.35rem 0.5rem; font-size: 0.8rem; }
.addbtn { width: 34px; flex: 0 0 34px; border: 1px solid var(--bd); border-radius: var(--radius); display: inline-flex; align-items: center; justify-content: center; font-size: 1rem; }

/* conversation rows */
.convo-row { display: flex; gap: 2px; align-items: stretch; border-radius: 9px; border: 1px solid transparent; }
.convo-row:hover { background: var(--pane-2); }
.convo-row.active { border-color: var(--accent); background: var(--accent-soft); }
.convo-row.archived { opacity: 0.6; }
.convo-row.archived .label { font-style: italic; }
.convo { flex: 1; min-width: 0; text-align: left; padding: 0.5rem 0.6rem; font-size: 0.86rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.convo .label { display: block; overflow: hidden; text-overflow: ellipsis; }
.convo-del { flex: 0 0 26px; display: inline-flex; align-items: center; justify-content: center; opacity: 0; color: var(--muted); border-radius: 9px; }
.convo-row:hover .convo-del, .convo-row.active .convo-del { opacity: 0.5; }
.convo-del:hover { opacity: 1 !important; color: var(--danger); }
.convo-more { flex: 0 0 26px; display: inline-flex; align-items: center; justify-content: center; opacity: 0; color: var(--muted); border-radius: 9px; }
.convo-row:hover .convo-more, .convo-row.active .convo-more { opacity: 0.5; }
.convo-more:hover { opacity: 1 !important; color: var(--text); }

#versions-empty { padding: 0.6rem; } /* legacy <p> empty state still using .pad */
/* Left-pane empty state reuses .ws-empty (icon + centered) but drops the top
   margin: the sidebar's headers (panel-head + tagbar) are ~1.5rem taller than
   the workspace's (toolbar + breadcrumb), so margin-top:0 lines the message up
   vertically with the workspace's empty state (which has margin-top 1.3rem). */
#convos-empty.ws-empty { margin-top: 0; }
/* Skills & Crons panes have only a panel-head (no tagbar) above their content,
   ~2.45rem less than the Conversations pane. Compensate so their empty state
   lines up vertically with #convos-empty and the workspace's .ws-empty. */
#skills-empty.ws-empty, #crons-empty.ws-empty { margin-top: 2.45rem; }

.navitem { display: flex; width: 100%; align-items: center; gap: 0.4rem; padding: 0.45rem 0.55rem; border-radius: 8px; font-size: 0.85rem; text-align: left; }
.navitem:hover { background: var(--pane-2); }
.navitem .ic { opacity: 0.6; }
.navitem .navprefix { opacity: 0.6; }

/* ------------------------------------------------------------- chat center */
.chat { flex: 1; min-width: 0; height: 100%; display: flex; flex-direction: column; background: var(--bg); }
.chat-view { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.memory-pane { flex: 1; min-height: 0; display: flex; flex-direction: column; background: var(--pane); }
/* Center "fiche" panes (memory, and later skills/crons editors) sit on a faintly
   lighter surface than the chat (--pane vs --bg) so they read as a distinct
   document surface, not a continuation of the conversation list. */
/* tag pills in the conversation list (dot + name, click to filter) */
.convo .ctags { display: flex; flex-wrap: wrap; gap: 0.25rem; margin-top: 0.2rem; }
.convo-tag { display: inline-flex; align-items: center; gap: 0.25rem; padding: 0.05rem 0.4rem 0.05rem 0.12rem; border-radius: 999px; border: 1px solid transparent; font-size: 0.7rem; color: var(--muted); }
.convo-tag .convo-dot { width: 8px; height: 8px; flex: 0 0 8px; border-radius: 50%; border: 1px solid rgba(255,255,255,0.2); display: inline-block; }
.convo-tag.active { border-color: var(--text); color: var(--text); }

.messages { flex: 1; overflow-y: auto; padding: 0.8rem; display: flex; flex-direction: column; gap: 0.7rem; }
/* Empty-chat welcome state: a single discreet use-case suggestion shown
   when #messages is empty on a fresh session. No card/border/badge — just
   muted text on the background (gris sur noir in Scuderia dark), clickable to
   fill the prompt. updateWelcome() collapses #messages (display:none) while the
   welcome is shown so the two never compete for the column height. */
.welcome { flex: 1; overflow-y: auto; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.9rem; padding: 1.2rem 0.9rem; text-align: center; }
.welcome[hidden] { display: none; }
.usecase { display: inline-flex; align-items: center; gap: 0.5rem; text-align: left; padding: 0.3rem 0.4rem; border: none; background: none; color: var(--muted); cursor: pointer; font-size: 0.9rem; line-height: 1.35; max-width: 34ch; }
.usecase:hover { color: var(--text); }
.usecase-ic { flex: 0 0 auto; width: 18px; height: 18px; color: inherit; opacity: 0.9; }
.usecase-ic svg { width: 18px; height: 18px; display: block; }
.usecase-label { flex: 1; min-width: 0; }
.usecase-cat { flex: 0 0 auto; font-size: 0.62rem; text-transform: uppercase; letter-spacing: 0.05em; padding: 0.08rem 0.38rem; border-radius: 99px; color: var(--muted); background: var(--pane-2); opacity: 0.85; }
.welcome-hide { background: none; border: none; color: var(--muted); opacity: 0.6; font-size: 0.72rem; cursor: pointer; text-decoration: underline; text-underline-offset: 3px; padding: 0.2rem 0.5rem; }
.welcome-hide:hover { color: var(--text); opacity: 1; }
/* Settings toggle (Theme tab): startup suggestions checkbox. */
.settings-toggle { display: flex; align-items: center; gap: 0.5rem; margin-top: 1rem; font-size: 0.88rem; color: var(--text); cursor: pointer; }
.settings-toggle input { width: 16px; height: 16px; accent-color: var(--accent); }
.msg { max-width: 88%; padding: 0.65rem 0.85rem; border-radius: 14px; white-space: pre-wrap; word-wrap: break-word; line-height: 1.5; }
.msg.user { background: var(--accent-soft); align-self: flex-end; border-bottom-right-radius: 4px; }
.msg.assistant { background: var(--pane); border: 1px solid var(--bd); align-self: flex-start; border-bottom-left-radius: 4px; }
/* Archived messages (summarized by compaction): dimmed so the user sees what
   was condensed, but visually subordinate to the kept/new messages below the
   compaction chip. Retry/Edit are already omitted in JS (they make no sense on
   summarized history); Copy stays so the user can still grab old content. */
.msg.archived { opacity: 0.45; }
.msg .role { font-size: 0.68rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.25rem; display: flex; align-items: center; gap: 0.34em; }
/* Assistant role badge: Italian tricolore (green–white–red) as a single
   oblique parallelogram (sportscar-badge vibe), inline before the "Scuderia"
   name. skewX leans the top to the right; the three bands stay parallel and
   vertical relative to each other. White band uses #f0f0f2 to read as white
   yet stay visible on the white pane of the Scuderia Clair theme. */
.msg .role-flag { width: 1.4rem; height: 0.48rem; flex: 0 0 auto; transform: skewX(-15deg); overflow: hidden; border-radius: 2px; }
.msg.tool, .msg.bash { font-family: ui-monospace, monospace; font-size: 0.78rem; color: var(--muted); background: var(--pane-2); border: 1px dashed var(--bd); max-width: 95%; }
.toolchip { font-size: 0.76rem; color: var(--muted); font-family: ui-monospace, monospace; margin: 0.2rem 0; display: flex; align-items: center; gap: 0.3rem; }
.toolchip .ic { width: 13px; height: 13px; flex: 0 0 13px; display: inline-flex; align-items: center; justify-content: center; line-height: 0; }
.toolchip .ic svg { width: 100%; height: 100%; display: block; }
.toolchip-domain { color: var(--text); opacity: 0.82; font-weight: 500; }
.toolchip-tokens { display: none; color: var(--muted); opacity: 0.7; font-weight: 400; }
body.ctx-warn .toolchip-tokens { display: inline; }
.toolchip.busy .ic { color: var(--accent); }
.toolchip.busy .ic svg { animation: spin 1.1s linear infinite; transform-box: fill-box; transform-origin: center; }
.toolchip.busy::after { content: " …"; }

/* Status banner shown at the compaction cut point in the transcript, so the
   user sees the conversation was summarized (the old bubbles are gone,
   replaced by a compact version). Collapsible: click the header to reveal the
   summary text the model sees as context. */
.compaction-banner { align-self: stretch; margin: 0.25rem 0 0.5rem; }
.compaction-header { display: flex; align-items: center; gap: 0.4rem; width: fit-content; margin: 0 auto; padding: 0.35rem 0.8rem; font-size: 0.78rem; color: var(--muted); background: var(--pane-2); border: 1px dashed var(--bd); border-radius: 999px; cursor: pointer; transition: color 0.15s; }
.compaction-header:hover { color: var(--text); }
.compaction-header .ic { width: 14px; height: 14px; flex: 0 0 14px; color: var(--accent); display: inline-flex; align-items: center; justify-content: center; line-height: 0; }
.compaction-header .ic svg { width: 100%; height: 100%; display: block; }
.compaction-chevron { width: 12px; height: 12px; flex: 0 0 12px; display: inline-flex; align-items: center; justify-content: center; }
.compaction-chevron .ic { width: 100%; height: 100%; display: block; transform-box: fill-box; transform-origin: center; transition: transform 0.15s; }
.compaction-header.open .compaction-chevron .ic { transform: rotate(90deg); }
.compaction-body { margin-top: 0.4rem; padding: 0.6rem 0.85rem; background: var(--pane-2); border: 1px solid var(--bd); border-radius: 10px; font-size: 0.85rem; line-height: 1.5; color: var(--muted); max-height: 400px; overflow-y: auto; }
.compaction-body .md-body { color: var(--muted); }
.compaction-body .md-body p { margin: 0.3rem 0; }
.compaction-body .md-body p:first-child { margin-top: 0; }
.compaction-body .md-body p:last-child { margin-bottom: 0; }
@keyframes spin { to { transform: rotate(360deg); } }
.cursor::after { content: "▋"; animation: blink 1s steps(2) infinite; color: var(--accent); }
@keyframes blink { 50% { opacity: 0; } }

/* "Thinking" indicator shown in the assistant bubble before the first token
   arrives (or before a tool starts). Brain icon pulses, three dots bounce. */
.thinking { display: inline-flex; align-items: center; gap: 0.45rem; color: var(--muted); font-size: 0.82rem; padding: 0.1rem 0; }
.thinking .ic { width: 16px; height: 16px; color: var(--thinking); animation: idea-pulse 1.5s ease-in-out infinite; transform-origin: center; filter: drop-shadow(0 0 3px var(--thinking)); }
/* Phase title shown next to "Réflexion…" while the model reasons. Replaced in
   place (textContent swap, same span) as each phase streams — never appended.
   Discreet: muted, slightly smaller, with a soft separator dot so it reads as a
   continuation of the label rather than a second line. Empty by default so the
   label sits alone until the first phase header arrives. */
.thinking-title { color: var(--muted); font-size: 0.78rem; opacity: 0.7; max-width: 22rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.thinking-title:empty { display: none; }
.thinking-title:not(:empty)::before { content: "·"; margin-right: 0.35rem; opacity: 0.6; }
.thinking-dots { display: inline-flex; gap: 0.18rem; align-items: center; }
.thinking-dots span { width: 4px; height: 4px; border-radius: 50%; background: currentColor; opacity: 0.3; animation: dot-bounce 1.2s ease-in-out infinite; }
.thinking-dots span:nth-child(2) { animation-delay: 0.18s; }
.thinking-dots span:nth-child(3) { animation-delay: 0.36s; }
@keyframes idea-pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.18); } }
@keyframes dot-bounce { 0%, 60%, 100% { opacity: 0.3; transform: translateY(0); } 30% { opacity: 1; transform: translateY(-3px); } }

/* Wrapper holding a bubble + its action row (actions sit UNDER the bubble,
   not inside it). Aligns the whole group to the sender's side. */
.msg-row { display: flex; flex-direction: column; gap: 0.2rem; }
.msg-row.user { align-self: flex-end; align-items: flex-end; }
.msg-row.assistant { align-self: flex-start; align-items: flex-start; }

/* Per-message action buttons (Retry / Edit / Copy) shown under each bubble.
   Discrete: icon-only, faded until the row is hovered. */
.msg-actions { display: flex; gap: 0.1rem; justify-content: flex-end; }
.msg-action { font-size: 0.78rem; color: var(--muted); display: inline-flex; align-items: center; justify-content: center; width: 1.6rem; height: 1.6rem; border-radius: 7px; opacity: 0.4; transition: opacity 0.12s, background 0.12s; }
.msg-action .ic { width: 1em; height: 1em; }
.msg-row:hover .msg-action { opacity: 0.7; }
.msg-action:hover { color: var(--text); background: var(--hover-bg); opacity: 1; }
.msg-action.primary { color: var(--accent); }
/* Per-message timestamp, left-aligned in the actions row. Very discreet: small,
   muted, low opacity until the row is hovered — same reveal pattern as the
   action buttons so the transcript stays calm. */
.msg-time { margin-right: auto; font-size: 0.68rem; color: var(--muted); opacity: 0.3; transition: opacity 0.12s; align-self: center; }
.msg-row:hover .msg-time { opacity: 0.7; }
.msg-action.primary:hover { background: var(--accent-soft); }
.msg-action.copied { color: var(--accent); opacity: 1; }
/* Dim + disable actions while a response is streaming. */
body.streaming .msg-action { opacity: 0.35; pointer-events: none; }
/* Inline editor shown in place of the edited user bubble. */
.msg-edit-area { width: 100%; resize: none; min-height: 44px; max-height: 320px; background: var(--bg); }
.msg-edit-area:focus { outline: none; border-color: var(--accent); }
.msg.user.editing { outline: 1px solid var(--accent); outline-offset: 2px; }

.composer { flex: 0 0 auto; display: flex; gap: 0.4rem; align-items: flex-end; padding: 0.7rem; border-top: 1px solid var(--bd); background: var(--pane); }
.composer textarea { flex: 1; resize: none; max-height: 38vh; min-height: 44px; }
.sendbtn { flex: 0 0 auto; width: 44px; height: 44px; border-radius: var(--radius); background: var(--accent); color: #fff; display: inline-flex; align-items: center; justify-content: center; font-size: 1.15rem; }
.sendbtn:hover { filter: brightness(1.08); }
.sendbtn.danger { background: var(--danger); }
/* In Scuderia dark the Stop button matches the deep red of user message
   bubbles (var(--accent-soft) composited over the carbon-black surface)
   rather than the orange danger token, so it belongs to the conversation. */
[data-theme="scuderia"] .sendbtn.danger { background: var(--accent-soft); }
/* Dictation (Speech-to-Text) button. Neutral at rest so it doesn't compete
   with Send; turns into a pulsing red badge while recording so the user knows
   the mic is live. Built on .sendbtn to match the composer's geometry. */
.sendbtn.mic { background: var(--pane-2); color: var(--muted); }
.sendbtn.mic:hover { color: var(--text); }
.sendbtn.mic.recording { background: var(--danger); color: #fff; animation: mic-pulse 1.4s ease-in-out infinite; }
@keyframes mic-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255, 107, 107, 0.45); }
  50% { box-shadow: 0 0 0 7px rgba(255, 107, 107, 0); }
}

/* Context-size gauge: thin bar above the composer, silent (hidden) while light.
 * Appears at average (amber dot, informational) and heavy (red dot + action). */
.context-gauge { flex: 0 0 auto; display: flex; align-items: center; gap: 0.5rem; padding: 0.45rem 0.8rem; font-size: 0.82rem; line-height: 1.3; border-top: 1px solid var(--bd); background: var(--pane); }
.context-gauge .gauge-bar { flex: 0 0 auto; width: 64px; height: 6px; border-radius: 3px; background: var(--bd); overflow: hidden; }
.context-gauge .gauge-fill { height: 100%; width: 0; border-radius: 3px; transition: width 0.3s ease; }
.context-gauge.avg .gauge-fill { background: #f0ad4e; }
.context-gauge.heavy .gauge-fill { background: var(--danger); }
.context-gauge .gauge-pct { flex: 0 0 auto; color: var(--muted); font-variant-numeric: tabular-nums; min-width: 2.4em; text-align: right; }
.context-gauge .gauge-text { flex: 1; min-width: 0; }
.context-gauge .compact-btn { flex: 0 0 auto; padding: 0.3rem 0.7rem; font-size: 0.8rem; border-radius: var(--radius); background: var(--accent); color: #fff; border: none; cursor: pointer; }
.context-gauge .compact-btn:hover { filter: brightness(1.08); }
.context-gauge .compact-btn:disabled { opacity: 0.6; cursor: default; filter: none; }

/* ----------------------------------------------------------- right workspace */
.workspace { display: flex; flex-direction: column; height: 100%; width: var(--right-w); flex: 0 0 var(--right-w); border-left: 1px solid var(--bd); background: var(--pane); }
.workspace.hidden { display: none; }

/* ------------------------------- resizable panes (desktop only) */
/* Thin drag handles between the sidebar/chat and chat/workspace. They update the
   --panel-w / --right-w CSS variables, which the desktop layout and the mobile
   media queries both read. Hidden by default; .show is toggled when the pane is
   open. On mobile the panes are overlay drawers, so resizing is disabled. */
.resize-handle { flex: 0 0 7px; width: 7px; height: 100%; cursor: col-resize; position: relative; z-index: 30; display: none; }
.resize-handle.show { display: block; }
.resize-handle::after { content: ""; position: absolute; top: 0; bottom: 0; left: 3px; width: 1px; border-radius: 1px; background: transparent; transition: background 0.12s ease; }
.resize-handle:hover::after, .resize-handle.dragging::after { background: var(--accent); }
body.resizing { cursor: col-resize; user-select: none; }
body.resizing * { cursor: col-resize !important; }
@media (max-width: 1023px) { .resize-handle { display: none !important; } }
.panehead { flex: 0 0 auto; display: flex; align-items: center; gap: 0.4rem; padding: 0.45rem 0.55rem; border-bottom: 1px solid var(--bd); }
.panehead .pathlabel { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.iconbtn { width: 32px; height: 32px; flex: 0 0 32px; display: inline-flex; align-items: center; justify-content: center; border-radius: 8px; border: 1px solid var(--bd); font-size: 0.95rem; }
.iconbtn:hover { background: var(--pane-2); }
.savebtn { flex: 0 0 auto; padding: 0.3rem 0.7rem; border: 1px solid var(--bd); border-radius: 8px; font-size: 0.8rem; }
.savebtn:hover { background: var(--pane-2); }
/* Auto-save indicator: a compact icon-only status that replaces the Save button.
   Smaller than the Save button (no text, no padding box). Shows a dimmed check
   when content is saved, a spinning glyph while a save is pending/in flight. */
.savestatus { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; color: var(--muted); }
.savestatus .ic { width: 16px; height: 16px; }
.savestatus.saving .ic { color: var(--accent); animation: spin 1s linear infinite; }

.filebrowser { flex: 1; overflow-y: auto; padding: 0.4rem; }
.breadcrumb { font-size: 0.78rem; color: var(--muted); padding: 0.3rem 0.5rem; display: flex; flex-wrap: wrap; align-items: center; gap: 0.2rem; }
.breadcrumb button { color: var(--accent); font-size: 0.78rem; }
.breadcrumb .crumb-root { font-family: ui-monospace, monospace; font-size: 0.9rem; }
.breadcrumb .sep { opacity: 0.5; }
/* Workspace toolbar (line 1): folder icon on the left, action buttons pushed right. */
.ws-toolbar .ws-title { flex: 0 0 auto; margin-right: auto; display: inline-flex; align-items: center; color: var(--muted); }
.ws-toolbar .ws-title .ic { width: 18px; height: 18px; }
/* Workspace path bar (line 2): breadcrumb when browsing, filepath row when a file is open. */
.ws-pathbar { flex: 0 0 auto; border-bottom: 1px solid var(--bd); }
.filepath-row { display: flex; align-items: center; gap: 0.3rem; padding: 0.35rem 0.5rem; }
.filepath-row .pathlabel { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.filelist { display: flex; flex-direction: column; gap: 2px; padding: 0 0.3rem; }
.ws-empty { display: flex; flex-direction: column; align-items: center; gap: 0.55rem; margin: 1.3rem 0.5rem; padding: 1.2rem 0.8rem; text-align: center; color: var(--muted); font-size: 0.8rem; line-height: 1.5; }
.ws-empty .ic { width: 1.9rem; height: 1.9rem; opacity: 0.3; }
.fileitem { display: flex; width: 100%; align-items: center; gap: 0.4rem; padding: 0.4rem 0.5rem; border-radius: 8px; border: 1px solid transparent; font-size: 0.85rem; text-align: left; }
.fileitem:hover { background: var(--pane-2); }
/* Per-type icons: each type has its own silhouette (see fileIconFor) and its
   own color so it reads at a glance at small sizes. Folders are filled solid
   (not just outlined) so they stand out from the many file silhouettes that
   otherwise read as plain outlines at a glance. All icons render at full
   opacity so their true colors show; the only exception is the ".." back-row
   chevron (ic-back), kept dimmed so it reads as a secondary nav affordance. */
.fileitem .ic.ic-back { opacity: 0.6; }
.fileitem .ic.ic-folder { color: var(--c-folder); }
.fileitem .ic.ic-folder path { fill: currentColor; }
.fileitem .ic.ic-doc { color: var(--c-doc); }
.fileitem .ic.ic-pdf { color: var(--c-pdf); }
.fileitem .ic.ic-img { color: var(--c-img); }
.fileitem .ic.ic-csv { color: var(--c-csv); }
.fileitem .ic.ic-code { color: var(--c-code); }
.fileitem .ic.ic-zip { color: var(--c-zip); }
.fileitem .ic.ic-ppt { color: var(--c-ppt); }
/* File row: the name button grows, the delete (x) button sits at the right and is
   subtle until hover so the list stays calm. */
.filerow { display: flex; align-items: center; gap: 0.2rem; border-radius: 8px; }
.filerow .fileitem { flex: 1; min-width: 0; }
.filerow .fileitem span:last-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.filerow-del, .filerow-dl, .filerow-ren { flex: 0 0 auto; width: 26px; height: 26px; display: inline-flex; align-items: center; justify-content: center; border-radius: 6px; border: 1px solid transparent; color: var(--muted); background: transparent; opacity: 0; transition: opacity 0.12s, color 0.12s, background 0.12s; }
.filerow:hover .filerow-del,
.filerow-del:focus-visible,
.filerow:hover .filerow-dl,
.filerow-dl:focus-visible,
.filerow:hover .filerow-ren,
.filerow-ren:focus-visible { opacity: 1; }
.filerow-del:hover { color: var(--danger, #e55); background: var(--pane-2); }
.filerow-dl:hover, .filerow-ren:hover { color: var(--accent); background: var(--pane-2); }
.filerow-del .ic, .filerow-dl .ic, .filerow-ren .ic { width: 14px; height: 14px; }
/* Touch devices have no hover: keep the row action buttons visible there. */
@media (hover: none) { .filerow-del, .filerow-dl, .filerow-ren { opacity: 0.6; } }
/* Inline rename input inside a file row (Enter commits, Esc cancels). */
.filerow-input { flex: 1; min-width: 0; height: 28px; padding: 0 0.5rem; font-size: 0.85rem; color: var(--text); background: var(--bg); border: 1px solid var(--accent); border-radius: 6px; outline: none; }
.filerow-input.invalid { border-color: var(--danger, #e55); }
/* Inline rename input in the pathbar (edits the basename only). */
.pathlabel-input { flex: 1; min-width: 0; height: 26px; padding: 0 0.4rem; font-size: 0.8rem; color: var(--text); background: var(--bg); border: 1px solid var(--accent); border-radius: 6px; outline: none; }
.pathlabel-input.invalid { border-color: var(--danger, #e55); }

/* Version history list (Versions pane). One row per commit, newest first. */
.versionrow { display: flex; width: 100%; align-items: center; gap: 0.4rem; padding: 0.5rem 0.55rem; border-radius: 8px; border: 1px solid transparent; font-size: 0.85rem; text-align: left; }
.versionrow:hover { background: var(--pane-2); }
.versionrow.current { border-color: var(--accent); background: var(--accent-soft); }
.versionrow .ic { opacity: 0.6; flex: 0 0 auto; }
.versionrow.current .ic { opacity: 1; color: var(--accent); }
.versionrow .vtime { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.versionbadge { flex: 0 0 auto; font-size: 0.68rem; padding: 0.1rem 0.45rem; border-radius: 99px; background: var(--accent-soft); color: var(--accent); text-transform: uppercase; letter-spacing: 0.04em; }

.editorwrap { flex: 1; min-height: 0; padding: 0.4rem; display: flex; }
.cm-host { flex: 1; border: 1px solid var(--bd); border-radius: var(--radius); overflow: hidden; }
.cm-host .cm-editor { height: 100%; }
.cm-host .cm-scroller { font-family: ui-monospace, monospace; }
/* CodeMirror gutters: the default theme paints a light grey band behind line
   numbers and fold markers, clashing with the dark editor surface. Make the
   gutter strip match the editor background and dim the numbers so they stay
   discreet (the active line keeps a more readable tone). */
.cm-host .cm-gutters { background: transparent; border-right: 1px solid var(--bd); }
.cm-host .cm-gutterElement { color: #55555d; }
.cm-host .cm-activeGutterElement { color: var(--muted); }

/* floating reveal button */
.floatbtn { position: fixed; top: 0.6rem; right: 0.6rem; z-index: 24; width: 40px; height: 40px; border-radius: 10px; border: 1px solid var(--bd); background: var(--pane); color: var(--text); display: inline-flex; align-items: center; justify-content: center; font-size: 1.05rem; }
.floatbtn:hover { background: var(--pane-2); }
/* Scuderia themes: the mobile floating buttons get the brand colors so they
   read clearly against the chat surface — burger on Modena yellow, folder on
   rosso corsa. Standard keeps the neutral pane-colored look. */
[data-theme="scuderia"] .mobile-burger,
[data-theme="scuderia-clair"] .mobile-burger { background: #ffe000; color: #000; border-color: rgba(0,0,0,0.18); }
[data-theme="scuderia"] #workspace-show,
[data-theme="scuderia-clair"] #workspace-show { background: #000; color: #fff; border-color: rgba(0,0,0,0.18); }
[data-theme="scuderia"] #mobile-new-chat,
[data-theme="scuderia-clair"] #mobile-new-chat { background: var(--accent); color: #fff; border-color: rgba(0,0,0,0.18); }
/* Grab handle shown at the top of the workspace bottom sheet on mobile. */
.sheet-handle { display: none; flex: 0 0 auto; height: 18px; position: relative; }
.sheet-handle::before { content: ""; position: absolute; top: 8px; left: 50%; transform: translateX(-50%); width: 36px; height: 4px; border-radius: 2px; background: var(--bd); }

/* file preview (markdown rendered, before entering edit mode) */
.file-preview { flex: 1; min-height: 0; overflow-y: auto; padding: 0.85rem 1rem; font-size: 0.9rem; line-height: 1.6; color: var(--text); }
/* Markdown rendered inside chat bubbles (assistant + user). Mirrors .file-preview. */
.md-body { white-space: normal; word-wrap: break-word; overflow-wrap: anywhere; }
.md-body > *:first-child { margin-top: 0; }
.md-body > *:last-child { margin-bottom: 0; }
.file-preview pre, .md-body pre { font-family: ui-monospace, monospace; font-size: 0.8rem; white-space: pre-wrap; word-break: break-word; background: var(--pane-2); border: 1px solid var(--bd); border-radius: var(--radius); padding: 0.6rem 0.7rem; overflow-x: auto; }
/* Inline preview for images / PDFs opened in the workspace editor. */
.media-preview { display: block; max-width: 100%; max-height: 100%; object-fit: contain; border-radius: var(--radius); margin: 0 auto; }
.file-preview embed.media-preview { width: 100%; height: 100%; min-height: 70vh; }
/* Sandboxed srcdoc iframe for standalone .html workspace files. White bg so a
   page that sets no background of its own still reads; border to frame it. */
.file-preview iframe.html-preview { width: 100%; min-height: 72vh; border: 1px solid var(--bd); border-radius: var(--radius); background: #fff; }
/* Placeholder for non-previewable binary files (xlsx, zip, ...). */
.binary-box { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.7rem; margin: 2rem auto; padding: 2rem 1.5rem; text-align: center; color: var(--muted); border: 1px dashed var(--bd); border-radius: var(--radius); max-width: 360px; }
.binary-box .ic { width: 36px; height: 36px; }
.binary-box .binary-label { margin: 0; }
/* Drop overlay shown while dragging files over the workspace browser. */
.filebrowser { position: relative; }
.drop-overlay { position: absolute; inset: 0; background: rgba(15,15,16,0.85); display: flex; align-items: center; justify-content: center; z-index: 5; }
.drop-overlay-inner { display: flex; flex-direction: column; align-items: center; gap: 0.6rem; color: var(--accent); }
.drop-overlay-inner .ic { width: 32px; height: 32px; }
.drop-overlay-inner span:last-child { font-size: 0.9rem; }
.file-preview code, .md-body code { font-family: ui-monospace, monospace; font-size: 0.85em; background: var(--pane-2); padding: 0.1rem 0.35rem; border-radius: 4px; }
.file-preview pre code, .md-body pre code { background: none; padding: 0; }
/* GFM task-list checkboxes: the native disabled checkbox is greyed out, so
   checked vs unchecked become hard to tell apart. Replace its rendering with a
   custom box (appearance: none) so we fully control the look: an empty outline
   when unchecked, a filled accent box with a white check when checked. Keeps
   the semantic <input> and works in chat bubbles (.md-body) and file previews
   (.file-preview). Resets the global input rule (width:100%, padding, bg,
   border) that otherwise stretches the checkbox full-width on its own line. */
.md-body input[type="checkbox"],
.file-preview input[type="checkbox"] {
  appearance: none; -webkit-appearance: none;
  width: 1rem; height: 1rem; margin: 0 0.4rem 0 0; padding: 0;
  background: none; border: 1.5px solid var(--muted); border-radius: 3px;
  display: inline-block; vertical-align: middle; position: relative;
  opacity: 1; cursor: default; flex: 0 0 auto;
}
.md-body input[type="checkbox"]:checked,
.file-preview input[type="checkbox"]:checked {
  background: var(--accent); border-color: var(--accent);
}
.md-body input[type="checkbox"]:checked::after,
.file-preview input[type="checkbox"]:checked::after {
  content: ""; position: absolute; left: 5px; top: 2px;
  width: 5px; height: 9px; border: solid #fff; border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.md-body li.task-list-item, .file-preview li.task-list-item { list-style: none; }
.md-body ul.contains-task-list, .file-preview ul.contains-task-list { padding-left: 0; }
.file-preview h1, .md-body h1 { font-size: 1.35rem; margin: 0.8rem 0 0.5rem; line-height: 1.25; }
.file-preview h2, .md-body h2 { font-size: 1.15rem; margin: 0.8rem 0 0.4rem; line-height: 1.25; }
.file-preview h3, .md-body h3 { font-size: 1rem; margin: 0.7rem 0 0.3rem; line-height: 1.3; }
.file-preview h4, .file-preview h5, .file-preview h6, .md-body h4, .md-body h5, .md-body h6 { font-size: 0.92rem; margin: 0.6rem 0 0.3rem; }
.file-preview p, .md-body p { margin: 0.45rem 0; }
.file-preview ul, .file-preview ol, .md-body ul, .md-body ol { margin: 0.45rem 0; padding-left: 1.4rem; }
/* Restore bullet markers on <ul>: the global `ul { list-style: none }` reset
   (line 110) kills them everywhere; markdown content needs them back.
   <ol> keeps its default decimal numbering (not reset by the global rule). */
.file-preview ul, .md-body ul { list-style-type: disc; }
.file-preview li, .md-body li { margin: 0.15rem 0; }
.file-preview a, .md-body a { color: var(--accent); text-decoration: underline; }
.file-preview blockquote, .md-body blockquote { border-left: 3px solid var(--bd); padding-left: 0.8rem; color: var(--muted); margin: 0.5rem 0; }
.file-preview hr, .md-body hr { border: none; border-top: 1px solid var(--bd); margin: 0.8rem 0; }
.file-preview img, .md-body img { max-width: 100%; border-radius: var(--radius); }
.file-preview table, .md-body table { border-collapse: collapse; width: 100%; margin: 0.5rem 0; font-size: 0.82rem; }
.file-preview th, .file-preview td, .md-body th, .md-body td { border: 1px solid var(--bd); padding: 0.4rem 0.6rem; text-align: left; }
.file-preview th, .md-body th { background: var(--pane-2); }
/* Mermaid diagrams: centered, horizontally scrollable on narrow viewports.
   .mermaid-error keeps the raw source readable when the syntax couldn't parse
   (e.g. the model emitted a half-valid graph) instead of a broken empty box. */
.file-preview .mermaid, .md-body .mermaid { margin: 0.6rem 0; text-align: center; overflow-x: auto; }
.file-preview .mermaid svg, .md-body .mermaid svg { max-width: 100%; height: auto; }
.file-preview .mermaid-error, .md-body .mermaid-error { display: block; font-family: ui-monospace, monospace; font-size: 0.8rem; color: var(--muted); white-space: pre-wrap; background: var(--pane-2); border: 1px dashed var(--bd); border-radius: var(--radius); padding: 0.6rem 0.7rem; text-align: left; }
/* Math spans are rendered into KaTeX HTML by render-extras.js. .math-error is
   the fallback shown when the LaTeX couldn't parse (or a lone $ was captured):
   restore the delimited text in a discreet monospace style. */
.file-preview .math-error, .md-body .math-error { font-family: ui-monospace, monospace; color: var(--muted); }

/* overlay */
.overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.5); z-index: 20; }

/* modal dialog (settings, etc.) — backdrop + centered card. */
.modal { position: fixed; inset: 0; background: rgba(0,0,0,0.5); z-index: 40; display: flex; align-items: center; justify-content: center; padding: 1rem; }
.modal-card { width: 100%; max-width: 380px; background: var(--pane); border: 1px solid var(--bd); border-radius: 14px; overflow: hidden; box-shadow: 0 10px 40px rgba(0,0,0,0.4); }
.modal-body { display: flex; flex-direction: column; gap: 0.7rem; padding: 1rem 1.2rem 1.2rem; }
.modal-body input { width: 100%; height: 40px; border-radius: var(--radius); background: var(--bg); border: 1px solid var(--bd); color: var(--text); padding: 0 0.7rem; box-sizing: border-box; }
.modal-body .savebtn { height: 42px; border-radius: var(--radius); background: var(--accent); color: #fff; font-weight: 600; cursor: pointer; }
.modal-body .savebtn:hover { filter: brightness(1.08); }

/* Settings modal: tabbed (Theme | Password). Tabs sit between the panehead
   and the panel body; only the active panel is shown. */
.settings-tabs { display: flex; gap: 0.2rem; padding: 0.45rem 0.6rem; border-bottom: 1px solid var(--bd); }
.settings-tab { flex: 1; padding: 0.45rem 0.5rem; border-radius: 8px; font-size: 0.86rem; color: var(--muted); text-align: center; cursor: pointer; }
.settings-tab:hover { color: var(--text); background: var(--pane-2); }
.settings-tab.active { color: var(--accent); background: var(--accent-soft); }
.settings-panel { display: none; }
.settings-panel.active { display: block; }

/* Theme picker: 2×2 grid of swatches. Each swatch is a circle filled with the
   theme's bg, holding a smaller dot in the theme's accent — a real mini-
   preview. "Auto" uses a half/half split (dark | light) and no dot. */
.theme-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0.6rem; }
.theme-option { display: flex; flex-direction: column; align-items: center; gap: 0.4rem; padding: 0.7rem 0.4rem; border: 1px solid var(--bd); border-radius: 10px; background: var(--pane-2); cursor: pointer; }
.theme-option:hover { border-color: var(--accent); }
.theme-option.active { border-color: var(--accent); background: var(--accent-soft); }
.theme-swatch { width: 40px; height: 40px; border-radius: 50%; border: 1px solid rgba(0,0,0,0.12); position: relative; display: flex; align-items: center; justify-content: center; }
.theme-swatch .theme-dot { width: 14px; height: 14px; border-radius: 50%; box-shadow: 0 0 0 1px rgba(0,0,0,0.15); }
.theme-label { font-size: 0.8rem; color: var(--muted); text-align: center; }
.theme-option.active .theme-label { color: var(--text); }

/* --------------------------------------------------------------- login */
body.center { display: flex; align-items: center; justify-content: center; min-height: 100vh; padding: 1rem; overflow: auto; }
.login-card { width: 100%; max-width: 340px; background: var(--pane); border: 1px solid var(--bd); border-radius: 14px; padding: 1.6rem; }
.login-card .brand { text-align: center; margin-bottom: 1.2rem; font-size: 1.2rem; font-weight: 600; color: var(--accent); }
.login-card .subtitle { text-align: center; margin-bottom: 0.4rem; font-size: 0.98rem; font-weight: 600; }
.login-card form { display: flex; flex-direction: column; gap: 0.7rem; }
.login-card button[type="submit"] { height: 44px; border-radius: var(--radius); background: var(--accent); color: #fff; font-weight: 600; }
#err { min-height: 1em; text-align: center; color: var(--danger); }

/* ---------------------------------------------------- responsive drawers */
@media (max-width: 1023px) {
  /* Left sidebar = full-width drawer sliding in from the left. The rail
     reflows as a horizontal top bar inside the drawer, so every nav button
     (conversations/memory/skills/crons/versions/settings) stays reachable
     with no JS rewiring — the existing handlers are reused as-is. */
  .sidebar { position: fixed; inset: 0; width: 100%; flex-direction: column; z-index: 30; transform: translateX(-100%); transition: transform 0.22s ease; }
  .sidebar.expanded { transform: translateX(0); }

  .rail { flex-direction: row; width: 100%; height: 52px; flex: 0 0 auto; border-right: none; border-bottom: 1px solid var(--bd); padding: 0 0.5rem; }
  .rail-logo { margin-bottom: 0; margin-right: 0.5rem; }
  .rail-nav { flex-direction: row; width: auto; }
  /* X close button shown at the right of the top bar (mobile only). */
  .rail-close { display: inline-flex; margin-left: auto; }
  /* Versions + settings reflow as a full-width bottom bar pinned to the bottom of
     the drawer (pulled out of the top-bar flow via absolute positioning, relative
     to the fixed .sidebar). The panel gets matching bottom padding so its
     scrollable list never hides behind the bar. */
  .rail-bottom { position: absolute; bottom: 0; left: 0; right: 0; height: 52px; margin-top: 0; flex-direction: row; border-top: 1px solid var(--rail-border); background: var(--rail-bg); }
  /* Reset the desktop margin-top (auto / 0.2rem) that pins versions+settings
     to the bottom of the rail column — in the mobile row it breaks vertical
     centering (margin-top:auto pushes the item to the bottom cross-axis). */
  #rail-versions, #rail-settings { margin-top: 0; }

  .panel { position: static; width: 100%; flex: 1; border-right: none; display: flex; transform: none; padding-bottom: 52px; }
  .sidebar:not(.expanded) .panel { transform: none; }
  .sidebar.expanded .panel { transform: none; }

  /* Right workspace = bottom sheet: full width, ~92% height, slides up. */
  .workspace { position: fixed; left: 0; right: 0; bottom: 0; top: auto; width: 100%; height: 92vh; border-left: none; border-radius: 14px 14px 0 0; box-shadow: 0 -4px 24px rgba(0,0,0,0.5); z-index: 25; transform: translateY(100%); transition: transform 0.22s ease; }
  .workspace:not(.hidden) { transform: translateY(0); }
  .workspace.hidden { display: flex; transform: translateY(100%); }
  .sheet-handle { display: block; }

  /* Floating burger (top-left) shown on mobile only; visibility toggled by JS. */
  .mobile-burger { left: 0.6rem; right: auto; }
  /* New-chat button sits just left of the folder button (right edge). */
  .mobile-new-chat { right: calc(0.6rem + 44px); }

  .convo-del { opacity: 0.4; }
  .msg { max-width: 96%; }
  /* Keep the first message clear of the two floating buttons at the top. */
  .messages { padding-top: 3.4rem; }
  /* Fiche panes (memory/skills/crons/versions) live in the main column; their
     panehead must clear the two floating buttons (burger top-left, folder top-right). */
  .memory-pane { padding-top: 3.4rem; }
  /* Composer: more breathing room at the bottom for phone rounded corners and
     home indicator (env(safe-area-inset-bottom)). Taller textarea + buttons. */
  .composer { padding: 0.7rem 0.7rem calc(0.9rem + env(safe-area-inset-bottom, 0px)); }
  .composer textarea { min-height: 52px; }
  .sendbtn { width: 48px; height: 48px; }
  /* Prevent iOS auto-zoom on input focus (happens when font-size < 16px). 16px
     on all form fields keeps the layout stable when the keyboard opens. */
  input, textarea, select { font-size: 16px; }
  /* iOS zoom guard for compact inputs that set an explicit font-size < 16px:
     their higher specificity (.class input) beats the generic rule above, so
     iOS Safari still zooms when focusing them. Bump to 16px on mobile only. */
  .searchbar input,
  .popover-input,
  .inline-form input,
  .filerow-input,
  .pathlabel-input { font-size: 16px; }
}

/* Touch devices: neutralize the hover-reveal of conversation row action buttons.
   On iOS the first tap "sticks" on :hover (revealing the more/delete buttons)
   without firing the click — so the user must tap twice to open a convo. Making
   the hover-reveal a no-op on touch lets the first tap go straight to the click. */
@media (hover: none) {
  .convo-row:hover { background: transparent; }
  .convo-row.active:hover { background: var(--accent-soft); }
  .convo-row:hover .convo-more { opacity: 0; }
  .convo-row:hover .convo-del { opacity: 0.4; }
}
@media (max-width: 480px) {
  :root { --panel-w: 260px; --right-w: 300px; }
}

/* --------------------------------------------------------------- crons */
.cron-row { display: flex; gap: 2px; align-items: stretch; border-radius: 9px; border: 1px solid transparent; }
.cron-row:hover { background: var(--pane-2); }
.cron-row.disabled { opacity: 0.55; }
.cron-main { flex: 1; min-width: 0; text-align: left; padding: 0.5rem 0.6rem; display: flex; flex-direction: column; gap: 0.15rem; cursor: pointer; }
.cron-prompt { font-size: 0.86rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cron-sched { font-size: 0.74rem; }
.cron-status { font-size: 0.7rem; padding: 0.05rem 0.4rem; border-radius: 99px; align-self: flex-start; text-transform: uppercase; letter-spacing: 0.03em; }
.cron-status.idle { color: var(--muted); background: var(--pane-2); }
.cron-status.running { color: var(--accent); background: var(--accent-soft); animation: cron-pulse 1.4s ease-in-out infinite; }
.cron-status.scheduled { color: var(--accent); background: var(--accent-soft); }
@keyframes cron-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } }
.cron-status.ok { color: #5fd17a; background: rgba(95,209,122,0.12); }
.cron-status.error { color: var(--danger, #e55); background: rgba(229,85,85,0.12); }
.cron-row .iconbtn { opacity: 0; }
.cron-row:hover .iconbtn { opacity: 1; }
/* Cron create modal fields: labels stack input + control, matching the
   existing modal input look. */
.cron-field { display: flex; flex-direction: column; gap: 0.25rem; }
.cron-field select,
.cron-field input { height: 40px; border-radius: var(--radius); background: var(--bg); border: 1px solid var(--bd); color: var(--text); padding: 0 0.7rem; box-sizing: border-box; }
#cron-prompt { resize: vertical; min-height: 64px; font-family: inherit; }
/* Cron detail pane: title + schedule + instructions (editable) + history.
   Reuses .cron-run rows from the runs list for the history section. */
.cron-detail-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.8rem; padding: 0.9rem 1rem 1.2rem; overflow-y: auto; }
.cron-detail-section { display: flex; flex-direction: column; gap: 0.3rem; }
.cron-detail-label { text-transform: uppercase; letter-spacing: 0.04em; font-size: 0.68rem; }
.cron-detail-value { font-size: 0.9rem; color: var(--text); white-space: pre-wrap; word-break: break-word; }
.cron-detail-value.mono { font-family: ui-monospace, monospace; font-size: 0.8rem; white-space: pre-wrap; word-break: break-word; background: var(--pane-2); border: 1px solid var(--bd); border-radius: var(--radius); padding: 0.55rem 0.7rem; }
/* Editable sections: same input look as the create modal. */
.cron-detail-edit-section input,
.cron-detail-edit-section select { width: 100%; height: 40px; border-radius: var(--radius); background: var(--bg); border: 1px solid var(--bd); color: var(--text); padding: 0 0.7rem; box-sizing: border-box; }
.cron-detail-edit-section textarea { width: 100%; resize: vertical; min-height: 64px; border-radius: var(--radius); background: var(--bg); border: 1px solid var(--bd); color: var(--text); padding: 0.5rem 0.7rem; box-sizing: border-box; font-family: inherit; }
/* History sub-list inside the detail pane. */
.cron-runs-list { display: flex; flex-direction: column; }
/* Task title shown in the list row (replaces the old prompt-ellipsis). */
.cron-title { font-size: 0.9rem; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Cron runs history pane (one row per execution). Mirrors .versionrow so
   the runs list reads like the Versions list. */
.cron-run { display: flex; align-items: flex-start; gap: 0.5rem; padding: 0.55rem 0.6rem; border-bottom: 1px solid var(--bd); font-size: 0.85rem; }
.cron-run:last-child { border-bottom: none; }
.cron-run .ic { opacity: 0.6; flex: 0 0 auto; margin-top: 0.1rem; }
.cron-run-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.2rem; }
.cron-run-head { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.cron-run .run-date { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cron-run .run-duration { white-space: nowrap; }
.cron-run .run-error { color: var(--danger, #e55); margin: 0; }
.cron-run .iconbtn { flex: 0 0 auto; }

/* Skills: rows mirror the cron layout so the two lists feel the same. */
.skill-row { display: flex; gap: 2px; align-items: stretch; border-radius: 9px; border: 1px solid transparent; }
.skill-row:hover { background: var(--pane-2); }
.skill-row.disabled { opacity: 0.55; }
.skill-main { flex: 1; min-width: 0; text-align: left; padding: 0.5rem 0.6rem; display: flex; flex-direction: column; gap: 0.15rem; cursor: pointer; border: none; background: none; color: inherit; border-radius: 8px; }
.skill-name { font-size: 0.9rem; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.skill-desc { font-size: 0.74rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.skill-status { font-size: 0.7rem; padding: 0.05rem 0.4rem; border-radius: 99px; align-self: flex-start; text-transform: uppercase; letter-spacing: 0.03em; }
.skill-status.idle { color: var(--muted); background: var(--pane-2); }
.skill-status.ok { color: #5fd17a; background: rgba(95,209,122,0.12); }
.skill-row .iconbtn { opacity: 0; }
.skill-row:hover .iconbtn { opacity: 1; }
/* Instructions preview in the skill detail pane: markdown rendered, readable width. */
.skill-instr-preview { font-size: 0.88rem; line-height: 1.5; }
.skill-instr-preview :first-child { margin-top: 0; }
.skill-instr-preview :last-child { margin-bottom: 0; }
