/* ── JBS Design System Tokens ───────────────────────────────────────────── */
:root {
  /* brand */
  --jbs-navy:       #0E2748;
  --jbs-navy-deep:  #081B33;
  --jbs-cyan:       #1E7AE0;
  --jbs-cyan-deep:  #1763BE;
  --deep:           #0A356B;

  /* surfaces */
  --bg-app:            #F5F7FA;
  --bg-surface:        #FFFFFF;
  --bg-surface-raised: #F7F9FC;
  --bg-glass:          rgba(14,39,72,0.03);
  --bg-glass-strong:   rgba(14,39,72,0.05);

  /* text */
  --text-primary:   #0E2748;
  --text-secondary: #4C5566;
  --text-muted:     #5C6473;
  --text-dim:       #9AA4B2;

  /* borders */
  --border-default: #E6EBF2;
  --border-subtle:  #EEF1F6;
  --border-strong:  #D7E2F1;

  /* accent */
  --accent:          #1E7AE0;
  --accent-primary:  #1763BE;
  --accent-gradient: linear-gradient(135deg, #1E7AE0, #1763BE);
  --title-gradient:  linear-gradient(180deg, #0E2748 12%, rgba(14,39,72,0.55) 100%);
  --chip-bg:   #E8F1FB;
  --chip-text: #1763BE;

  /* semantic */
  --positive: #2E8B2E;
  --negative: #D32F2F;
  --warning:  #B7791F;
  --info:     #1763BE;

  /* elevation */
  --shadow-card:       0 2px 12px  rgba(14,39,72,0.06);
  --shadow-card-hover: 0 10px 30px rgba(14,39,72,0.10);
  --shadow-cta:        0 8px 24px  rgba(30,122,224,0.25);

  /* layout */
  --chat-col:     860px;  /* shared reading column: messages, composer, banner, empty state */
  --mobile-bar-h: 52px;   /* mobile top bar height; the drawer + account menu anchor to it */

  /* chrome + fx */
  --nav-bg:     rgba(245,247,250,0.86);
  --nav-border: #E6EBF2;
  --hero-radial:
    radial-gradient(circle at 18% 30%, rgba(30,122,224,0.14) 0%, transparent 45%),
    radial-gradient(circle at 82% 72%, rgba(10,53,107,0.08) 0%, transparent 50%);
  --hero-grid-color: rgba(14,39,72,0.08);
  --orb-opacity: 0.16;

  --ease-out: cubic-bezier(.16,1,.3,1);

  /* Fades a session title out under the row's action buttons. 96px clears the
     three 26px controls and their 8px gaps; the 16px ramp keeps the cut soft.
     A mask carries no colour, so it holds in every theme and on the active row. */
  --session-fade: linear-gradient(to right, #000 calc(100% - 112px), transparent calc(100% - 96px));
}

[data-theme="dark"] {
  --bg-app:            #081325;
  --bg-surface:        #0E2748;
  --bg-surface-raised: #122E50;
  --bg-glass:          rgba(255,255,255,0.04);
  --bg-glass-strong:   rgba(255,255,255,0.06);
  --text-primary:   #FFFFFF;
  --text-secondary: rgba(255,255,255,0.75);
  --text-muted:     rgba(255,255,255,0.55);
  --text-dim:       rgba(255,255,255,0.38);
  --border-default: rgba(255,255,255,0.10);
  --border-subtle:  rgba(255,255,255,0.06);
  --border-strong:  rgba(255,255,255,0.18);
  --accent:          #4FA0F0;
  --accent-primary:  #4FA0F0;
  --accent-gradient: linear-gradient(135deg, #1E7AE0, #4FA0F0);
  --title-gradient:  linear-gradient(180deg, #fff 15%, rgba(255,255,255,0.55) 100%);
  --chip-bg:   rgba(79,160,240,0.16);
  --chip-text: #9DC3F0;
  --positive: #5FBF5F;  --negative: #F07A7A;
  --shadow-card:       0 4px 16px  rgba(0,0,0,0.35);
  --shadow-card-hover: 0 12px 32px rgba(0,0,0,0.45);
  --nav-bg:     rgba(8,19,37,0.72);
  --nav-border: rgba(255,255,255,0.08);
  --hero-radial:
    radial-gradient(circle at 18% 30%, rgba(30,122,224,0.22) 0%, transparent 45%),
    radial-gradient(circle at 82% 72%, rgba(10,53,107,0.28) 0%, transparent 50%);
  --hero-grid-color: rgba(255,255,255,0.16);
  --orb-opacity: 0.36;
}

/* Teams reports `contrast` for its high-contrast theme, handed over through the
   SDK context. Maximise separation rather than softening it the way dark mode
   does: pure black canvas, pure white text, borders at full strength, and no
   shadows or gradients -- both of those read as mud at this contrast ratio. */
[data-theme="contrast"] {
  /* Five rules build their own linear-gradient() from the brand tokens rather
     than using --accent-gradient, so overriding only the accent left the New
     chat CTA fading cyan-to-navy on a black canvas. Override the brand tokens
     too, and to the same cyan: a gradient gives an element variable contrast
     across its own surface, which is the opposite of what this theme is for. */
  --jbs-cyan:       #00FFFF;
  --jbs-cyan-deep:  #00FFFF;
  --jbs-navy:       #00FFFF;
  --bg-app:            #000000;
  --bg-surface:        #000000;
  --bg-surface-raised: #1A1A1A;
  --bg-glass:          rgba(255,255,255,0.10);
  --bg-glass-strong:   rgba(255,255,255,0.20);
  --text-primary:   #FFFFFF;
  --text-secondary: #FFFFFF;
  --text-muted:     #FFFF00;
  --text-dim:       #FFFF00;
  --border-default: #FFFFFF;
  --border-subtle:  #FFFFFF;
  --border-strong:  #FFFFFF;
  --accent:          #00FFFF;
  --accent-primary:  #00FFFF;
  --accent-gradient: #00FFFF;
  --title-gradient:  #FFFFFF;
  --chip-bg:   #000000;
  --chip-text: #00FFFF;
  --positive: #00FF00;
  --negative: #FF6060;
  --warning:  #FFFF00;
  --info:     #00FFFF;
  --shadow-card:       none;
  --shadow-card-hover: none;
  --shadow-cta:        none;
  --nav-bg:     #000000;
  --nav-border: #FFFFFF;
  --hero-radial: none;
  --hero-grid-color: rgba(255,255,255,0.30);
  --orb-opacity: 0;
}

/* Everything that sits on an accent fill hardcodes color:#fff, which is ~1.1:1
   against cyan. Each of these needs dark text instead. Keep this list in step
   with the rules that consume --jbs-cyan or --accent-gradient as a background. */
[data-theme="contrast"] .btn--primary,
[data-theme="contrast"] .send,
[data-theme="contrast"] .avatar,
[data-theme="contrast"] .sidebar__new,
[data-theme="contrast"] .msg--user,
[data-theme="contrast"] .msg-avatar--user,
[data-theme="contrast"] .mobile-bar__avatar,
[data-theme="contrast"] a.source-chip:active { color: #000000; }

/* ── Reset ───────────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
[hidden] { display: none !important; }

body {
  font-family: 'Plus Jakarta Sans', -apple-system, 'Segoe UI', sans-serif;
  font-size: 14px;
  line-height: 1.55;
  color: var(--text-primary);
  background: var(--bg-app);
  display: flex;
  flex-direction: column;
  height: 100vh;
  /* dvh tracks the viewport as mobile browsers show/hide the URL bar; without it
     the composer ends up underneath that chrome. The 100vh line above is the
     fallback -- browsers without dvh support simply ignore the line below. */
  height: 100dvh;
  overflow: hidden;
}

h1, h2, h3, .display {
  font-family: 'Archivo', 'Plus Jakarta Sans', sans-serif;
  letter-spacing: -0.02em;
}

/* ── Sidebar brand ───────────────────────────────────────────────────────── */
.sidebar__brand {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 16px 14px 10px;
  flex-shrink: 0;
}

.sidebar__brand-info { display: flex; align-items: center; gap: 10px; min-width: 0; }

.sidebar__logo-btn {
  display: flex;
  align-items: center;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  flex-shrink: 0;
}
.sidebar__logo-btn-icon { display: none; }

.sidebar__logo { height: 28px; width: auto; flex-shrink: 0; }
.logo-white { display: none; }
/* Contrast is a dark canvas too, so it needs the white mark -- the navy one is
   nearly invisible on black. */
[data-theme="dark"] .logo-color,
[data-theme="contrast"] .logo-color { display: none; }
[data-theme="dark"] .logo-white,
[data-theme="contrast"] .logo-white { display: block; }

.sidebar__product {
  font-family: 'Archivo';
  font-weight: 700;
  font-size: 16px;
  color: var(--text-primary);
  white-space: nowrap;
}

.sidebar__badge {
  padding: 3px 10px;
  border-radius: 100px;
  background: var(--chip-bg);
  color: var(--chip-text);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .3px;
  white-space: nowrap;
}

.avatar {
  width: 30px; height: 30px;
  border-radius: 50%;
  background: var(--accent-gradient);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  letter-spacing: 0.02em;
}

/* ── Buttons ─────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  border-radius: 100px;
  border: 0;
  cursor: pointer;
  padding: 8px 16px;
  transition: background 160ms, opacity 160ms, transform 200ms var(--ease-out), box-shadow 200ms;
}
.btn:disabled { opacity: 0.45; cursor: not-allowed; }

.btn--primary { background: var(--accent-gradient); color: #fff; box-shadow: var(--shadow-cta); }
@media (hover: hover) {
  .btn--primary:hover:not(:disabled) { transform: translateY(-1px); box-shadow: 0 14px 36px rgba(23,99,190,.35); }
}
.btn--primary:active:not(:disabled) { transform: translateY(0); box-shadow: 0 4px 12px rgba(30,122,224,.30); }

.btn--ghost { background: transparent; color: var(--text-primary); border: 1px solid var(--border-default); }
@media (hover: hover) {
  .btn--ghost:hover:not(:disabled) { background: var(--bg-glass-strong); }
}
.btn--ghost:active:not(:disabled) { background: var(--chip-bg); border-color: var(--accent-primary); }

/* ── Login screen (standalone browser, not yet authenticated) ──────────────── */
.login-screen {
  flex: 1;
  min-height: 0;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: var(--bg-app);
}
.login-card {
  width: 100%;
  max-width: 400px;
  background: var(--bg-surface);
  border: 1px solid var(--border-default);
  border-radius: 20px;
  box-shadow: var(--shadow-card);
  padding: 40px 32px 32px;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}
.login-card__logo { height: 32px; width: auto; margin-bottom: 20px; }
.login-card__title {
  font-family: 'Archivo';
  font-weight: 700;
  font-size: 24px;
  color: var(--text-primary);
  margin-bottom: 6px;
}
.login-card__sub { color: var(--text-muted); font-size: 14px; margin-bottom: 24px; }
.login-card__spinner { display: flex; gap: 5px; margin: -8px 0 24px; }
.login-card__spinner span {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--accent-primary); animation: dot 1.2s infinite;
}
.login-card__spinner span:nth-child(2) { animation-delay: .15s; }
.login-card__spinner span:nth-child(3) { animation-delay: .3s; }
.login-card__cta { width: 100%; justify-content: center; padding: 12px 20px; font-size: 14px; }
.login-card__error { margin-top: 14px; font-size: 13px; color: var(--negative); }
.login-card__footer {
  margin-top: 20px;
  font-size: 12px;
  color: var(--text-dim);
  line-height: 1.5;
}

/* ── Two-column layout ───────────────────────────────────────────────────── */
.layout {
  flex: 1;
  min-height: 0;
  width: 100%;
  display: grid;
  /* Three tracks, no gap: the middle one IS the old 16px gap, now occupied by the
     resize handle. Visually identical, but the dead space becomes the grab target
     instead of needing extra chrome. */
  grid-template-columns: var(--sidebar-w, 288px) 16px minmax(0,1fr);
  gap: 0;
  padding: 16px 24px 20px;
  overflow: hidden;
  transition: grid-template-columns 200ms var(--ease-out);
}
/* A width transition is right for the collapse toggle but fights the pointer
   during a drag, where the track must track the cursor exactly. */
html.sidebar-resizing .layout { transition: none; }
html.sidebar-resizing { cursor: col-resize; user-select: none; }

/* ── Sidebar resize handle ───────────────────────────────────────────────────
   Invisible at rest so the 16px gutter still reads as whitespace; a grip appears
   on hover or focus to signify that the edge is draggable. */
.sidebar-resizer {
  align-self: stretch;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: col-resize;
  touch-action: none;          /* let pointermove drive the drag, not a scroll */
  background: none;
  border: none;
  padding: 0;
}
.sidebar-resizer__grip {
  width: 4px;
  height: 40px;
  border-radius: 100px;
  background: var(--border-strong);
  opacity: 0;
  transition: opacity 160ms var(--ease-out), background 160ms;
}
@media (hover: hover) {
  .sidebar-resizer:hover .sidebar-resizer__grip { opacity: 1; }
}
.sidebar-resizer:focus-visible { outline: none; }
.sidebar-resizer:focus-visible .sidebar-resizer__grip {
  opacity: 1;
  background: var(--accent-primary);
  height: 64px;
}
html.sidebar-resizing .sidebar-resizer__grip {
  opacity: 1;
  background: var(--accent-primary);
}
/* sidebar-collapsed is a DESKTOP-ONLY icon-rail concept. Scope every rule it
   drives to >=768px: below that the sidebar is an off-canvas drawer, and an
   unscoped `html.sidebar-collapsed ...` (specificity 0,2,1) would otherwise beat
   the mobile rules -- squeezing the chat into the 72px track and hiding the
   drawer's own contents. Mobile uses max-width:767.98px, so 768 is the exact
   companion boundary the mobile breakpoint was chosen to pair with. */
@media (min-width: 768px) {
  /* The rail is a fixed 72px, so resizing is meaningless while collapsed --
     the handle hides and stops taking focus rather than dragging to no effect. */
  html.sidebar-collapsed .layout { grid-template-columns: 72px 16px minmax(0,1fr); }
  html.sidebar-collapsed .sidebar-resizer { visibility: hidden; }

  /* Collapsed sidebar becomes a narrow icon rail -- it stays visible and
     interactive (logo, new-chat, avatar), only the elements that don't fit
     an icon-only rail (text labels, session list) are hidden. The explicit
     toggle button also hides here -- the logo itself takes over as the
     expand control, swapping to the same icon on hover. */
  html.sidebar-collapsed .sidebar__product,
  html.sidebar-collapsed .sidebar__badge,
  html.sidebar-collapsed #sidebar-toggle,
  html.sidebar-collapsed .sidebar__new-label,
  html.sidebar-collapsed .sidebar__label,
  html.sidebar-collapsed #session-list,
  html.sidebar-collapsed #pinned-section,
  html.sidebar-collapsed .user-panel__info {
    display: none;
  }
  html.sidebar-collapsed .sidebar__brand {
    justify-content: center;
    padding-left: 0;
    padding-right: 0;
  }
  html.sidebar-collapsed .sidebar__logo { height: 24px; }
  /* Hover-reveal: swaps the logo for an expand icon. Pointer-only by nature --
     on touch the logo simply stays, which is the correct outcome since the icon
     was only ever a hint that the collapsed rail is clickable. */
  @media (hover: hover) {
    html.sidebar-collapsed .sidebar__logo-btn:hover .sidebar__logo { display: none; }
    html.sidebar-collapsed .sidebar__logo-btn:hover .sidebar__logo-btn-icon { display: block; }
  }
  html.sidebar-collapsed .sidebar__header { justify-content: center; }
  html.sidebar-collapsed .sidebar__new {
    flex: none;
    width: 30px;
    height: 30px;
    padding: 0;
    border-radius: 50%;
  }
  html.sidebar-collapsed .user-panel__trigger {
    justify-content: center;
    padding: 6px 0;
  }
}

/* ── Sidebar ─────────────────────────────────────────────────────────────── */
.sidebar {
  display: flex;
  flex-direction: column;
  min-height: 0;
  background: var(--bg-surface);
  border: 1px solid var(--border-default);
  border-radius: 20px;
  box-shadow: var(--shadow-card);
  overflow: hidden;
}

.sidebar__header {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 14px 14px 10px;
}
.sidebar__new {
  flex: 1;
  padding: 10px 18px;
  border: none;
  border-radius: 100px;
  color: #fff;
  background: linear-gradient(135deg, var(--jbs-cyan), var(--jbs-navy));
  box-shadow: var(--shadow-cta);
  font-weight: 600;
  font-size: 13px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  transition: transform 200ms var(--ease-out), box-shadow 200ms;
}
@media (hover: hover) {
  .sidebar__new:hover { transform: translateY(-1px); }
}
.sidebar__new:active { transform: translateY(0); }
/* The '+' glyph is centred on the font's math axis, roughly half the x-height,
   while the label's caps centre higher -- so a box-centred '+' renders 1.81px
   low (measured from rendered pixels at 8x, not estimated). Nudge it optically;
   2px is inside the sub-scale optical allowance the guideline documents. */
.sidebar__new-icon { font-size: 16px; line-height: 1; transform: translateY(-2px); }
.sidebar__new-label { white-space: nowrap; }
@media (min-width: 768px) {
  html.sidebar-collapsed .sidebar__new-icon { font-size: 16px; }
}

.sidebar-toggle {
  width: 30px; height: 30px;
  border-radius: 50%;
  border: 1px solid var(--border-default);
  background: var(--bg-glass);
  color: var(--text-secondary);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  flex-shrink: 0;
  transition: background 160ms, color 160ms;
}
@media (hover: hover) {
  .sidebar-toggle:hover { background: var(--chip-bg); color: var(--accent-primary); }
}
.sidebar-toggle:active { background: var(--accent-primary); color: #fff; }

.sidebar__label {
  padding: 0 14px 6px;
  font-family: 'Archivo';
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  color: var(--text-dim);
}

.session-list {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 0 8px 12px;
  scrollbar-width: thin;
}

.session-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 9px 10px;
  border-radius: 12px;
  cursor: pointer;
  user-select: none;
  transition: background 160ms var(--ease-out);
}
@media (hover: hover) {
  .session-item:hover { background: var(--bg-glass-strong); }
}
.session-item:active { background: var(--chip-bg); }
.session-item--active { background: var(--chip-bg); }

.session-item__info {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 1;
  min-width: 0;
}

/* Out of flow on purpose. As inline flex children the three controls reserved
   26px each plus gaps -- ~102px, 41% of a 250px row -- even at opacity 0, so
   titles truncated with plenty of space to spare. Absolute positioning hands
   that width back to the title. */
.session-item__actions {
  position: absolute;
  right: 10px;                 /* matches the row's own side padding */
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  gap: 8px;
}

/* Once the controls show they overlap the tail of a long title, so fade the
   title out beneath them. A mask needs no colour and therefore stays correct in
   every theme and on the active row, which a solid backdrop would not.
   -webkit- prefix included: mobile webview is a supported surface. */
@media (hover: hover) {
  .session-item:hover .session-item__info {
    -webkit-mask-image: var(--session-fade);
    mask-image: var(--session-fade);
  }
}
.session-item--active .session-item__info,
.session-item--pinned .session-item__info,
.session-item:focus-within .session-item__info {
  -webkit-mask-image: var(--session-fade);
  mask-image: var(--session-fade);
}
@media (pointer: coarse) {
  /* Controls are always visible here, so the fade is permanent. */
  .session-item__info {
    -webkit-mask-image: var(--session-fade);
    mask-image: var(--session-fade);
  }
}

.session-item__title {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  outline: none;
  border-radius: 2px;
}
/* Rename failed: flash the title in --negative, matching the pin-failure idiom.
   The element is no longer contenteditable by this point, so the editing border
   is gone and colour has to carry the signal. */
@keyframes title-error-flash { 0%, 100% { color: var(--text-primary); } 50% { color: var(--negative); } }
.session-item__title--error { animation: title-error-flash 400ms; }
.session-item__title[contenteditable="true"] {
  background: var(--bg-surface);
  border: 1px solid var(--accent-primary);
  white-space: nowrap;
  overflow: visible;
  padding: 0 2px;
}

.session-item__time { font-size: 11px; color: var(--text-dim); }

.session-item__icon-btn {
  width: 26px; height: 26px;
  border-radius: 50%;
  border: none;
  background: none;
  color: var(--text-dim);
  opacity: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  cursor: pointer;
  transition: opacity 120ms, background 160ms, color 160ms;
}
/* Split deliberately: the active-row and focus-visible reveals must stay
   unguarded so they keep working on touch and via the keyboard. Only the
   hover-driven reveal is pointer-conditional. */
.session-item--active .session-item__icon-btn:not(:disabled),
.session-item__icon-btn:focus-visible:not(:disabled) { opacity: 1; }
@media (hover: hover) {
  .session-item:hover .session-item__icon-btn:not(:disabled) { opacity: 1; }
  .session-item__delete:hover { background: var(--chip-bg); color: var(--negative); }
  .session-item__edit:hover { background: var(--chip-bg); color: var(--accent-primary); }
}
.session-item__delete:active:not(:disabled) { background: var(--negative); color: #fff; }
.session-item__edit:active:not(:disabled) { background: var(--accent-primary); color: #fff; }
/* Touch has no hover to reveal these, so a non-active row showed no delete,
   edit, or pin at all -- the controls existed but could not be discovered.
   Show them unconditionally where the pointer is coarse. */
@media (pointer: coarse) {
  .session-item__icon-btn:not(:disabled) { opacity: 1; }
}
.session-item__pin--active {
  opacity: 1;
  color: var(--accent-primary);
}
@media (hover: hover) {
  .session-item__pin:not(.session-item__pin--active):hover { background: var(--chip-bg); color: var(--accent-primary); }
}
.session-item__pin:active:not(:disabled) { background: var(--accent-primary); color: #fff; }
.session-item__icon-btn:disabled {
  opacity: 0.3;
  cursor: not-allowed;
}
@media (hover: hover) {
  .session-item__icon-btn:disabled:hover { background: none; color: var(--text-dim); }
}
.session-item__pin--error { animation: pin-error-flash 400ms; }
@keyframes pin-error-flash { 0%, 100% { color: var(--text-dim); } 50% { color: var(--negative); } }

#pinned-section:not([hidden]) {
  border-bottom: 1px solid var(--border-subtle);
  padding-bottom: 6px;
  margin-bottom: 6px;
}
.session-list--pinned { overflow: visible; padding: 0 8px; }

.user-panel {
  position: relative;
  margin-top: auto;
  border-top: 1px solid var(--border-default);
  padding: 10px 14px;
}
.user-panel__trigger {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  background: none;
  border: none;
  border-radius: 12px;
  padding: 6px;
  cursor: pointer;
  text-align: left;
  transition: background 160ms var(--ease-out);
}
@media (hover: hover) {
  .user-panel__trigger:hover { background: var(--bg-glass-strong); }
}
.user-panel__trigger:active { background: var(--chip-bg); }
.user-panel__info {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
  flex: 1;
}
.user-panel__name {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.user-panel__email {
  font-size: 11px;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.avatar--sm { width: 26px; height: 26px; font-size: 11px; flex-shrink: 0; }
.user-panel__menu {
  position: absolute;
  left: 14px; right: 14px;
  bottom: calc(100% + 6px);
  background: var(--bg-surface);
  border: 1px solid var(--border-default);
  border-radius: 12px;
  box-shadow: var(--shadow-card-hover);
  padding: 6px;
  z-index: 10;
}
.user-panel__menu-item {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  border-radius: 8px;
  padding: 8px 10px;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-primary);
  cursor: pointer;
  transition: background 160ms;
}
@media (hover: hover) {
  .user-panel__menu-item:hover:not(:disabled) { background: var(--bg-glass-strong); }
}
.user-panel__menu-item:active:not(:disabled) { background: var(--chip-bg); }
.user-panel__menu-item:disabled { opacity: 0.45; cursor: not-allowed; }

.session-list__more {
  display: block;
  width: 100%;
  background: none;
  border: none;
  padding: 10px 14px;
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
  cursor: pointer;
  text-align: center;
  transition: color 160ms;
}
@media (hover: hover) {
  .session-list__more:hover:not(:disabled) { color: var(--text-primary); }
}
.session-list__more:active:not(:disabled) { color: var(--accent-primary); }
.session-list__more:disabled { cursor: default; opacity: 0.6; }

/* ── Chat shell ──────────────────────────────────────────────────────────── */
.chat-shell {
  position: relative;
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  background: var(--bg-surface-raised);
  border: 1px solid var(--border-subtle);
  border-radius: 28px;
  box-shadow: var(--shadow-card);
  overflow: hidden;
}
.chat-shell::before { content: ''; position: absolute; inset: 0; background: var(--hero-radial); pointer-events: none; }

.chat-fx__grid {
  position: absolute; inset: 0; opacity: .5; pointer-events: none;
  background-image: linear-gradient(var(--hero-grid-color) 1px, transparent 1px),
                     linear-gradient(90deg, var(--hero-grid-color) 1px, transparent 1px);
  background-size: 60px 60px;
  mask-image: radial-gradient(circle at 50% 30%, #000 0%, transparent 70%);
}
.chat-fx__orb { position: absolute; border-radius: 50%; filter: blur(40px); opacity: var(--orb-opacity); pointer-events: none; }
.chat-fx__orb--1 { width: 300px; height: 300px; background: var(--jbs-cyan); top: -90px; right: 8%; }
.chat-fx__orb--2 { width: 220px; height: 220px; background: var(--deep); bottom: -70px; left: 6%; opacity: calc(var(--orb-opacity) * 0.7); }

.chat-body {
  position: relative;
  z-index: 1;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 24px 24px 12px;
  display: flex;
  flex-direction: column;
}
.chat-body::-webkit-scrollbar { width: 6px; }
.chat-body::-webkit-scrollbar-track { background: transparent; }
.chat-body::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 999px; }

/* ── Empty state ─────────────────────────────────────────────────────────── */
.empty-state {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 32px 20px;
  text-align: center;
  gap: 16px;
  max-width: var(--chat-col);
  margin: 0 auto;
  width: 100%;
}
.empty-state__icon {
  width: 56px; height: 56px;
  border-radius: 16px;
  background: var(--accent-gradient);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 8px 24px rgba(30,122,224,.35);
}
.empty-state__eyebrow {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: 'Archivo';
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 3px;
  text-transform: uppercase;
  color: var(--accent-primary);
}
.empty-state__eyebrow::before, .empty-state__eyebrow::after {
  content: ''; width: 32px; height: 2px; background: var(--accent-gradient);
}
.empty-state__title {
  font-family: 'Archivo';
  font-weight: 800;
  font-size: clamp(32px, 4vw, 48px);
  letter-spacing: -.03em;
  line-height: 1;
  background: var(--title-gradient);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}
.empty-state__sub { font-size: 16px; color: var(--text-secondary); max-width: 460px; }
.empty-state__trust { font-size: 12px; color: var(--text-dim); }

.suggestions { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; margin-top: 8px; max-width: 560px; }
.suggestion {
  font-family: inherit;
  background: var(--bg-surface);
  border: 1px solid var(--border-default);
  border-radius: 999px;
  padding: 9px 16px;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-primary);
  box-shadow: var(--shadow-card);
  cursor: pointer;
  text-align: left;
  transition: transform 200ms var(--ease-out), box-shadow 200ms, border-color 160ms, color 160ms;
}
@media (hover: hover) {
  .suggestion:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-card-hover);
    border-color: var(--accent-primary);
    color: var(--accent-primary);
  }
}
.suggestion:active {
  transform: translateY(0);
  box-shadow: var(--shadow-card);
  border-color: var(--accent-primary);
  color: var(--accent-primary);
}

/* Follow-up chips under an answer: left-aligned wrapping row, reusing the
   .suggestion look. On mobile the existing `.suggestion { width: 100% }` rule
   (in the max-width:767.98px block) stacks them full-width; the row wraps and
   lives inside the --chat-col column, so it never causes horizontal overflow. */
.followups { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.followup { font-size: 13px; }

/* ── Service desk tickets ─────────────────────────────────────────────────── */
/* Single entry point on the empty state. The request types live in the picker
   (rendered into the conversation) so this stays one row however many templates
   IT adds. */
.ticket-section { margin-top: 24px; display: flex; justify-content: center; }
.ticket-open {
  font-family: inherit;
  display: flex;
  align-items: center;
  gap: 11px;
  text-align: left;
  background: var(--bg-surface);
  border: 1px solid var(--border-default);
  border-radius: 14px;
  padding: 11px 18px 11px 14px;
  cursor: pointer;
  box-shadow: var(--shadow-card);
  transition: transform 200ms var(--ease-out), box-shadow 200ms, border-color 160ms;
}
@media (hover: hover) {
  .ticket-open:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-card-hover);
    border-color: var(--accent-primary);
  }
}
.ticket-open__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  flex-shrink: 0;
  border-radius: 9px;
  background: var(--accent-primary);
  color: #fff;
}
.ticket-open__text { display: flex; flex-direction: column; gap: 2px; }
.ticket-open__title { font-size: 13px; font-weight: 600; color: var(--text-primary); }
.ticket-open__sub { font-size: 12px; color: var(--text-secondary); }

/* Request types, listed inside an assistant message. Column rather than wrap:
   these read as a menu of choices, and a ragged wrapped grid is harder to scan. */
.ticket-picker { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
.ticket-picker .ticket-template { width: 100%; }
.ticket-template {
  font-family: inherit;
  display: flex;
  flex-direction: column;
  gap: 3px;
  text-align: left;
  background: var(--bg-surface);
  border: 1px solid var(--border-default);
  border-radius: 14px;
  padding: 11px 16px;
  cursor: pointer;
  box-shadow: var(--shadow-card);
  transition: transform 200ms var(--ease-out), box-shadow 200ms, border-color 160ms;
}
@media (hover: hover) {
  .ticket-template:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-card-hover);
    border-color: var(--accent-primary);
  }
}
.ticket-template__title { font-size: 13px; font-weight: 600; color: var(--text-primary); }
.ticket-template__blurb { font-size: 12px; color: var(--text-secondary); }

/* In-conversation wizard step. */
.ticket-step .ticket-intro { margin: 0 0 10px; }
.ticket-step .ticket-prompt { margin: 0; font-weight: 600; }
.ticket-step .ticket-help { margin: 4px 0 0; font-size: 12px; color: var(--text-secondary); }
/* --negative is redefined in the dark-theme block, so the tint is derived from
   currentColor rather than a second hardcoded literal that would not follow it. */
.ticket-step .ticket-error {
  margin: 0 0 10px;
  font-size: 13px;
  color: var(--negative);
  background: color-mix(in srgb, currentColor 10%, transparent);
  border-radius: 8px;
  padding: 8px 10px;
}
.ticket-step .ticket-progress { margin: 10px 0 0; font-size: 11px; color: var(--text-secondary); }
.ticket-step .ticket-outcome { margin: 0; }

.ticket-controls { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
/* Controls of a step the user has moved past stay visible as transcript but are
   inert; fading them makes that state legible rather than looking broken. */
.ticket-controls--spent { opacity: 0.45; }

.ticket-btn {
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  border-radius: 999px;
  padding: 8px 15px;
  cursor: pointer;
  border: 1px solid var(--border-default);
  background: var(--bg-surface);
  color: var(--text-primary);
  transition: border-color 160ms, color 160ms, background 160ms, opacity 160ms;
}
.ticket-btn:disabled { cursor: default; }
@media (hover: hover) {
  .ticket-btn:not(:disabled):hover { border-color: var(--accent-primary); color: var(--accent-primary); }
}
.ticket-btn--primary {
  background: var(--accent-primary);
  border-color: var(--accent-primary);
  color: #fff;
}
@media (hover: hover) {
  .ticket-btn--primary:not(:disabled):hover { filter: brightness(1.06); color: #fff; }
}
.ticket-btn--ghost { background: transparent; color: var(--text-secondary); font-weight: 500; }
.ticket-link { display: inline-block; margin-top: 12px; text-decoration: none; }

/* Review step: label above value, so long email addresses never get squeezed
   into a narrow second column on mobile. */
.ticket-summary { margin: 12px 0 0; display: flex; flex-direction: column; gap: 8px; }
.ticket-summary dt { font-size: 12px; color: var(--text-secondary); }
.ticket-summary dd { margin: 2px 0 0; font-size: 13px; font-weight: 600; word-break: break-word; }

/* ── Messages ────────────────────────────────────────────────────────────── */
.messages { display: flex; flex-direction: column; gap: 20px; max-width: var(--chat-col); margin: 0 auto; width: 100%; }

.msg-row { display: flex; align-items: flex-start; gap: 12px; animation: msg-in .35s var(--ease-out) both; }
.msg-row--user { flex-direction: row-reverse; }
@keyframes msg-in { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: translateY(0); } }

.msg-avatar { flex-shrink: 0; display: flex; align-items: center; justify-content: center; margin-top: 2px; }
.msg-avatar--bot {
  width: 32px; height: 32px; border-radius: 10px; color: #fff;
  background: var(--accent-gradient);
  box-shadow: 0 4px 12px rgba(30,122,224,.30);
}
.msg-avatar--user {
  width: 32px; height: 32px; border-radius: 50%; color: #fff;
  background: linear-gradient(135deg, var(--jbs-cyan), var(--jbs-navy));
  font-size: 11px; font-weight: 700;
}

.msg--assistant {
  max-width: 78%;
  background: var(--bg-surface);
  border: 1px solid var(--border-default);
  border-radius: 4px 18px 18px 18px;
  box-shadow: var(--shadow-card);
  padding: 14px 18px;
  font-size: 14px;
  color: var(--text-secondary);
}
.msg--user {
  max-width: 70%;
  color: #fff;
  background: linear-gradient(135deg, var(--jbs-cyan), var(--jbs-cyan-deep));
  border-radius: 18px 4px 18px 18px;
  box-shadow: var(--shadow-cta);
  padding: 12px 18px;
  font-size: 14px;
}

.msg--assistant a { color: var(--accent-primary); }
.msg--assistant p { margin-bottom: 10px; }
.msg--assistant p:last-child { margin-bottom: 0; }
.msg--assistant ul, .msg--assistant ol { padding-left: 1.4em; margin-bottom: 10px; }
.msg--assistant li { margin-bottom: 3px; }
.msg--assistant strong { font-weight: 600; }
.msg--assistant code {
  font-family: ui-monospace, 'SF Mono', Menlo, monospace;
  font-size: 12px;
  background: var(--chip-bg);
  color: var(--chip-text);
  padding: 1px 5px;
  border-radius: 4px;
}
.msg--assistant pre {
  background: var(--bg-surface-raised);
  border: 1px solid var(--border-subtle);
  border-radius: 10px;
  padding: 12px 14px;
  overflow-x: auto;
  margin-bottom: 10px;
}
.msg--assistant pre code { background: none; color: inherit; padding: 0; font-size: 12px; }

/* ── Sources ─────────────────────────────────────────────────────────────── */
.sources {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--border-subtle);
}
.sources-label {
  font-family: 'Archivo'; font-size: 11px; font-weight: 700;
  letter-spacing: 1.5px; text-transform: uppercase; color: var(--text-dim);
}
.source-chip {
  display: inline-flex;
  padding: 3px 10px;
  border-radius: 100px;
  background: var(--chip-bg);
  color: var(--chip-text);
  font-size: 11px;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  transition: background 160ms, color 160ms;
}
@media (hover: hover) {
  a.source-chip:hover { background: var(--accent-primary); color: #fff; }
}
a.source-chip:active { background: var(--jbs-navy); color: #fff; }

/* ── Context-truncated note ──────────────────────────────────────────────── */
/* No border-top of its own -- when it follows .sources, that block's divider
   already separates it from the answer text above. */
.context-truncated-note {
  margin-top: 8px;
  font-size: 11px;
  font-style: italic;
  color: var(--text-muted);
}

/* ── Typing indicator ────────────────────────────────────────────────────── */
/* Must match .messages' column exactly -- #typing is a SIBLING of #messages, not a
   child, so it inherits none of that centering and would otherwise stretch full-width
   and pin its avatar to the far-left edge while the answer sits in the 860px column.
   (Deliberately not nested inside #messages: that element is aria-live="polite", and
   the perpetually re-animating dots would be announced repeatedly by screen readers.) */
.typing-row {
  padding-top: 4px;
  max-width: var(--chat-col);
  margin: 0 auto;
  width: 100%;
}
.typing-bubble {
  display: inline-flex; gap: 5px; padding: 14px 16px;
  background: var(--bg-surface);
  border: 1px solid var(--border-default);
  border-radius: 4px 16px 16px 16px;
  box-shadow: var(--shadow-card);
}
.typing-bubble span { width: 6px; height: 6px; border-radius: 50%; background: var(--accent-primary); animation: dot 1.2s infinite; }
.typing-bubble span:nth-child(2) { animation-delay: .15s; }
.typing-bubble span:nth-child(3) { animation-delay: .3s; }
@keyframes dot { 0%,60%,100% { transform: none; opacity: .4; } 30% { transform: translateY(-4px); opacity: 1; } }

/* Phase 2 ("generating"): same row/bubble, modifier class swaps the 3 dots for a
   shimmering 2-line skeleton. Toggled in JS (app.js) on the first streamed token. */
.typing-bubble--generating span { display: none; }
.typing-bubble--generating { flex-direction: column; gap: 6px; min-width: 120px; }
.typing-bubble--generating::before,
.typing-bubble--generating::after {
  content: "";
  display: block;
  height: 8px;
  border-radius: 4px;
  background: linear-gradient(90deg, var(--bg-glass-strong) 25%, var(--chip-bg) 50%, var(--bg-glass-strong) 75%);
  background-size: 200% 100%;
  animation: shimmer 1.4s ease-in-out infinite;
}
.typing-bubble--generating::before { width: 100%; }
.typing-bubble--generating::after  { width: 65%; }
@keyframes shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }

/* ── Feedback bar ────────────────────────────────────────────────────────── */
.feedback-bar { display: flex; flex-direction: column; margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--border-subtle); }
.feedback-bar__btns { display: flex; gap: 6px; }
.feedback-btn {
  width: 26px; height: 26px; border-radius: 8px;
  border: 1px solid var(--border-subtle);
  background: var(--bg-glass);
  color: var(--text-dim);
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background 160ms, color 160ms;
}
@media (hover: hover) {
  .feedback-btn:hover:not(:disabled) { background: var(--chip-bg); color: var(--accent-primary); }
  .feedback-btn--down:hover:not(:disabled) { color: var(--negative); }
}
.feedback-btn:active:not(:disabled) { background: var(--accent-primary); color: #fff; }
.feedback-btn--down:active:not(:disabled) { background: var(--negative); color: #fff; }
.feedback-btn:disabled { cursor: default; opacity: .5; }
.feedback-btn--up.active { background: var(--chip-bg); color: var(--accent-primary); }
.feedback-btn--down.active { background: rgba(211,47,47,0.10); color: var(--negative); }

.feedback-comment { margin-top: 8px; }
.feedback-comment textarea {
  width: 100%;
  font-family: inherit;
  font-size: 12px;
  color: var(--text-primary);
  background: var(--bg-surface);
  border: 1px solid var(--border-default);
  border-radius: 12px;
  padding: 8px 12px;
  resize: none;
  line-height: 1.5;
}
.feedback-comment textarea:focus {
  outline: none;
  border-color: var(--accent-primary);
  box-shadow: 0 0 0 3px rgba(30,122,224,.12);
}
.feedback-comment__actions { display: flex; gap: 8px; margin-top: 8px; }
.feedback-comment__actions .btn--primary { font-size: 12px; padding: 6px 14px; }
.feedback-comment__actions .btn--ghost { font-size: 12px; padding: 6px 14px; border: none; color: var(--accent-primary); background: none; }

/* ── Error banner ────────────────────────────────────────────────────────── */
.banner {
  background: rgba(211,47,47,0.10);
  color: var(--negative);
  border: 1px solid rgba(211,47,47,0.25);
  border-radius: 12px;
  padding: 10px 16px;
  font-size: 13px;
  font-weight: 600;
  margin: 0 24px 12px;
  max-width: var(--chat-col);
  margin-left: auto;
  margin-right: auto;
}

/* ── Composer ────────────────────────────────────────────────────────────── */
.composer-panel {
  padding: 12px 24px 18px;
  /* Keeps the composer clear of the home indicator on notched devices; env()
     resolves to 0px everywhere else, so this is a no-op on desktop. */
  padding-bottom: calc(18px + env(safe-area-inset-bottom, 0px));
  flex-shrink: 0;
  position: relative;
  z-index: 1;
}
.composer {
  display: flex; align-items: center; gap: 8px;
  max-width: var(--chat-col); margin: 0 auto;
  background: var(--bg-surface);
  border: 1.5px solid var(--border-default);
  border-radius: 18px;
  padding: 6px 6px 6px 8px;
  box-shadow: var(--shadow-card-hover);
  transition: border-color 160ms, box-shadow 160ms;
}
.composer:focus-within {
  border-color: var(--accent-primary);
  box-shadow: var(--shadow-card-hover), 0 0 0 3px rgba(30,122,224,.12);
}

.attach-btn {
  flex-shrink: 0;
  width: 38px; height: 38px;
  padding: 0;  /* override .btn's 8px 16px -- otherwise the 16px side padding
                  crushes the icon's content box to ~6px and it renders tiny */
  border-radius: 12px;
  background: var(--bg-glass);
  border: 1px solid var(--border-subtle);
  color: var(--text-muted);
  display: inline-flex; align-items: center; justify-content: center;
}
@media (hover: hover) {
  .attach-btn:hover:not(:disabled) { color: var(--accent-primary); border-color: var(--accent-primary); }
}
.attach-btn:active:not(:disabled) { background: var(--chip-bg); color: var(--accent-primary); border-color: var(--accent-primary); }
.attach-btn:disabled { cursor: not-allowed; opacity: .35; }

.query {
  flex: 1;
  border: 0; outline: none; background: transparent;
  font: inherit; font-size: 14px; color: var(--text-primary);
  padding: 9px 6px;
  resize: none;
  line-height: 1.5;
  max-height: 160px;
  overflow-y: auto;
}
.query::placeholder { color: var(--text-dim); }
.query:disabled { cursor: not-allowed; }

.send {
  flex-shrink: 0;
  border: none;
  border-radius: 12px;
  padding: 10px 18px;
  color: #fff;
  background: linear-gradient(135deg, var(--jbs-cyan), var(--jbs-navy));
  box-shadow: var(--shadow-cta);
  font-weight: 600;
  font-size: 13px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  transition: transform 200ms var(--ease-out), box-shadow 200ms, opacity 160ms;
}
@media (hover: hover) {
  .send:hover:not(:disabled) { transform: translateY(-1px); box-shadow: 0 14px 36px rgba(23,99,190,.35); }
}
.send:active:not(:disabled) { transform: translateY(0); box-shadow: 0 4px 12px rgba(30,122,224,.30); }
.send:disabled { opacity: .45; }
.send svg { width: 14px; height: 14px; }

.composer__hint {
  font-size: 12px;
  color: var(--text-dim);
  text-align: center;
  margin-top: 10px;
  max-width: var(--chat-col);
  margin-left: auto;
  margin-right: auto;
}

/* ── Attachment tray ─────────────────────────────────────────────────────── */
.attachment-tray {
  display: flex; flex-wrap: wrap; gap: 8px;
  padding: 10px 24px 0;
  max-width: var(--chat-col); margin: 0 auto; width: 100%;
  box-sizing: border-box;
}
.attachment-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 12px;
  border-radius: 100px;
  background: var(--chip-bg);
  color: var(--chip-text);
  font-size: 12px;
  font-weight: 600;
  max-width: 220px;
}
.attachment-chip--loading { opacity: .6; }
.attachment-chip--error { background: rgba(211,47,47,0.10); color: var(--negative); }
.attachment-chip__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.attachment-chip__badge {
  padding: 1px 7px;
  border-radius: 100px;
  background: rgba(183,121,31,0.14);
  color: var(--warning);
  font-size: 11px;
  white-space: nowrap;
  flex-shrink: 0;
}
.attachment-chip__remove {
  background: none; border: none; cursor: pointer;
  padding: 0 2px; color: inherit; opacity: .7;
  font-size: 14px; line-height: 1; flex-shrink: 0;
}
@media (hover: hover) {
  .attachment-chip__remove:hover { opacity: 1; }
}
.attachment-chip__remove:active { opacity: 1; color: var(--negative); }
@keyframes chip-spin { to { transform: rotate(360deg); } }
.attachment-chip__spinner {
  width: 10px; height: 10px;
  border: 2px solid rgba(255,255,255,.4);
  border-top-color: var(--chip-text);
  border-radius: 50%;
  animation: chip-spin .6s linear infinite;
  flex-shrink: 0;
}

/* ── Account-menu modal ──────────────────────────────────────────────────── */
.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: rgba(8,19,37,0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}
.modal {
  width: 100%;
  max-width: 420px;
  max-height: calc(100vh - 40px);
  /* Same fallback pair as the app shell: mobile browser chrome is excluded from
     dvh, so the modal stops short of it instead of running underneath. The vh
     line above is the fallback for browsers without dvh support. */
  max-height: calc(100dvh - 40px);
  overflow-y: auto;
  background: var(--bg-surface);
  border: 1px solid var(--border-default);
  border-radius: 16px;
  box-shadow: var(--shadow-card-hover);
  padding: 20px;
}
.modal__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}
.modal__title { font-family: 'Archivo'; font-size: 18px; font-weight: 700; color: var(--text-primary); }
.modal__close {
  width: 28px; height: 28px;
  border-radius: 50%;
  border: none;
  background: none;
  color: var(--text-muted);
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer;
  flex-shrink: 0;
  transition: background 160ms, color 160ms;
}
@media (hover: hover) {
  .modal__close:hover { background: var(--bg-glass-strong); color: var(--accent-primary); }
}
.modal__close:active { background: var(--accent-primary); color: #fff; }
.modal__body { font-size: 14px; color: var(--text-secondary); line-height: 1.6; }
.modal__body p + p { margin-top: 10px; }
.modal__list { margin: 10px 0 0; padding-left: 18px; display: flex; flex-direction: column; gap: 8px; }
.modal__lead { margin-bottom: 10px; }

/* ── Profile card (Teams-style) ──────────────────────────────────────────── */
.profile { display: flex; flex-direction: column; gap: 18px; }

.profile__header { display: flex; align-items: center; gap: 14px; }
.profile__avatar {
  position: relative;
  width: 64px; height: 64px;
  font-size: 24px;
  flex-shrink: 0;
  overflow: hidden;
}
.profile__avatar--photo { background: none; }
.profile__photo { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }
.profile__id { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.profile__name { font-family: 'Archivo'; font-size: 18px; font-weight: 700; color: var(--text-primary); }
.profile__subtitle { font-size: 13px; color: var(--text-secondary); }

/* Quick actions (Email / Chat in Teams / Call) */
.profile__actions { display: flex; flex-wrap: wrap; gap: 8px; }
.profile__action {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 14px;
  border-radius: 100px;
  border: 1px solid var(--border-default);
  background: var(--bg-glass);
  color: var(--text-primary);
  font-size: 13px; font-weight: 600;
  text-decoration: none;
  transition: background 160ms, border-color 160ms, color 160ms;
}
@media (hover: hover) {
  .profile__action:hover { background: var(--chip-bg); color: var(--accent-primary); border-color: var(--accent-primary); }
}
.profile__action:active { background: var(--accent-primary); color: #fff; border-color: var(--accent-primary); }
.profile__action svg { width: 15px; height: 15px; flex-shrink: 0; }

/* Contact-information grid */
.profile__section { border-top: 1px solid var(--border-subtle); padding-top: 16px; }
.profile__section-title {
  font-size: 11px; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--text-muted); margin-bottom: 12px;
}
.profile__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 14px 20px;
}
.profile__row { display: flex; align-items: flex-start; gap: 10px; min-width: 0; }
.profile__row-icon { color: var(--text-dim); flex-shrink: 0; margin-top: 1px; }
.profile__row-icon svg { width: 16px; height: 16px; display: block; }
.profile__row-body { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.profile__row-label { font-size: 11px; color: var(--text-muted); }
.profile__row-value { font-size: 13px; color: var(--text-primary); word-break: break-word; }
a.profile__row-value { color: var(--accent-primary); text-decoration: none; }
@media (hover: hover) {
  a.profile__row-value:hover { text-decoration: underline; }
}
.modal__textarea {
  width: 100%;
  border: 1px solid var(--border-default);
  border-radius: 12px;
  background: var(--bg-glass);
  font: inherit;
  font-size: 14px;
  color: var(--text-primary);
  padding: 10px 12px;
  resize: vertical;
}
.modal__textarea::placeholder { color: var(--text-dim); }
.modal__actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 14px; }

/* ── Focus visibility ────────────────────────────────────────────────────── */
button:focus-visible, a:focus-visible, textarea:focus-visible, [contenteditable]:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(30,122,224,.15);
}

/* ── Touch targets ───────────────────────────────────────────────────────────
   Coarse pointers need a 44px minimum (iOS) / 48px (Android). Controls expand
   their hit area with a transparent overlay rather than growing, so the visual
   design stays as drawn and nothing reflows. Each axis only grows as far as
   there is room -- an overlay wider than the gap to its neighbour would steal
   that neighbour's taps, which for a delete button is worse than a small
   target. */
@media (pointer: coarse) {
  /* Standalone controls: nothing adjacent, so take the full 44px. */
  .modal__close,
  .sidebar-toggle { position: relative; }
  .modal__close::after,
  .sidebar-toggle::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 44px;
    height: 44px;
    transform: translate(-50%, -50%);
  }

  /* Grouped icon buttons sit 32-34px apart centre to centre, so a 44px-wide
     overlay would overlap its neighbour and a tap aimed at edit could fire
     delete. Grow to the group's pitch across, and to the full 44px down. */
  .session-item__icon-btn,
  .feedback-btn { position: relative; }
  .session-item__icon-btn::after,
  .feedback-btn::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    height: 44px;
    transform: translate(-50%, -50%);
  }
  .session-item__icon-btn::after { width: 34px; }  /* 26px control + 8px gap */
  .feedback-btn::after { width: 32px; }            /* 26px control + 6px gap */

  /* These already reach 44px under the mobile breakpoint. Carry that to any
     coarse pointer, including tablets wider than 768px. */
  .send { padding: 12px 16px; min-height: 44px; }
  .attach-btn { width: 44px; height: 44px; }

  /* The remove control sits inside a padded chip, so a 44px box would spill
     onto the neighbouring chip. Widen within the chip instead. */
  .attachment-chip__remove { padding: 0 8px; }
}

