/* OpenChatGPT — dark theme, ChatGPT-style layout. Single stylesheet, no build step. */
:root {
  --bg: #212121;
  --bg-soft: #2f2f2f;
  --sidebar: #171717;
  --sidebar-hover: #212121;
  --text: #ececec;
  --text-dim: #b4b4b4;
  --text-faint: #8e8e8e;
  --border: #424242;
  --accent: #10a37f;
  --accent-hover: #0e8f6f;
  --user-bubble: #2f2f2f;
  --code-bg: #0d0d0d;
  --danger: #f93a37;
  --radius: 16px;
  --sidebar-w: 260px;
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; overflow-x: hidden; }
body {
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: 16px;
  line-height: 1.6;
}
a { color: #7dd3c0; }
a:hover { color: #a7e8d8; }
button { font: inherit; cursor: pointer; }
/* c3: every control gets a visible keyboard-focus ring, not
   just the few the old rules listed. */
:focus-visible { outline: 2px solid #5eead4; outline-offset: 2px; }
input, select, textarea { font: inherit; color: var(--text); }

/* ---------- App layout ---------- */
.app { display: flex; height: 100vh; height: 100dvh; overflow: hidden; }
.sidebar {
  width: var(--sidebar-w);
  flex: 0 0 var(--sidebar-w);
  background: var(--sidebar);
  display: flex;
  flex-direction: column;
  padding: 12px 10px;
  gap: 8px;
  overflow-y: auto;
}
.sidebar-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.brand { display: flex; align-items: center; gap: 8px; text-decoration: none; color: var(--text); font-weight: 700; font-size: 17px; }
.brand-mark {
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--accent); color: #fff;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 15px; font-weight: 800;
}
.btn {
  border: 1px solid var(--border);
  background: transparent; color: var(--text);
  border-radius: 999px; padding: 8px 14px;
}
.btn:hover { background: var(--sidebar-hover); }
.btn-primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.btn-primary:hover { background: var(--accent-hover); }
.btn-new { width: 100%; text-align: left; border-radius: 10px; padding: 10px 12px; }
.btn-icon { border: none; background: transparent; color: var(--text-dim); padding: 6px 8px; border-radius: 8px; }
.btn-icon:hover { background: var(--sidebar-hover); color: var(--text); }
.search-input {
  width: 100%; background: var(--bg-soft); border: 1px solid var(--border);
  border-radius: 10px; padding: 9px 12px; outline: none;
}
.search-input:focus { border-color: var(--accent); }
.history-label { font-size: 12px; color: var(--text-faint); margin: 8px 4px 2px; }
.history-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.history-list li { display: flex; align-items: center; gap: 4px; }
.history-list button.chat-item {
  flex: 1; min-width: 0; text-align: left; background: transparent; border: none;
  color: var(--text); padding: 9px 10px; border-radius: 10px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.history-list button.chat-item:hover, .history-list button.chat-item.active { background: var(--sidebar-hover); }
.history-list .del { border: none; background: transparent; color: var(--text-faint); padding: 4px 6px; border-radius: 6px; font-size: 14px; }
.history-list .del:hover { color: var(--danger); }
.history-empty { font-size: 13px; color: var(--text-faint); padding: 4px 10px; }
.sidebar-foot { margin-top: auto; display: flex; flex-direction: column; gap: 4px; padding-top: 10px; border-top: 1px solid var(--border); }
.sidebar-foot a { color: var(--text-dim); text-decoration: none; font-size: 13px; padding: 6px 10px; border-radius: 8px; }
.sidebar-foot a:hover { background: var(--sidebar-hover); color: var(--text); }

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.topbar {
  display: flex; align-items: center; gap: 10px;
  padding: calc(10px + env(safe-area-inset-top, 0px)) 14px 10px; border-bottom: 1px solid var(--border);
}
.topbar .brand { font-size: 16px; }
.status-pill {
  margin-left: auto; font-size: 12px; font-weight: 600; color: #a7e8d8;
  background: rgba(16, 163, 127, 0.14); border: 1px solid rgba(16, 163, 127, 0.45);
  border-radius: 999px; padding: 5px 12px; white-space: nowrap;
}
.chat-scroll { flex: 1; overflow-y: auto; padding: 24px 16px 12px; scroll-behavior: smooth; }
.chat-inner { max-width: 760px; margin: 0 auto; }
.welcome { text-align: center; padding: 48px 12px 8px; }
.welcome h1 { font-size: 34px; margin: 0 0 10px; font-weight: 700; letter-spacing: -0.02em; line-height: 1.2; }
.welcome h1 .grad {
  background: linear-gradient(90deg, #10a37f 0%, #5eead4 45%, #7dd3fc 100%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.welcome p { color: var(--text-dim); margin: 0 auto 28px; max-width: 540px; font-size: 16.5px; line-height: 1.65; }
/* P1 (v30): the welcome pill is mobile-only — on desktop the topbar
   already shows "Free · No sign-up", so the hero pill was a duplicate. */
.hero-pill { display: none; margin: 0 0 18px; }
.suggestions { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; text-align: left; }
.suggestion {
  display: flex; align-items: flex-start; gap: 12px;
  background: transparent; border: 1px solid var(--border); color: var(--text);
  border-radius: var(--radius); padding: 14px 16px; text-align: left; line-height: 1.45;
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}
.suggestion:hover { background: var(--bg-soft); border-color: #5a5a5a; transform: translateY(-1px); }
.suggestion:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.sug-icon {
  flex: 0 0 34px; width: 34px; height: 34px; border-radius: 10px;
  background: rgba(16, 163, 127, 0.16); color: #5eead4;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 17px; font-weight: 700; font-style: normal;
}
.sug-text { display: flex; flex-direction: column; min-width: 0; }
.sug-text strong { display: block; font-size: 15px; margin-bottom: 2px; }
.sug-text span { color: var(--text-dim); font-size: 13px; }
.message { padding: 14px 4px; }
.message.assistant {
  border-left: 3px solid rgba(16, 163, 127, 0.55);
  padding-left: 14px; margin-left: -4px;
}
.message.assistant .msg-body { line-height: 1.75; }
.message.user { text-align: right; }
.message.user .msg-head { justify-content: flex-end; }
.message .msg-head { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.avatar {
  width: 28px; height: 28px; border-radius: 50%; flex: 0 0 28px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 13px; font-weight: 700;
}
.avatar-ai { background: var(--accent); color: #fff; }
.avatar-user { background: #5436da; color: #fff; }
.msg-role { font-weight: 600; font-size: 14px; }
.message .msg-body { overflow-wrap: anywhere; }
.message.user .msg-body {
  background: #3a3a3a; border: 1px solid #4a4a4a; border-radius: 18px 18px 6px 18px;
  padding: 12px 16px; display: inline-block; max-width: 92%; white-space: pre-wrap;
  text-align: left; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.25);
}
.msg-actions { display: flex; gap: 4px; margin-top: 8px; }
.msg-actions button {
  border: none; background: transparent; color: var(--text-faint);
  font-size: 13px; padding: 4px 8px; border-radius: 6px;
}
.msg-actions button:hover { background: var(--bg-soft); color: var(--text); }
.msg-body p { margin: 0 0 12px; }
.msg-body p:last-child { margin-bottom: 0; }
.msg-body h1, .msg-body h2, .msg-body h3 { margin: 18px 0 8px; line-height: 1.3; }
.msg-body ul, .msg-body ol { margin: 0 0 12px; padding-left: 22px; }
.msg-body li { margin-bottom: 4px; }
.msg-body code { background: var(--code-bg); padding: 2px 6px; border-radius: 6px; font-size: 0.88em; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
.msg-body pre { background: var(--code-bg); border-radius: 12px; padding: 0; overflow: auto; margin: 0 0 12px; }
.msg-body pre code { display: block; background: transparent; padding: 14px 16px; border-radius: 0; }
/* M1 (v30): the Copy button lives in its own header row above the code,
   never absolutely positioned over it — on a narrow phone the button
   used to cover characters of the first code line. */
.code-block { border-radius: 12px; overflow: hidden; margin: 0 0 12px; }
.code-block pre { margin-bottom: 0; border-radius: 0; }
.code-head {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  background: #1a1a1a; border-bottom: 1px solid var(--border);
  padding: 6px 8px 6px 14px; min-height: 40px;
}
.code-lang { font-size: 12px; color: var(--text-faint); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
.code-block .copy-code {
  background: var(--bg-soft); color: var(--text); border: 1px solid var(--border);
  border-radius: 8px; padding: 4px 10px; font-size: 12px; flex: 0 0 auto;
}
.msg-body blockquote { border-left: 3px solid var(--border); margin: 0 0 12px; padding: 4px 14px; color: var(--text-dim); }
.msg-body table { border-collapse: collapse; margin-bottom: 12px; }
.msg-body th, .msg-body td { border: 1px solid var(--border); padding: 6px 10px; text-align: left; }
.typing { color: var(--text-dim); }
.typing .dot { animation: blink 1s infinite; }
@keyframes blink { 50% { opacity: 0.2; } }
.error-box {
  background: #3d1d1d; border: 1px solid #7a2e2e; color: #ffd7d7;
  border-radius: 12px; padding: 12px 16px; margin: 8px 0;
}
.error-box .error-text { display: block; margin-bottom: 10px; }
.error-retry {
  border: 1px solid #a33; background: #7a2e2e; color: #fff;
  font-size: 13px; font-weight: 600; padding: 6px 14px; border-radius: 8px;
  cursor: pointer;
}
.error-retry:hover { background: #933; }
.composer-wrap { padding: 8px 16px env(safe-area-inset-bottom, 0px); }
.composer { max-width: 760px; margin: 0 auto; }
.composer-box {
  background: var(--bg-soft); border: 1px solid var(--border);
  border-radius: 28px; padding: 10px 10px 10px 18px;
  display: flex; align-items: flex-end; gap: 8px;
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.35);
}
.composer-box:focus-within { border-color: var(--accent); box-shadow: 0 6px 24px rgba(0, 0, 0, 0.35), 0 0 0 3px rgba(16, 163, 127, 0.25); }
#prompt {
  flex: 1; background: transparent; border: none; outline: none; resize: none;
  min-height: 24px; max-height: 200px; padding: 6px 0; line-height: 1.5;
}
#sendBtn, #stopBtn {
  flex: 0 0 auto; width: 44px; height: 44px; min-width: 44px; min-height: 44px; border-radius: 50%;
  border: none; display: inline-flex; align-items: center; justify-content: center;
  font-size: 17px;
}
#sendBtn { background: linear-gradient(135deg, #10a37f 0%, #0d8a6c 55%, #0b7a8c 100%); color: #fff; box-shadow: 0 2px 10px rgba(16, 163, 127, 0.4); }
#sendBtn:hover:not(:disabled) { filter: brightness(1.12); }
#sendBtn:focus-visible, #stopBtn:focus-visible, .btn:focus-visible, .btn-icon:focus-visible { outline: 2px solid #5eead4; outline-offset: 2px; }
#sendBtn:disabled { background: #555; color: #999; cursor: not-allowed; box-shadow: none; }
#stopBtn { background: transparent; border: 1px solid var(--border); color: var(--text); display: none; }
.composer-meta { display: flex; justify-content: space-between; gap: 8px; font-size: 12px; color: var(--text-faint); padding: 8px 6px 0; }
.disclaimer { text-align: center; font-size: 12px; color: var(--text-faint); padding: 10px 16px calc(14px + env(safe-area-inset-bottom, 0px)); max-width: 760px; margin: 0 auto; }
.disclaimer a { color: var(--text-faint); }

/* ---------- Info pages ---------- */
.page { min-height: 100vh; display: flex; flex-direction: column; }
.site-header {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 14px 24px; border-bottom: 1px solid var(--border); flex-wrap: wrap;
}
.site-header nav { display: flex; gap: 4px; flex-wrap: wrap; }
.site-header nav a { color: var(--text-dim); text-decoration: none; padding: 8px 10px; border-radius: 8px; font-size: 14px; }
.site-header nav a:hover, .site-header nav a[aria-current="page"] { background: var(--bg-soft); color: var(--text); }
.site-header .cta { background: var(--accent); color: #fff; text-decoration: none; padding: 8px 16px; border-radius: 999px; font-size: 14px; }
.content { max-width: 760px; margin: 0 auto; padding: 40px 20px 60px; flex: 1; width: 100%; }
.content h1 { font-size: 32px; line-height: 1.25; margin: 0 0 12px; }
.content h2 { font-size: 22px; margin: 32px 0 10px; }
.content p, .content li { color: var(--text); }
.content .lede { color: var(--text-dim); font-size: 18px; }
.content ul, .content ol { padding-left: 22px; }
.site-footer { border-top: 1px solid var(--border); padding: 24px; text-align: center; color: var(--text-faint); font-size: 13px; }
.site-footer nav { margin-bottom: 10px; }
.site-footer a { color: var(--text-dim); margin: 0 8px; }
.ad-slot {
  margin: 28px auto; min-height: 90px;
  border: 1px dashed var(--border); border-radius: 12px;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-faint); font-size: 12px; text-align: center; padding: 12px;
}
.contact-form { display: flex; flex-direction: column; gap: 12px; max-width: 520px; }
.contact-form label { font-size: 14px; color: var(--text-dim); }
.contact-form input, .contact-form textarea, .contact-form select {
  width: 100%; background: var(--bg-soft); border: 1px solid var(--border);
  border-radius: 10px; padding: 10px 12px; outline: none;
}
.contact-form input:focus, .contact-form textarea:focus { border-color: var(--accent); }

/* ---------- Mobile ---------- */
/* M2 (v30, mobile only — desktop untouched): tighten the welcome
   spacing so all 8 suggestion cards fit inside the chat viewport on a
   phone once the cookie banner is dismissed (~680px of chat-scroll).
   Smaller paddings/margins, smaller card text, tighter grid gap. */
@media (max-width: 760px) {
  .welcome { padding: 14px 8px 4px; }
  .welcome h1 { font-size: 22px; margin-bottom: 6px; }
  .welcome p { margin-bottom: 12px; }
  .hero-pill { margin-bottom: 8px; }
  .suggestions { gap: 6px; }
  .suggestion { padding: 8px 12px; }
  .sug-icon { flex-basis: 30px; width: 30px; height: 30px; font-size: 15px; }
  .sug-text strong { font-size: 14px; }
  .sug-text span { font-size: 12px; }
}
@media (max-width: 760px) {
  .sidebar {
    position: fixed; top: 0; left: 0; bottom: 0; z-index: 50;
    transform: translateX(-100%); transition: transform 0.2s ease;
    box-shadow: 0 0 40px rgba(0,0,0,0.5);
  }
  .sidebar.open { transform: translateX(0); }
  .suggestions { grid-template-columns: 1fr; }
  .content h1 { font-size: 26px; }
  .composer-meta .hint { display: none; }
}
@media (max-width: 390px) {
  .welcome { padding: 10px 4px 4px; }
  .welcome h1 { font-size: 22px; }
  .welcome p { font-size: 15px; }
  .suggestion { padding: 8px 12px; }
  .status-pill { font-size: 11px; padding: 4px 10px; }
  .topbar .brand { font-size: 15px; }
  .composer-wrap { padding: 6px 10px 0; }
  .chat-scroll { padding: 10px 10px 8px; }
  .message.assistant { padding-left: 10px; }
}

/* ---------- v5 additions: cookie consent banner ---------- */
.cookie-banner {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 200;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  background: #171717; border-top: 1px solid var(--border);
  padding: 14px 24px; box-shadow: 0 -8px 32px rgba(0, 0, 0, 0.5);
}
.cookie-text { margin: 0; font-size: 13px; color: var(--text-dim); max-width: 760px; }
.cookie-text a { color: #7dd3c0; }
.cookie-buttons { display: flex; gap: 8px; flex: 0 0 auto; }
.cookie-accept {
  background: var(--accent); border: 1px solid var(--accent); color: #fff;
  border-radius: 999px; padding: 8px 18px; font-size: 14px; font-weight: 600;
}
.cookie-accept:hover { background: var(--accent-hover); }
.cookie-dismiss {
  background: transparent; border: 1px solid var(--border); color: var(--text);
  border-radius: 999px; padding: 8px 18px; font-size: 14px;
}
.cookie-dismiss:hover { background: var(--bg-soft); }
.footer-guides { margin-top: 6px; }
.footer-guides span { color: var(--text-faint); margin-right: 4px; }
.footer-guides .footer-sep { margin: 0 6px; }
@media (max-width: 760px) {
  .cookie-banner { flex-direction: column; align-items: flex-start; gap: 10px; padding: 14px 16px; }
}

/* ---------- v9 additions ---------- */
/* Desktop sidebar collapse: the ☰ button toggles body.sidebar-collapsed
   (app.js). The sidebar hides and .main (flex:1) expands full width.
   Scoped to desktop widths only — on mobile the sidebar is a fixed
   overlay drawer driven by .sidebar.open, untouched by this rule. */
@media (min-width: 761px) {
  body.sidebar-collapsed .sidebar { display: none; }
}
/* Toast feedback (Clear all chats) — brief, centred, above content. */
.toast {
  position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%); z-index: 300;
  background: #2f2f2f; color: var(--text); border: 1px solid var(--border);
  border-radius: 999px; padding: 10px 18px; font-size: 14px; white-space: nowrap;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5); pointer-events: none;
}
/* Cookie banner offset: while the fixed banner is shown, consent.js
   adds body.has-cookie-banner and sets --cookie-banner-h to the banner's
   measured height (taller on mobile). The app shrinks by exactly that
   height. That alone is NOT enough: the disclaimer / quick links at the
   end of the page would still sit exactly under the banner's top edge
   (v29 audit M4). So the content section also gains the banner height
   as extra bottom padding, giving the page enough scroll room for the
   disclaimer row to rise clear above the banner. The class and variable
   are removed when the banner is accepted/dismissed. */
body.has-cookie-banner { padding-bottom: var(--cookie-banner-h, 64px); }
body.has-cookie-banner .app {
  height: calc(100vh - var(--cookie-banner-h, 64px));
  height: calc(100dvh - var(--cookie-banner-h, 64px));
}
body.has-cookie-banner .content { padding-bottom: calc(60px + var(--cookie-banner-h, 64px)); }

/* ---------- v3 additions ---------- */
#clearAllBtn { text-align: left; }
.noscript-note { text-align: center; padding: 20px; }
.quick-links { text-align: center; font-size: 12px; color: var(--text-faint); padding: 0 16px 12px; max-width: 760px; margin: 0 auto; }
.quick-links a { color: var(--text-faint); }
.error-code { font-size: 72px; font-weight: 800; line-height: 1; margin: 0 0 8px; color: var(--accent); }
.content a.btn { text-decoration: none; display: inline-block; }

/* ---------- v4 additions: website preview modal ---------- */
.preview-modal { display: none; position: fixed; inset: 0; z-index: 100; background: rgba(0,0,0,0.7); padding: 24px; }
.preview-modal.open { display: flex; align-items: center; justify-content: center; }
.preview-box { background: var(--bg); border: 1px solid var(--border); border-radius: 12px; width: min(1000px, 100%); height: min(720px, 92vh); display: flex; flex-direction: column; overflow: hidden; box-shadow: 0 24px 64px rgba(0,0,0,0.6); }
.preview-bar { display: flex; align-items: center; justify-content: space-between; padding: 10px 14px; border-bottom: 1px solid var(--border); }
.preview-title { font-size: 14px; font-weight: 600; }
.preview-close { background: none; border: 1px solid var(--border); color: var(--text); font-size: 20px; line-height: 1; width: 32px; height: 32px; border-radius: 8px; cursor: pointer; }
.preview-close:hover { background: var(--bg-soft); }
.preview-frame { flex: 1; width: 100%; border: 0; background: #fff; }
.preview-note { margin: 0; padding: 8px 14px; font-size: 12px; color: var(--text-faint); border-top: 1px solid var(--border); }
@media (max-width: 760px) {
  .preview-modal { padding: 10px; }
  .preview-box { height: 92vh; }
}

/* ---------- v4 additions: files panel (folder tree) ---------- */
.files-panel { border: 1px solid var(--border); border-radius: 10px; background: var(--bg-soft); margin: 4px 0 12px; overflow: hidden; }
.files-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 10px 12px; border-bottom: 1px solid var(--border); }
.files-title { font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.files-zip-btn { background: var(--accent); border: 1px solid var(--accent); color: #fff; font-size: 12px; font-weight: 600; padding: 6px 12px; border-radius: 999px; cursor: pointer; white-space: nowrap; }
.files-zip-btn:hover { background: var(--accent-hover); }
.files-zip-btn:disabled { opacity: 0.6; cursor: default; }
.tree-folder { padding: 2px 12px; }
.tree-folder > summary { cursor: pointer; font-size: 13px; font-weight: 600; padding: 6px 0; list-style: none; }
.tree-folder > summary::-webkit-details-marker { display: none; }
.tree-folder .file-row, .tree-folder .tree-folder { margin-left: 16px; }
.file-row { display: flex; align-items: center; gap: 6px; padding: 5px 12px; }
.file-name { flex: 1; font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.file-btn { background: none; border: 1px solid var(--border); color: var(--text-faint); font-size: 11px; padding: 3px 8px; border-radius: 999px; cursor: pointer; white-space: nowrap; }
.file-btn:hover { background: var(--bg); color: var(--text); }

/* ---------- v7 additions: Continue button + incomplete-file note ---------- */
.msg-actions .continue-btn { background: var(--accent); color: #fff; font-weight: 600; }
.msg-actions .continue-btn:hover { background: var(--accent-hover); color: #fff; }
.files-note { font-size: 12px; color: var(--text-faint); padding: 0 12px 8px; }

/* ---------- v17 additions: thinking indicator + loading bar ---------- */
/* Thinking indicator (user order 2026-11-14): ChatGPT/Claude-style
   thinking state in the live assistant bubble — "Thinking" + three
   bouncing dots + a ticking elapsed-seconds counter. */
.thinking { display: inline-flex; align-items: baseline; gap: 4px; }
.thinking-label { font-weight: 600; }
.thinking-dots { display: inline-flex; gap: 3px; margin-left: 2px; }
.thinking-dots span {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--text-dim); display: inline-block;
  animation: thinking-bounce 1.2s infinite;
}
.thinking-dots span:nth-child(2) { animation-delay: 0.15s; }
.thinking-dots span:nth-child(3) { animation-delay: 0.3s; }
@keyframes thinking-bounce {
  0%, 60%, 100% { transform: translateY(0); opacity: 0.4; }
  30% { transform: translateY(-4px); opacity: 1; }
}
.thinking-timer { margin-left: 4px; font-size: 13px; color: var(--text-faint); font-variant-numeric: tabular-nums; }
/* Thin indeterminate bar at the top of the chat area, visible only while
   generating. position:sticky keeps it pinned just under the header while
   the chat scrolls. Never a fake percentage — the fill slides across. */
.loadbar { display: none; position: sticky; top: 0; z-index: 5; height: 3px; overflow: hidden; }
.loadbar.on { display: block; }
.loadbar-fill {
  display: block; height: 100%; width: 40%;
  background: linear-gradient(90deg, #10a37f, #5eead4);
  animation: loadbar-slide 1.2s ease-in-out infinite;
}
@keyframes loadbar-slide {
  0% { transform: translateX(-110%); }
  100% { transform: translateX(260%); }
}
@media (prefers-reduced-motion: reduce) {
  .thinking-dots span { animation: none; }
  .loadbar-fill { animation: none; width: 100%; }
}

/* ---------- v18 additions: mobile-friendly + user-friendly ---------- */
/* Drawer close button: hidden on desktop, visible in the sidebar header
   on mobile (<=760px) where the sidebar is an overlay drawer. */
.sidebar-close { display: none; }
/* Drawer backdrop (created once by app.js): dimmed layer under the fixed
   drawer, above the page. Shown only while the drawer is open. */
.sidebar-backdrop {
  display: none; position: fixed; inset: 0; z-index: 40;
  background: rgba(0, 0, 0, 0.5);
}
/* Wide tables in AI replies scroll inside their own block instead of
   pushing the page wider than the viewport. */
.msg-body table { display: block; max-width: 100%; overflow-x: auto; }
/* Thinking indicator must never clip on a narrow screen. */
.thinking { max-width: 100%; }
@media (max-width: 760px) {
  .sidebar-backdrop.on { display: block; }
  .sidebar-close {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 44px; min-height: 44px;
  }
  /* Drawer never wider than the phone: cap at 280px / 85% of the width. */
  .sidebar { width: min(280px, 85vw); flex-basis: min(280px, 85vw); }
  .topbar { flex-wrap: wrap; }
  .topbar .btn-icon { min-width: 44px; min-height: 44px; }
  /* 16px composer text: iOS zooms the page on focus below 16px. */
  #prompt { font-size: 16px; }
  #sendBtn, #stopBtn { min-width: 44px; min-height: 44px; width: 44px; height: 44px; }
  /* Message actions + file buttons: 40px minimum tap targets. */
  .msg-actions { flex-wrap: wrap; }
  .msg-actions button { min-height: 40px; padding: 8px 12px; }
  .files-zip-btn { min-height: 40px; padding: 8px 14px; }
  .file-btn { min-height: 40px; padding: 6px 10px; }
  .code-block .copy-code { min-height: 40px; padding: 8px 12px; }
  .error-retry { min-height: 40px; padding: 10px 16px; }
  .cookie-accept, .cookie-dismiss { min-height: 44px; }
  .composer-meta { flex-wrap: wrap; }
}
@media (max-width: 480px) {
  /* The topbar status pill crowds the header on very small phones; the
     same "Free · No sign-up" message still shows in the welcome hero. */
  .topbar .status-pill { display: none; }
  /* P1 (v30): the welcome pill is the mobile-only copy of the topbar
     pill — hidden on desktop, shown here. */
  .hero-pill { display: inline-block; }
}

/* ---------- v27 additions: voice input (mic) + read aloud ---------- */
/* Mic button: same 44px circular button as Send, same gradient when
   idle; while listening it pulses red so the recording state is
   obvious at a glance. */
#micBtn {
  flex: 0 0 auto; width: 44px; height: 44px; min-width: 44px; min-height: 44px; border-radius: 50%;
  border: none; display: inline-flex; align-items: center; justify-content: center;
  font-size: 17px; background: var(--bg-soft); border: 1px solid var(--border); color: var(--text);
}
#micBtn:hover { background: #3a3a3a; }
#micBtn.listening {
  background: #7a2e2e; border-color: #f93a37; color: #fff;
  animation: mic-pulse 1.2s ease-in-out infinite;
}
@keyframes mic-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(249, 58, 55, 0.45); }
  50% { box-shadow: 0 0 0 8px rgba(249, 58, 55, 0); }
}
/* "Listening…" status line in the composer meta row. */
.mic-status { color: #ff9d9d; font-weight: 600; }
/* Speaker button on assistant replies: same quiet text-button style
   as Copy/Regenerate; while its reply is playing it turns accent. */
.msg-actions .speak-btn.speaking { background: var(--accent); color: #fff; font-weight: 600; }
.msg-actions .speak-btn.speaking:hover { background: var(--accent-hover); color: #fff; }
@media (prefers-reduced-motion: reduce) {
  #micBtn.listening { animation: none; }
}
@media (max-width: 760px) {
  #micBtn { min-width: 44px; min-height: 44px; width: 44px; height: 44px; }
}

/* ---------- v28 fix: chat view is one full viewport tall ---------- */
/* v26 put the long content section inside <main> as a flex sibling of
   .chat-scroll, in a fixed 100dvh column — it stole all the space and
   crushed .chat-scroll to 24px on mobile (chat invisible). Now <main> is
   the page scroller and .chat-view is exactly one viewport tall: the
   topbar + chat + composer always fill the screen, and the disclaimer,
   quick links and content section scroll below inside .main. */
.main { overflow-y: auto; }
.chat-view { flex: none; height: 100%; display: flex; flex-direction: column; min-height: 0; }
.chat-scroll { min-height: 0; }

/* ---------- v29 additions: file attachments ---------- */
/* Attach button: same 44px circular button as the mic button. */
#attachBtn {
  flex: 0 0 auto; width: 44px; height: 44px; min-width: 44px; min-height: 44px; border-radius: 50%;
  border: 1px solid var(--border); display: inline-flex; align-items: center; justify-content: center;
  font-size: 17px; background: var(--bg-soft); color: var(--text);
}
#attachBtn:hover { background: #3a3a3a; }
/* Pending-attachment chip above the composer box. */
.attach-chip {
  display: flex; align-items: center; gap: 10px; max-width: 760px; margin: 0 auto 8px;
  background: var(--bg-soft); border: 1px solid var(--border); border-radius: 12px; padding: 8px 12px;
}
.attach-thumb { width: 40px; height: 40px; object-fit: cover; border-radius: 8px; flex: 0 0 40px; }
.attach-icon { font-size: 20px; flex: 0 0 auto; }
.attach-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; color: var(--text-dim); }
.attach-remove {
  flex: 0 0 auto; min-width: 40px; min-height: 40px; width: 40px; height: 40px; border-radius: 50%;
  border: none; background: transparent; color: var(--text-faint); font-size: 15px; cursor: pointer;
}
.attach-remove:hover { background: #3a3a3a; color: var(--text); }
/* File chip above a user message's question text. */
.msg-file-chip { display: flex; align-items: center; gap: 10px; margin: 0 0 8px; }
.msg-file-thumb { width: 40px; height: 40px; object-fit: cover; border-radius: 8px; flex: 0 0 40px; }
.msg-file-icon { font-size: 20px; flex: 0 0 auto; }
.msg-file-name { font-size: 13px; color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 760px) {
  #attachBtn { min-width: 44px; min-height: 44px; width: 44px; height: 44px; }
}

/* ---------- v30 additions: back-to-chat button (M3) ---------- */
/* Floating "Back to chat" — hidden while the visitor is at the top of
   the page (so it never covers the composer), shown once .main has
   scrolled past the chat view (app.js toggles .show). Fixed to the
   viewport; when the cookie banner is up it sits above the banner. */
.back-to-chat {
  position: fixed; right: 16px; z-index: 90;
  bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  background: var(--accent); color: #fff; border: none;
  border-radius: 999px; padding: 10px 16px; font-size: 14px; font-weight: 600;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
  opacity: 0; pointer-events: none; transform: translateY(8px);
  transition: opacity 0.2s ease, transform 0.2s ease;
}
.back-to-chat.show { opacity: 1; pointer-events: auto; transform: translateY(0); }
.back-to-chat:hover { background: var(--accent-hover); }
body.has-cookie-banner .back-to-chat { bottom: calc(var(--cookie-banner-h, 64px) + 16px + env(safe-area-inset-bottom, 0px)); }
@media (prefers-reduced-motion: reduce) {
  .back-to-chat { transition: none; }
}