/* ── Forced colours (Windows contrast mode) ──────────────────────────────────
   Distinct from [data-theme="contrast"]: that one is a theme the Teams host
   asks for, this one is a mode the OS imposes on any surface. The OS replaces
   colours wholesale, so stop painting our own surfaces and let the system
   palette through, keeping only the structure it cannot infer. */
@media (forced-colors: active) {
  .btn,
  .suggestion,
  .session-item,
  .modal,
  .login-card,
  .attachment-chip {
    border: 1px solid CanvasText;
    background: Canvas;
    color: CanvasText;
    forced-color-adjust: none;
  }
  .btn--primary,
  .send {
    background: Highlight;
    color: HighlightText;
    border-color: HighlightText;
  }
  /* The radial wash and blurred orbs survive forced colours as flat blocks,
     which obscures the text over them. Drop both. */
  .chat-shell::before { background: none; }
  .chat-fx__orb { display: none; }
}

/* ── Reduced motion ──────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    transition-duration: .01ms !important;
  }
}

/* ── Embed mode ──────────────────────────────────────────────────────────────
   Rendered inside the AI-portal iframe (ai.jbssa.com/chat). Strip the app chrome
   — sidebar, brand, account menu — down to just the chat, and let it fill the
   iframe edge-to-edge. The portal supplies the theme via a `?theme=` param and
   the session token via postMessage (see app.js "Embed mode"). */
html.embed .sidebar { display: none; }
/* A Teams tab is chrome-stripped like the portal embed, but the portal supplies its
   own history navigation and Teams does not -- hiding the sidebar there left users
   with a chat and no way back to previous conversations. Restore it for Teams only,
   keyed on the `teams` class set pre-paint from ?host=teams. */
html.embed.teams .sidebar { display: flex; }
/* The host sizes an embed, so there is nothing here for a user to resize. Must be
   display:none, not visibility: a single-column grid would otherwise push the
   handle into an implicit row. */
html.embed .sidebar-resizer { display: none; }

html.embed .layout {
  grid-template-columns: 1fr;
  gap: 0;
  padding: 0;
}
/* Teams keeps the sidebar, so it keeps the three-track grid -- but only where there
   is room for it. This override out-specifies the mobile `.layout` rule (0,3,1 beats
   0,1,0, and a media query adds no specificity), so leaving it unscoped forced a
   288px sidebar onto a 390px phone and squeezed the chat to 16px. Desktop only. */
@media (min-width: 768px) {
  html.embed.teams .layout {
    grid-template-columns: var(--sidebar-w, 288px) 16px minmax(0, 1fr);
  }
  html.embed.teams .sidebar-resizer { display: flex; }
  /* The collapse rule is `html.sidebar-collapsed .layout` at (0,2,1), which the
     Teams rule above out-specifies at (0,3,1) -- so without this the rail's
     contents hid but the track stayed 288px wide: a collapse that visibly did
     nothing. Restated here at (0,4,1) rather than lowering the rule above,
     because the Teams grid genuinely needs to beat the single-column embed rule. */
  html.embed.teams.sidebar-collapsed .layout {
    grid-template-columns: 72px 16px minmax(0, 1fr);
  }
}

/* Flatten the shell so it fills the iframe instead of floating as a rounded card. */
html.embed .chat-shell {
  border: none;
  border-radius: 0;
  box-shadow: none;
}

/* Suggestion skeleton — shown while dynamic prompts load; non-interactive. */
.suggestion--skeleton {
  color: transparent !important;
  pointer-events: none;
  border-color: transparent;
  background-image: linear-gradient(90deg,
    rgba(148, 163, 184, 0.15) 25%,
    rgba(148, 163, 184, 0.30) 37%,
    rgba(148, 163, 184, 0.15) 63%);
  background-size: 400% 100%;
  animation: suggestion-shimmer 1.4s ease infinite;
}
@keyframes suggestion-shimmer {
  0%   { background-position: 100% 0; }
  100% { background-position: 0 0; }
}
@media (prefers-reduced-motion: reduce) {
  .suggestion--skeleton { animation: none; }
}

/* ══ MOBILE (< 768px) ══════════════════════════════════════════════════════════
   The single breakpoint for the whole app. 767.98 rather than 768 so it can never
   overlap a future `min-width: 768px` rule at exactly 768px.

   CONSTRAINT: .sidebar must never gain transform/filter/will-change/contain here.
   Any of those makes it a containing block, which would trap the position:fixed
   account menu (see the account-menu block below) inside the off-screen drawer and
   clip it to .sidebar's overflow:hidden. That is why the drawer animates `left`
   rather than `translateX`. Do not "optimize" this to a transform.             */

.mobile-bar   { display: none; }
.drawer-scrim { display: none; }

@media (max-width: 767.98px) {
  .mobile-bar {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-shrink: 0;
    height: var(--mobile-bar-h);
    padding: 0 12px;
    background: var(--bg-surface);
    border-bottom: 1px solid var(--border-default);
    position: relative;
    z-index: 50;
  }
  html.embed .mobile-bar { display: none; }
  /* Teams on a phone is the one embed that needs this bar: the sidebar is an
     off-canvas drawer here, and without the bar there is no control to open it --
     history would exist but be unreachable. The portal supplies its own chrome. */
  html.embed.teams .mobile-bar { display: flex; }

  .mobile-bar__btn {
    width: 40px; height: 40px;
    display: inline-flex; align-items: center; justify-content: center;
    border: 1px solid var(--border-subtle);
    border-radius: 10px;
    background: var(--bg-glass);
    color: var(--text-secondary);
    cursor: pointer;
    flex-shrink: 0;
  }
  .mobile-bar__title {
    flex: 1;
    font-family: 'Archivo', 'Plus Jakarta Sans', sans-serif;
    font-size: 16px;
    font-weight: 700;
    color: var(--text-primary);
  }
  .mobile-bar__avatar {
    width: 34px; height: 34px;
    flex-shrink: 0;
    border: none;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--jbs-cyan), var(--jbs-navy));
    color: #fff;
    font-family: inherit;
    font-size: 11px;
    font-weight: 700;
    cursor: pointer;
  }

  /* Chat takes the full width; the sidebar leaves the grid entirely. */
  .layout { grid-template-columns: 1fr; gap: 0; padding: 0; }
  /* Below 768px the sidebar is an off-canvas drawer with no edge to drag, and a
     coarse pointer could not hit a 16px target anyway. */
  .sidebar-resizer { display: none; }

  .sidebar {
    position: fixed;
    top: 0; bottom: 0;
    left: -100%;
    width: min(86vw, 320px);
    border-radius: 0;
    border-top: 0; border-bottom: 0; border-left: 0;
    z-index: 60;
    transition: left 240ms var(--ease-out);
  }
  html.drawer-open .sidebar { left: 0; }

  .drawer-scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 55;
    background: rgba(8, 27, 51, 0.45);
    opacity: 0;
    pointer-events: none;
    transition: opacity 240ms var(--ease-out);
  }
  html.drawer-open .drawer-scrim { opacity: 1; pointer-events: auto; }
}

@media (max-width: 767.98px) and (prefers-reduced-motion: reduce) {
  .sidebar, .drawer-scrim { transition: none; }
}

@media (max-width: 767.98px) {
  /* The account menu lives at the bottom of .user-panel, inside the sidebar --
     off-canvas whenever the drawer is closed. Re-anchor it to the viewport so the
     mobile-bar avatar can open it without opening the drawer first. This works
     ONLY because the drawer animates `left` instead of `transform`: a transformed
     ancestor would become the containing block for this fixed element and drag it
     off-screen with the drawer (and clip it to .sidebar's overflow:hidden).
     One position on mobile regardless of which trigger opened it. */
  .user-panel__menu {
    position: fixed;
    top: calc(var(--mobile-bar-h) + 8px);
    right: 12px;
    left: auto;
    bottom: auto;
    width: min(260px, calc(100vw - 24px));
    z-index: 70;  /* above the drawer (60) and its scrim (55) */
  }
}

@media (max-width: 767.98px) {
  /* Edge-to-edge, matching the treatment html.embed already uses -- a floating
     rounded card wastes scarce width on a phone. */
  .chat-shell { border: none; border-radius: 0; box-shadow: none; }

  .chat-body { padding: 16px 12px 8px; }

  .composer-panel {
    padding: 8px 12px 12px;
    padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px));
  }

  /* Must stay >= 16px: below that, iOS Safari auto-zooms the page on focus and
     does not zoom back out. */
  .query { font-size: 16px; }

  /* >= 44px touch targets. */
  .send { padding: 12px 16px; min-height: 44px; }
  .attach-btn { width: 44px; height: 44px; }

  /* Pills stack full-width instead of wrapping into ragged rows. */
  .suggestions { max-width: none; gap: 8px; }
  .suggestion { width: 100%; text-align: center; padding: 11px 14px; }

  .empty-state { padding: 24px 12px; gap: 12px; }
  .empty-state__title { font-size: 24px; }
  .composer__hint { font-size: 11px; }
}
