/* UniGuide — a trustworthy, institutional course-advising UI.

   Design intent (web/DESIGN.md §K): a two-pane shell — a dark, inky RAIL holding the brand, the
   student's past conversations and the account, beside a paper-toned MAIN pane holding the
   conversation — with maroon as the single strong accent across both. The rail is dark so the
   two panes read as different kinds of surface (a shelf beside a page) rather than one grey
   sheet with a divider; the main pane keeps the warm neutrals the transcript already used.
   Refusals stay a calm parchment note (never a red error); provenance stays a distinct chip.

   System font stack only — no web-font network dependency, so the page stays offline-friendly
   for a university tool. The one display face is a SERIF for the empty-state question and the
   wordmark, drawn from what the OS already has. All tokens live in :root below. */

:root {
  /* ---- Maroon brand (the single strong accent) ---- */
  --aub-red: #840132;
  --aub-red-600: #6d0129;
  --aub-red-700: #5a0121;
  --aub-red-800: #470019;
  --aub-red-tint: #fbeef3; /* faint maroon wash for hovers/selection */

  /* ---- Warm neutrals (the main pane) ---- */
  --bg: #f5f3f1;
  --surface: #ffffff;
  --surface-sunken: #f4f1ee;
  --text: #221f1d;
  --text-muted: #6b645f;
  --text-faint: #948c85;
  --border: #e8e3de;
  --border-strong: #d9d2cb;

  /* ---- The rail: ink with a trace of the maroon in it, never neutral grey ---- */
  --rail-bg: #1b1417;
  --rail-bg-raised: #251b1f;
  --rail-hover: rgba(255, 255, 255, 0.06);
  --rail-active: rgba(255, 255, 255, 0.11);
  --rail-text: #f1e9ec;
  --rail-text-muted: #a89ca2;
  --rail-text-faint: #7d7176;
  --rail-border: rgba(255, 255, 255, 0.08);
  --rail-width: 272px;

  /* ---- Shadows (soft, warm-tinted) ---- */
  --shadow-sm: 0 1px 2px rgba(50, 35, 30, 0.06);
  --shadow-md: 0 1px 2px rgba(50, 35, 30, 0.05), 0 4px 14px rgba(50, 35, 30, 0.06);
  --shadow-lg: 0 10px 34px rgba(50, 35, 30, 0.12);

  /* ---- Refusal note — warm parchment with a muted-gold accent (not an error red).
     The "by design" variant swaps to a cooler slate accent so the two calm categories read
     apart without either looking like an error. ---- */
  --note-bg: #fbf7ee;
  --note-border: #ecdfba;
  --note-accent: #c9a227;
  --note-label: #927619;
  --note-text: #4a4131;
  --note-design-bg: #f4f6f8;
  --note-design-border: #dfe4ea;
  --note-design-accent: #7b8494;
  --note-design-label: #59626f;
  --note-limit-bg: #fdf1f5;
  --note-limit-border: #f0d3de;
  --note-limit-accent: var(--aub-red);
  --note-limit-label: var(--aub-red-700);
  --note-quiet-bg: var(--surface-sunken);
  --note-quiet-border: var(--border);
  --note-quiet-accent: #9a928b;
  --note-quiet-label: var(--text-muted);
  --note-ok-bg: #f0f7f2;
  --note-ok-border: #cfe6d8;
  --note-ok-accent: #2f7d52;
  --note-ok-label: #266443;

  /* ---- Clarifying ask — a QUESTION BACK, deliberately not a refusal. ---- */
  --ask-bg: #fffafc;
  --ask-border: #f2dde6;
  --ask-accent: var(--aub-red);
  --ask-label: var(--aub-red-700);
  --ask-option-border: #e9d6de;

  /* ---- Schedule provenance chip — muted, present but quiet. ---- */
  --chip-bg: #f0ece7;
  --chip-border: #e2dcd5;
  --chip-text: #6b645f;

  /* ---- Spacing scale (4 / 8 / 12 / 16 / 20 / 24 / 32) ---- */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 20px;
  --sp-6: 24px;
  --sp-8: 32px;

  /* ---- Radii ---- */
  --radius-lg: 22px;
  --radius-md: 16px;
  --radius-sm: 10px;

  /* ---- Layout: the conversation column ---- */
  --content-width: 780px;
  --gutter: 20px;
  --band-pad: max(var(--gutter), calc((100% - var(--content-width)) / 2));

  /* ---- Type ---- */
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial,
    "Apple Color Emoji", "Segoe UI Emoji", sans-serif;
  /* The display face: a bookish serif for the one question the empty page asks, and the
     wordmark. Every entry here is a face an OS already ships, so nothing is fetched. */
  --font-display: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia,
    "Times New Roman", serif;
  --font-size: 15.5px;
  --line-body: 1.62;

  /* Uppercase micro-labels (sources / eyebrow / refusal / recents). */
  --micro-size: 11px;
  --micro-tracking: 0.08em;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  height: 100%;
}

body {
  background: var(--rail-bg);
  color: var(--text);
  font-family: var(--font);
  font-size: var(--font-size);
  line-height: var(--line-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

::selection {
  background: var(--aub-red-tint);
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  clip: rect(0 0 0 0);
  overflow: hidden;
  white-space: nowrap;
}

/* ---- The shell: rail | main, full height ---- */

.app {
  display: flex;
  height: 100vh;
  height: 100dvh;
  width: 100%;
  overflow: hidden;
  background: var(--rail-bg);
}

/* ---- The rail ---- */

.rail {
  flex: 0 0 var(--rail-width);
  width: var(--rail-width);
  display: flex;
  flex-direction: column;
  min-height: 0;
  color: var(--rail-text);
  background: var(--rail-bg);
  transition: margin-left 0.22s ease, transform 0.22s ease;
}

/* Collapsed: the rail slides off the left edge and the main pane takes the width. */
.app--rail-hidden .rail {
  margin-left: calc(-1 * var(--rail-width));
}

.rail__top {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 14px 12px 6px 14px;
}

.header__brand {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  flex: 1 1 auto;
}

/* UniGuide's own mark — the open book on a maroon tile, the same lockup as the favicon. */
.header__mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  border-radius: 10px;
  background: var(--aub-red);
  color: #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
}

.brand-glyph {
  width: 19px;
  height: 19px;
  display: block;
}

.header__titles {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.header__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: 19px;
  font-weight: 600;
  letter-spacing: 0.01em;
  line-height: 1.1;
  color: var(--rail-text);
}

.header__subtitle {
  margin: 2px 0 0;
  font-size: 11.5px;
  color: var(--rail-text-muted);
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Small square icon buttons in the rail (hide sidebar) and the topbar (show sidebar). */
.rail__iconbtn,
.topbar__iconbtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 32px;
  height: 32px;
  padding: 0;
  color: var(--rail-text-muted);
  background: transparent;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease;
}

.rail__iconbtn:hover {
  background: var(--rail-hover);
  color: var(--rail-text);
}

.rail__iconbtn:focus-visible,
.rail__action:focus-visible,
.recents__row:focus-visible,
.recents__more:focus-visible,
.account__button:focus-visible,
.rail__search-input:focus-visible {
  outline: 2px solid #fff;
  outline-offset: -2px;
}

.rail__icon {
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
}

.rail__actions {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px 10px 4px;
}

.rail__action {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 10px;
  font-family: inherit;
  font-size: 14px;
  font-weight: 500;
  text-align: left;
  color: var(--rail-text);
  background: transparent;
  border: none;
  border-radius: 9px;
  cursor: pointer;
  transition: background-color 0.15s ease;
}

.rail__action:hover:not(:disabled) {
  background: var(--rail-hover);
}

.rail__action:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.rail__action .rail__icon {
  color: var(--rail-text-muted);
}

.rail__action[aria-expanded="true"] {
  background: var(--rail-active);
}

.rail__search {
  padding: 4px 2px 6px;
}

.rail__search[hidden] {
  display: none;
}

.rail__search-input {
  width: 100%;
  padding: 8px 12px;
  font-family: inherit;
  font-size: 13.5px;
  color: var(--rail-text);
  background: var(--rail-bg-raised);
  border: 1px solid var(--rail-border);
  border-radius: 9px;
  outline: none;
}

.rail__search-input::placeholder {
  color: var(--rail-text-faint);
}

/* ---- Recents: the list of past conversations ---- */

.rail__recents {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 10px 10px 8px;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.14) transparent;
}

.rail__label {
  margin: 4px 10px 6px;
  font-size: var(--micro-size);
  font-weight: 600;
  letter-spacing: var(--micro-tracking);
  text-transform: uppercase;
  color: var(--rail-text-faint);
}

.recents {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.recents__empty {
  margin: 6px 10px;
  font-size: 13px;
  line-height: 1.45;
  color: var(--rail-text-faint);
}

.recents__empty[hidden] {
  display: none;
}

/* A row: the title button fills it; the "…" sits at the right edge and appears on hover,
   focus, or when the row is the open one. */
.recents__item {
  position: relative;
  display: flex;
  align-items: center;
  border-radius: 9px;
}

.recents__item:hover,
.recents__item:focus-within {
  background: var(--rail-hover);
}

.recents__item--active {
  background: var(--rail-active);
}

.recents__item--active:hover {
  background: var(--rail-active);
}

.recents__row {
  flex: 1 1 auto;
  min-width: 0;
  display: block;
  padding: 8px 30px 8px 10px;
  font-family: inherit;
  font-size: 13.5px;
  line-height: 1.35;
  text-align: left;
  color: var(--rail-text);
  background: transparent;
  border: none;
  border-radius: 9px;
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.recents__row:disabled {
  cursor: default;
}

/* The maroon tick on the open conversation — the one place the accent shows in the rail
   besides the mark, so it reads as "you are here". */
.recents__item--active::before {
  content: "";
  position: absolute;
  left: 0;
  top: 9px;
  bottom: 9px;
  width: 3px;
  border-radius: 2px;
  background: var(--aub-red);
}

.recents__more {
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  color: var(--rail-text-muted);
  background: transparent;
  border: none;
  border-radius: 7px;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.12s ease, background-color 0.15s ease;
}

.recents__item:hover .recents__more,
.recents__item:focus-within .recents__more,
.recents__item--active .recents__more,
.recents__more[aria-expanded="true"] {
  opacity: 1;
}

.recents__more:hover,
.recents__more[aria-expanded="true"] {
  background: rgba(255, 255, 255, 0.12);
  color: var(--rail-text);
}

@media (hover: none) {
  .recents__more {
    opacity: 1;
  }
}

/* Explicit, because the absolute positioning above would otherwise outrank `hidden`. */
.recents__more[hidden] {
  display: none;
}

/* The row menu: a small light panel, the same surface the account menu uses, so the two
   pop-overs in the rail are one family. */
.recents__menu {
  position: absolute;
  right: 6px;
  top: calc(100% - 2px);
  z-index: 30;
  min-width: 150px;
  padding: 6px;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  box-shadow: var(--shadow-lg);
}

.recents__menu--up {
  top: auto;
  bottom: calc(100% - 2px);
}

.recents__menu[hidden] {
  display: none;
}

.recents__menu-item {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  padding: 7px 10px;
  font-family: inherit;
  font-size: 13.5px;
  font-weight: 500;
  text-align: left;
  color: var(--text);
  background: transparent;
  border: none;
  border-radius: 8px;
  cursor: pointer;
}

.recents__menu-item .msg-action__icon {
  width: 15px;
  height: 15px;
  color: var(--text-faint);
}

.recents__menu-item:hover {
  background: var(--aub-red-tint);
  color: var(--aub-red-700);
}

.recents__menu-item:hover .msg-action__icon {
  color: var(--aub-red);
}

.recents__menu-item:focus-visible {
  outline: 2px solid var(--aub-red);
  outline-offset: -2px;
}

.recents__menu-item--danger {
  color: var(--aub-red-700);
}

/* Inline rename: the title becomes a field in place. */
.recents__rename {
  flex: 1 1 auto;
  min-width: 0;
  margin: 3px 4px;
  padding: 5px 8px;
  font-family: inherit;
  font-size: 13.5px;
  color: var(--rail-text);
  background: var(--rail-bg-raised);
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 7px;
  outline: none;
}

.recents__rename:focus {
  border-color: rgba(255, 255, 255, 0.32);
}

/* The page-wide selection colour is a pale maroon wash meant for dark text on paper; on the
   rail's light text it reads as a blank white bar. Selected text here is white on maroon. */
.recents__rename::selection {
  background: var(--aub-red);
  color: #fff;
}

/* Inline delete confirmation: the row turns into a question with two answers. */
.recents__confirm {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  padding: 6px 8px 6px 10px;
  font-size: 13px;
  color: var(--rail-text);
}

.recents__confirm-text {
  flex: 1 1 auto;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.recents__confirm-btn {
  flex: 0 0 auto;
  padding: 4px 9px;
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--rail-text);
  background: rgba(255, 255, 255, 0.1);
  border: none;
  border-radius: 6px;
  cursor: pointer;
}

.recents__confirm-btn--danger {
  background: var(--aub-red);
  color: #fff;
}

.recents__confirm-btn:hover {
  filter: brightness(1.15);
}

/* A short status line in the rail (a list that failed to load, a rename that didn't save). */
.rail__status {
  margin: 6px 10px 0;
  font-size: 12.5px;
  color: var(--rail-text-faint);
}

.rail__status:empty {
  display: none;
}

/* ---- The data stamp: the term's schedule and when it was taken, above the account ---- */

.rail__data {
  flex: 0 0 auto;
  padding: 10px 14px 9px;
  border-top: 1px solid var(--rail-border);
}

.rail__data-term {
  margin: 0;
  font-size: var(--micro-size);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--micro-tracking);
  color: var(--rail-text-faint);
}

.rail__data-when {
  margin: 3px 0 0;
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  color: var(--rail-text-muted);
}

/* ---- Account: the foot of the rail, and the menu it opens ---- */

.account {
  position: relative;
  flex: 0 0 auto;
  padding: 8px 10px 10px;
  border-top: 1px solid var(--rail-border);
}

.account__button {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 7px 8px;
  font-family: inherit;
  text-align: left;
  color: var(--rail-text);
  background: transparent;
  border: none;
  border-radius: 10px;
  cursor: pointer;
  transition: background-color 0.15s ease;
}

.account__button:hover,
.account__button[aria-expanded="true"] {
  background: var(--rail-hover);
}

.account__badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 32px;
  height: 32px;
  font-size: 14px;
  font-weight: 700;
  line-height: 1;
  color: #fff;
  background: linear-gradient(160deg, #a2124a 0%, var(--aub-red) 100%);
  border-radius: 50%;
}

.account__glyph {
  width: 17px;
  height: 17px;
}

.account__initial {
  display: none;
}

.account__button--initialed .account__glyph {
  display: none;
}

.account__button--initialed .account__initial {
  display: block;
}

.account__who {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.account__name {
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.25;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.account__sub {
  font-size: 11.5px;
  color: var(--rail-text-muted);
  line-height: 1.25;
}

.account__sub:empty {
  display: none;
}

.account__menu {
  position: absolute;
  left: 10px;
  right: 10px;
  bottom: calc(100% - 2px);
  z-index: 20;
  padding: var(--sp-2);
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  text-align: left;
}

.account__menu[hidden] {
  display: none;
}

.account__identity {
  padding: var(--sp-2) var(--sp-3) var(--sp-3);
  border-bottom: 1px solid var(--border);
  margin-bottom: var(--sp-2);
}

.account__identity-label {
  margin: 0 0 3px;
  font-size: var(--micro-size);
  font-weight: 600;
  letter-spacing: var(--micro-tracking);
  text-transform: uppercase;
  color: var(--text-faint);
}

.account__email {
  margin: 0;
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.35;
  color: var(--text);
  overflow-wrap: anywhere;
}

.account__identity--anonymous .account__identity-label {
  display: none;
}

.account__identity--anonymous .account__email {
  font-weight: 500;
  color: var(--text-muted);
}

.account__email:empty {
  display: none;
}

.account__items {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.account__item {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  padding: 9px var(--sp-3);
  font-family: inherit;
  font-size: 14px;
  font-weight: 500;
  text-align: left;
  color: var(--text);
  text-decoration: none; /* the operator's link is an item like the buttons around it */
  background: transparent;
  border: 0;
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.account__item[hidden] {
  display: none;
}

.account__item:hover:not(:disabled) {
  background: var(--aub-red-tint);
  color: var(--aub-red-700);
}

.account__item:focus-visible {
  outline: 2px solid var(--aub-red);
  outline-offset: -2px;
}

.account__item:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.account__item-icon {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  color: var(--text-faint);
}

.account__item:hover:not(:disabled) .account__item-icon {
  color: var(--aub-red);
}

.account__sep {
  height: 1px;
  margin: var(--sp-1) var(--sp-3);
  background: var(--border);
}

.account__item--exit {
  color: var(--aub-red-700);
}

/* "Delete all chats" and the in-place question it gives way to (web/DESIGN.md §K): the row
   confirm's shape, on the light panel. */
.account__item--danger {
  color: var(--aub-red-700);
}

.account__item--danger .account__item-icon {
  color: var(--aub-red);
}

.account__confirm {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  width: 100%;
  padding: 6px var(--sp-3);
  font-size: 13px;
  color: var(--text);
}

.account__confirm[hidden] {
  display: none;
}

/* The question takes its own line; the two answers sit under it. The panel is narrow, and a
   clipped "Delete all 7 …" is exactly the wrong thing to clip. */
.account__confirm-text {
  flex: 1 0 100%;
  font-weight: 600;
}

.account__confirm-btn {
  flex: 0 0 auto;
  padding: 4px 9px;
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text);
  background: var(--aub-red-tint);
  border: none;
  border-radius: 6px;
  cursor: pointer;
}

.account__confirm-btn--danger {
  background: var(--aub-red);
  color: #fff;
}

.account__confirm-btn:hover {
  filter: brightness(1.08);
}

.account__confirm-btn:focus-visible {
  outline: 2px solid var(--aub-red);
  outline-offset: 1px;
}

.account__item--exit .account__item-icon {
  color: var(--aub-red);
}

/* ---- The main pane ---- */

.main {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  /* The page corner: the paper sits on the ink like a sheet on a desk. */
  border-top-left-radius: 14px;
  margin-top: 8px;
  overflow: hidden;
}

.app--rail-hidden .main {
  border-top-left-radius: 0;
  margin-top: 0;
}

.topbar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: 48px;
  padding: 8px 12px;
}

.topbar__iconbtn {
  color: var(--text-muted);
}

.topbar__iconbtn:hover {
  background: rgba(0, 0, 0, 0.06);
  color: var(--text);
}

.topbar__iconbtn:focus-visible {
  outline: 2px solid var(--aub-red);
  outline-offset: -2px;
}

/* "Show the sidebar" only exists once the rail is hidden (or on a phone, where it opens the
   drawer); the phone-only "new chat" lives in the same bar. */
.topbar #rail-open {
  display: none;
}

.app--rail-hidden .topbar #rail-open {
  display: inline-flex;
}

/* The topbar's own "New chat": a quiet outlined pill, present at every width. */
.topbar__new {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  flex: 0 0 auto;
  padding: 6px 12px 6px 10px;
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-muted);
  background: transparent;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.topbar__new:hover:not(:disabled) {
  color: var(--aub-red-700);
  background: var(--aub-red-tint);
  border-color: rgba(132, 1, 50, 0.35);
}

.topbar__new:focus-visible {
  outline: 2px solid var(--aub-red);
  outline-offset: 2px;
}

.topbar__new:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.topbar__title {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0 4px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* On a fresh chat the pane itself says so; a "New chat" label beside a "New chat" button would
   only read as a second control that does nothing. */
.app--empty .topbar__title {
  visibility: hidden;
}

.main__body {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* ---- The empty state: the question in the middle of the page, the composer under it ---- */

.hero {
  display: none;
  padding: 0 var(--band-pad);
  text-align: center;
}

.hero__title {
  margin: 0 0 10px;
  font-family: var(--font-display);
  font-size: 34px;
  font-weight: 500;
  letter-spacing: -0.005em;
  line-height: 1.15;
  color: var(--text);
}

.hero__blurb {
  max-width: 560px;
  margin: 0 auto 26px;
  font-size: 15px;
  line-height: 1.55;
  color: var(--text-muted);
}

.hero-examples {
  display: none;
  padding: 18px var(--band-pad) 0;
}

.app--empty .main__body {
  justify-content: center;
}

.app--empty .hero,
.app--empty .hero-examples {
  display: block;
}

.app--empty .chat {
  display: none;
}

.app--empty .composer {
  padding-top: 0;
}

/* The hero and the footer each take an auto margin, so the question + composer + chips sit
   in the middle of the pane and the disclaimer stays pinned to the foot. */
.app--empty .hero {
  margin-top: auto;
}

.app--empty .disclaimer {
  margin-top: auto;
}

/* ---- Chat log ---- */

.chat {
  flex: 1 1 auto;
  overflow-y: auto;
  overflow-x: hidden;
  padding: var(--sp-6) var(--band-pad) var(--sp-4);
  display: flex;
  flex-direction: column;
  gap: var(--sp-5);
  scroll-behavior: smooth;
}

/* A message row: a single content column, aligned left (bot) or right (user). Bot rows carry
   no avatar chip — the bubble treatments already separate the speakers. */
.message {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  width: 100%;
  animation: message-in 0.28s ease both;
}

.message--user {
  justify-content: flex-end;
}

.message--bot {
  justify-content: flex-start;
}

/* The content column (holds a bubble or a refusal note, plus that message's action bar). */
.message__content {
  min-width: 0;
  max-width: min(100%, 620px);
  display: flex;
  flex-direction: column;
}

/* The student's own column: bubble and actions both hug the right edge. */
.message__content--user {
  align-items: flex-end;
}

@keyframes message-in {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.bubble {
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--radius-md);
  word-wrap: break-word;
  overflow-wrap: anywhere;
}

.bubble__text {
  margin: 0;
  white-space: pre-wrap;
}

.bubble__text + .bubble__text {
  margin-top: var(--sp-3);
}

.bubble--user {
  max-width: min(100%, 560px);
  background: linear-gradient(160deg, var(--aub-red) 0%, var(--aub-red-600) 100%);
  color: #fff;
  border-bottom-right-radius: 6px;
  box-shadow: var(--shadow-md);
}

.bubble--bot {
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-bottom-left-radius: 6px;
  box-shadow: var(--shadow-sm);
}

/* Schedule answers list 1..N sections in pre-wrapped prose; a touch more line-height
   keeps a multi-section answer scannable rather than a wall of text. */
.bubble--schedule .bubble__text {
  line-height: 1.7;
}

/* Answer prose drawn as structure (appendProse in app.js): a paragraph of "- " lines is a list,
   a quoted regulation or catalogue sentence is a labelled quote. The spacing step between
   blocks is the one paragraphs already use. */
.bubble__list {
  margin: 0;
  padding-left: 1.25em;
  white-space: pre-wrap;
}

.bubble__text + .bubble__list,
.bubble__list + .bubble__text,
.bubble__list + .bubble__list,
.bubble__quote + .bubble__text,
.bubble__text + .bubble__quote,
.bubble__quote + .bubble__quote,
.bubble__list + .bubble__quote,
.bubble__quote + .bubble__list {
  margin-top: var(--sp-3);
}

.bubble__item + .bubble__item {
  margin-top: 4px;
}

.bubble__quote {
  margin: 0;
  padding: 6px 12px;
  border-left: 3px solid var(--chip-border);
  background: var(--chip-bg);
  border-radius: 0 8px 8px 0;
}

.bubble__quote-label {
  display: block;
  margin-bottom: 2px;
  font-size: var(--micro-size);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--micro-tracking);
  color: var(--text-muted);
}

.bubble__quote-text {
  display: block;
  white-space: pre-wrap;
}

/* The audit card's folded prerequisite list: the section label doubles as the toggle. */
.au-details > .au-details__summary {
  cursor: pointer;
  list-style: none;
}

.au-details > .au-details__summary::-webkit-details-marker {
  display: none;
}

.au-details > .au-details__summary::before {
  content: "▸ ";
}

.au-details[open] > .au-details__summary::before {
  content: "▾ ";
}

/* ---- Welcome / empty state (richer first bot message) ---- */

.welcome {
  padding: var(--sp-5) var(--sp-5) var(--sp-4);
}

.welcome__title {
  margin: 0 0 var(--sp-2);
  font-size: 18px;
  font-weight: 700;
  letter-spacing: 0.005em;
  color: var(--text);
}

.welcome .bubble__text {
  color: var(--text);
}

.welcome .bubble__text + .bubble__text {
  margin-top: var(--sp-2);
}

/* ---- Schedule answer: eyebrow + provenance chip ---- */

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  align-self: flex-start;
  font-size: var(--micro-size);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--micro-tracking);
  color: var(--aub-red);
  margin-bottom: var(--sp-2);
}

.eyebrow::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--aub-red);
}

.provenance {
  display: inline-block;
  margin-top: var(--sp-3);
  padding: 4px 11px;
  font-size: 12px;
  line-height: 1.4;
  color: var(--chip-text);
  background: var(--chip-bg);
  border: 1px solid var(--chip-border);
  border-radius: 999px;
}

/* ---- Empty-state examples (clickable onboarding prompts) ---- */

.examples {
  margin-top: var(--sp-4);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--border);
}

.examples__label {
  display: block;
  font-size: var(--micro-size);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--micro-tracking);
  color: var(--text-faint);
  margin-bottom: var(--sp-3);
}

.examples__list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

/* Now six chips (one per capability), so a couple are long sentences. `max-width: 100%` keeps
   the longest from overflowing the card on a narrow phone — it wraps inside its own pill
   instead, which `line-height` already accommodates. */
.example {
  font-family: inherit;
  font-size: 13.5px;
  line-height: 1.3;
  color: var(--aub-red);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  padding: 7px 13px;
  max-width: 100%;
  cursor: pointer;
  text-align: left;
  transition: background-color 0.15s ease, border-color 0.15s ease, transform 0.1s ease;
}

.example:hover {
  background: var(--aub-red-tint);
  border-color: rgba(132, 1, 50, 0.45);
}

.example:active {
  transform: translateY(1px);
}

.example:focus-visible {
  outline: 2px solid var(--aub-red);
  outline-offset: 2px;
}

/* ---- Sources (citations) — hidden by default, kept for a one-flag re-enable ---- */

.sources {
  margin-top: var(--sp-3);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--border);
}

.sources__label {
  display: block;
  font-size: var(--micro-size);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--micro-tracking);
  color: var(--text-muted);
  margin-bottom: 6px;
}

.sources__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}

.source {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  font-size: 13px;
  color: var(--text);
}

.source__n {
  flex: 0 0 auto;
  font-weight: 700;
  color: var(--aub-red);
}

.source__code {
  flex: 0 0 auto;
  font-weight: 600;
}

.source__title {
  color: var(--text-muted);
}

/* ---- Per-message actions: quiet, and never the loudest thing in the row ----

   Revealed on hover where there IS a hover (a desktop pointer), always visible where there
   isn't (a phone), and revealed by keyboard focus in both cases — so they are never a
   mouse-only affordance. They keep their layout space at rest, so nothing shifts when a row
   is hovered. */

.msg-actions {
  display: flex;
  align-items: center;
  gap: 2px;
  margin-top: var(--sp-1);
  min-height: 26px;
  opacity: 0;
  transition: opacity 0.14s ease;
}

.message:hover .msg-actions,
.msg-actions:focus-within {
  opacity: 1;
}

/* No hover to reveal with (touch): the actions are simply always there. */
@media (hover: none) {
  .msg-actions {
    opacity: 1;
  }
}

.msg-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  font-family: inherit;
  color: var(--text-faint);
  background: transparent;
  border: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: color 0.15s ease, background-color 0.15s ease;
}

.msg-action__icon {
  width: 15px;
  height: 15px;
}

/* A page without the icon <template>s still gets a labelled control, just a wordy one. */
.msg-action__text {
  font-size: 12px;
  padding: 0 6px;
}

.msg-action:hover {
  color: var(--aub-red);
  background: var(--aub-red-tint);
}

.msg-action:focus-visible {
  outline: 2px solid var(--aub-red);
  outline-offset: 1px;
}

.msg-action--done {
  color: var(--note-ok-accent);
}

.msg-actions__flash {
  margin-left: var(--sp-1);
  font-size: 12px;
  color: var(--text-faint);
  animation: message-in 0.18s ease both;
}

/* ---- Feedback on a turn (web/DESIGN.md §J) ----

   The two thumbs sit in the SAME action row as copy/retry, separated by a hairline: rating an
   answer is one of the things you do with an answer, not a widget bolted underneath it. They
   inherit .msg-action wholesale — size, hover, focus ring, the 30px phone tap target — so the
   row stays one set of controls at one weight, and only the "voted" state is new. */

.msg-actions__sep {
  width: 1px;
  height: 14px;
  margin: 0 4px;
  background: var(--border);
}

/* A registered vote is the one persistent state in this row, so it is the one that keeps its
   colour when the pointer leaves. Maroon, like every other "this is on" in the app. */
/* A cast vote FILLS its thumb in maroon — the icon itself is the record, the tint is just the
   seat. The glyph is drawn as an outline; filling it with the current colour turns the same
   path into a solid thumb, so no second icon is needed. */
.msg-action--voted {
  color: var(--aub-red);
  background: var(--aub-red-tint);
}

.msg-action--voted .msg-action__icon {
  fill: currentColor;
}

/* The row is revealed on hover — but a vote already cast must stay legible at rest, or the
   student loses the only record that their tap did anything. */
.message:has(.msg-action--voted) .msg-actions {
  opacity: 1;
}

.vote-status {
  margin-left: var(--sp-1);
  font-size: 12px;
  color: var(--text-faint);
}

/* The note field: offered after a dislike is already saved, never as a precondition for it. */
.vote-note {
  display: block;
  margin-top: var(--sp-1);
  animation: message-in 0.18s ease both;
}

.vote-note[hidden] {
  display: none;
}

.vote-note__row {
  display: flex;
  align-items: flex-end;
  gap: var(--sp-2);
  max-width: 520px;
}

.vote-note__input {
  flex: 1;
  min-width: 0;
  padding: 8px 10px;
  font-family: inherit;
  font-size: 13px;
  line-height: 1.45;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  resize: vertical;
}

.vote-note__input:focus-visible {
  outline: 2px solid var(--aub-red);
  outline-offset: 1px;
  border-color: var(--aub-red);
}

.vote-note__send {
  flex: none;
  padding: 8px 14px;
  font-family: inherit;
  font-size: 13px;
  color: var(--aub-red);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}

.vote-note__send:hover {
  background: var(--aub-red-tint);
  border-color: var(--aub-red);
}

.vote-note__send:focus-visible {
  outline: 2px solid var(--aub-red);
  outline-offset: 1px;
}

.vote-note__send:disabled {
  opacity: 0.55;
  cursor: default;
}

/* ---- The clarifying ask: a question back, its own third family ----

   Not an answer (it carries a "?" mark, a maroon label and the options), and pointedly not a
   refusal (no parchment, no left rule, no uppercase label, no alert glyph). It keeps the bot
   bubble's shape and left-tucked corner because it IS a turn in the conversation. */

.ask {
  width: 100%;
  background: var(--ask-bg);
  border: 1px solid var(--ask-border);
  border-radius: var(--radius-md);
  border-bottom-left-radius: 6px;
  padding: var(--sp-3) var(--sp-4) var(--sp-4);
  box-shadow: var(--shadow-sm);
}

.ask__label {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13.5px;
  font-weight: 700;
  letter-spacing: 0.005em;
  color: var(--ask-label);
  margin-bottom: 6px;
}

/* A question mark, not an "i" and not a warning triangle: UniGuide is asking, not reporting. */
.ask__label::before {
  content: "?";
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--ask-accent);
  color: #fff;
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
}

.ask__text {
  margin: 0;
  white-space: pre-wrap;
  color: var(--text);
}

.ask__options {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin-top: var(--sp-3);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--ask-border);
}

/* An option is a prompt for input, so it reads as a control: a white pill on the tinted card,
   with the identifying line first and the quiet detail under it. */
.ask__option {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  font-family: inherit;
  text-align: left;
  max-width: 100%;
  padding: 8px 14px;
  color: var(--aub-red);
  background: var(--surface);
  border: 1px solid var(--ask-option-border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease, transform 0.1s ease;
}

/* An option that carries a detail line (a section's meeting summary) takes a share of the row
   instead of sizing to its text, so seven of them read as a two-column list rather than seven
   full-width slabs. Options without a detail (the programs) stay content-sized pills. */
.ask__option--detailed {
  flex: 1 1 250px;
  min-width: 0;
}

.ask__option-label {
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.3;
}

/* One line. The ask's own message lists every section in full directly above, so the option needs
   only enough to tell the sections apart — and the whole summary is on the button's tooltip and
   its aria-label. */
.ask__option-detail {
  align-self: stretch;
  font-size: 12px;
  line-height: 1.35;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ask__option:hover {
  background: var(--aub-red-tint);
  border-color: rgba(132, 1, 50, 0.45);
}

.ask__option:active {
  transform: translateY(1px);
}

.ask__option:focus-visible {
  outline: 2px solid var(--aub-red);
  outline-offset: 2px;
}

/* ---- Refusal note: calm, deliberate, not an error ---- */

.note {
  width: 100%;
  background: var(--note-bg);
  border: 1px solid var(--note-border);
  border-left: 3px solid var(--note-accent);
  border-radius: var(--radius-sm);
  padding: var(--sp-3) var(--sp-4);
  color: var(--note-text);
  box-shadow: var(--shadow-sm);
}

.note__label {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: var(--micro-size);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--micro-tracking);
  color: var(--note-label);
  margin-bottom: 6px;
}

.note__label::before {
  content: "i";
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--note-accent);
  color: #fff;
  font-size: 11px;
  font-style: italic;
  font-weight: 700;
}

.note__text {
  margin: 0;
  white-space: pre-wrap;
  color: var(--note-text);
}

/* "Out of bounds by design" (advisory / degree requirements / live seats, and a question that
   isn't about AUB at all): same calm parchment family, a cooler slate accent so it reads as a
   deliberate boundary, not missing data. */
.note--by-design {
  background: var(--note-design-bg);
  border-color: var(--note-design-border);
  border-left-color: var(--note-design-accent);
}

.note--by-design .note__label {
  color: var(--note-design-label);
}

.note--by-design .note__label::before {
  content: "\2013"; /* en dash — "outside the line", vs. the informational "i" */
  background: var(--note-design-accent);
  font-style: normal;
}

/* A LIMIT (the §16.5 per-user answering cap, or a login endpoint's rate limit): the same calm
   note family, but neither of the refusal categories — UniGuide is not declining, it is out of
   capacity for now. The ↻ glyph says what the wording says: this resets. */
.note--limit {
  background: var(--note-limit-bg);
  border-color: var(--note-limit-border);
  border-left-color: var(--note-limit-accent);
}

.note--limit .note__label {
  color: var(--note-limit-label);
}

.note--limit .note__label::before {
  content: "\21BB"; /* ↻ — comes back on its own */
  background: var(--note-limit-accent);
  font-style: normal;
  font-size: 12px;
}

/* Success. Used only on the sign-in page, where something actually succeeded — so green never
   competes with a refusal anywhere in the transcript. */
.note--ok {
  background: var(--note-ok-bg);
  border-color: var(--note-ok-border);
  border-left-color: var(--note-ok-accent);
}

.note--ok .note__label {
  color: var(--note-ok-label);
}

.note--ok .note__label::before {
  content: "\2713"; /* ✓ */
  background: var(--note-ok-accent);
  font-style: normal;
}

/* A quiet confirmation. The parchment "info" note carries an amber accent and an "i" badge
   that, on a sign-in page, reads as a caution ("Signed out" looked like something had gone
   wrong). Plain routine outcomes — you signed out, a code was sent — get this instead: the
   page's own sunken surface, no coloured edge, and a ✓ in the label's grey. Nothing here says
   "look out". */
.note--quiet {
  background: var(--note-quiet-bg);
  border-color: var(--note-quiet-border);
  border-left-color: var(--note-quiet-border);
  border-left-width: 1px;
  box-shadow: none;
  color: var(--text);
}

.note--quiet .note__label {
  color: var(--note-quiet-label);
}

.note--quiet .note__label::before {
  content: "\2713"; /* ✓ — done, nothing to act on */
  background: var(--note-quiet-accent);
  font-style: normal;
}

.note--quiet .note__text {
  color: var(--text);
}

/* A note that offers an action (e.g. "Sign in again" after a session ends). */
.note__action {
  margin-top: var(--sp-3);
  font-family: inherit;
  font-size: 13.5px;
  font-weight: 600;
  color: #fff;
  background: var(--aub-red);
  border: none;
  border-radius: 999px;
  padding: 8px 16px;
  cursor: pointer;
  transition: background-color 0.15s ease, transform 0.1s ease;
}

.note__action:hover {
  background: var(--aub-red-600);
}

.note__action:active {
  transform: translateY(1px);
}

.note__action:focus-visible {
  outline: 2px solid var(--aub-red);
  outline-offset: 2px;
}

/* ---- Inline system message (network / server / validation hiccups) ---- */

.system {
  align-self: center;
  max-width: 90%;
  text-align: center;
  font-size: 13px;
  color: var(--text-muted);
  background: transparent;
  padding: 2px var(--sp-2);
  animation: message-in 0.28s ease both;
}

/* ---- Thinking indicator ---- */

.thinking {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 15px var(--sp-4);
}

.thinking__dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--aub-red);
  opacity: 0.4;
  animation: thinking-bounce 1.2s infinite ease-in-out both;
}

.thinking__dot:nth-child(2) {
  animation-delay: 0.18s;
}

.thinking__dot:nth-child(3) {
  animation-delay: 0.36s;
}

@keyframes thinking-bounce {
  0%,
  70%,
  100% {
    transform: translateY(0);
    opacity: 0.35;
  }
  35% {
    transform: translateY(-5px);
    opacity: 0.9;
  }
}

@media (prefers-reduced-motion: reduce) {
  .chat {
    scroll-behavior: auto;
  }
  .message,
  .system,
  .msg-actions__flash,
  .vote-note {
    animation: none;
  }
  .msg-actions {
    transition: none;
  }
  .thinking__dot {
    animation: none;
    opacity: 0.55;
  }
}

/* ---- Composer: a rounded field holding the textarea + a circular send button ---- */

.composer {
  flex: 0 0 auto;
  padding: var(--sp-3) var(--band-pad) var(--sp-2);
  background: var(--bg);
}

.composer__field {
  display: flex;
  align-items: flex-end;
  gap: var(--sp-2);
  padding: 6px 6px 6px var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.composer__field:focus-within {
  border-color: var(--aub-red);
  box-shadow: 0 0 0 3px rgba(132, 1, 50, 0.12);
}

.composer__input {
  flex: 1 1 auto;
  resize: none;
  overflow-y: auto;
  max-height: 168px;
  padding: 9px 0;
  font-family: inherit;
  font-size: 16px; /* 16px keeps iOS from zooming the page on focus */
  line-height: 1.5;
  color: var(--text);
  background: transparent;
  border: none;
  outline: none;
}

.composer__input::placeholder {
  color: #a79f98;
}

.composer__input:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.composer__send {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  padding: 0;
  color: #fff;
  background: var(--aub-red);
  border: none;
  border-radius: 50%;
  cursor: pointer;
  transition: background-color 0.15s ease, transform 0.1s ease, opacity 0.15s ease;
}

.composer__send-icon {
  width: 18px;
  height: 18px;
}

.composer__send:hover:not(:disabled) {
  background: var(--aub-red-600);
}

.composer__send:active:not(:disabled) {
  transform: scale(0.94);
}

.composer__send:focus-visible {
  outline: 2px solid var(--aub-red);
  outline-offset: 2px;
}

.composer__send:disabled {
  background: #cec5bf;
  cursor: not-allowed;
}

/* ---- AI disclaimer: one small muted line under the input bar ---- */

.disclaimer {
  flex: 0 0 auto;
  margin: 0;
  padding: var(--sp-2) var(--gutter) calc(var(--sp-3) + env(safe-area-inset-bottom, 0px));
  background: var(--bg);
  color: var(--text-faint);
  font-size: 11.5px;
  line-height: 1.45;
  text-align: center;
}

/* ---- Weekly schedule grid (kind="schedule_grid", ARCHITECTURE.md §15.4) ----

   Rendered from the STRUCTURED payload (day labels + backend start_min/end_min), never from
   prose. The grid message uses a wider content column so the six-day week has room; blocks are
   absolutely positioned within each day column by the minute offsets, and overlapping blocks are
   split into side-by-side lanes so neither is hidden. Conflicts get a distinct maroon hatch (not
   an error red) plus a legend — colour AND pattern, so the flag survives colour-blind viewing. */

.message__content--wide {
  max-width: min(100%, 700px);
}

.sg-card {
  width: 100%;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
  padding: var(--sp-4);
}

/* Space the structured card below the confirmation bubble when both are present. */
.message__content--wide > * + * {
  margin-top: var(--sp-3);
}

.sg-grid {
  overflow-x: auto;
  overflow-y: hidden;
  margin-top: var(--sp-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  -webkit-overflow-scrolling: touch;
}

.sg-grid__inner {
  --sg-axis-w: 52px;
  display: grid;
  /* grid-template-columns is set inline (axis + one minmax(100px,1fr) per day) so the week
     fills the column on desktop and scrolls inside the card on a phone. */
}

.sg-corner {
  border-bottom: 1px solid var(--border-strong);
  border-right: 1px solid var(--border);
}

.sg-dayhead {
  text-align: center;
  font-size: var(--micro-size);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--micro-tracking);
  color: var(--text-muted);
  padding: 7px 4px;
  border-bottom: 1px solid var(--border-strong);
  border-right: 1px solid var(--border);
}

.sg-dayhead:last-child {
  border-right: none;
}

.sg-axis {
  position: relative;
  border-right: 1px solid var(--border-strong);
}

.sg-axis__label {
  position: absolute;
  right: 8px;
  transform: translateY(-50%);
  font-size: 10.5px;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
  white-space: nowrap;
}

.sg-daycol {
  position: relative;
  border-right: 1px solid var(--border);
  /* One 1px hour line at the top of each hour band; band height (background-size) is set inline
     to match PX_PER_MIN, and the grid start is hour-aligned so the lines land on the hour. */
  background-image: linear-gradient(to bottom, var(--border) 0, var(--border) 1px, transparent 1px);
  background-repeat: repeat-y;
}

.sg-daycol:last-child {
  border-right: none;
}

.sg-block {
  --sg-fill: var(--aub-red);
  position: absolute;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  border-radius: 5px;
  padding: 3px 5px;
  background: var(--sg-fill);
  border: 1px solid rgba(255, 255, 255, 0.55);
  box-shadow: var(--shadow-sm);
  font-size: 10px;
  line-height: 1.25;
  color: #fff;
}

.sg-block > * {
  max-width: 100%;
}

/* A block sharing its column with an overlapping one has half the width: the code may wrap
   onto two lines rather than vanish behind an ellipsis, and everything steps down a size. */
.sg-block--split {
  padding: 2px 3px;
  line-height: 1.15;
}

.sg-block--split .sg-block__code {
  font-size: 11px;
  white-space: normal;
  overflow-wrap: anywhere;
}

.sg-block--split .sg-block__time {
  font-size: 9.5px;
  white-space: normal; /* "11:00–" / "11:50" on two lines beats "11:00–1…" */
}

.sg-block--split .sg-block__warn {
  font-size: 9px;
  right: 2px;
  bottom: 1px;
}

/* Section and room do not fit a half-width block; the tooltip and the key still carry them. */
.sg-block--split .sg-block__meta {
  display: none;
}

/* ---- Time conflict: this block is on top of another one, and it says so ----
   The block keeps its own colour but flashes to warning red and back, wears a thick red
   edge and a ⚠, and its list entry below is marked too — colour, motion and a symbol, so
   the clash is unmistakable and still survives a grayscale or a still screen. Reduced-motion
   users get the edge and the symbol with no pulse. */
.sg-block--conflict {
  --sg-warn: #e5261a;
  border: 2px solid #ffffff;
  outline: 2px solid var(--sg-warn);
  outline-offset: 0;
  animation: sg-conflict-pulse 0.9s ease-in-out infinite alternate;
  z-index: 1;
}

@keyframes sg-conflict-pulse {
  from {
    background-color: var(--sg-fill);
    box-shadow: 0 0 0 0 rgba(229, 38, 26, 0);
  }
  to {
    background-color: var(--sg-warn);
    box-shadow: 0 0 0 5px rgba(229, 38, 26, 0.28);
  }
}

/* The ⚠ sits in the block's top-right corner rather than inline, so a narrow side-by-side
   conflict block still shows the course code first. */
.sg-block__warn {
  position: absolute;
  right: 3px;
  bottom: 2px;
  color: #fff;
  font-size: 10px;
  line-height: 1;
}

.sg-block__code {
  font-weight: 700;
  font-size: 12.5px;
  letter-spacing: 0.01em;
  color: #fff;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.sg-block__time,
.sg-block__meta {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.sg-block__time {
  font-size: 10.5px;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.95);
  font-variant-numeric: tabular-nums;
}

.sg-block__meta {
  font-size: 9.5px;
  color: rgba(255, 255, 255, 0.82);
}

/* ---- The card's foot: the snapshot stamp left, the credit total right ---- */

.sg-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  flex-wrap: wrap;
  margin-top: var(--sp-3);
}

.sg-foot .provenance {
  margin-top: 0;
}

.sg-pdf {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-left: auto;
  padding: 4px 11px;
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--aub-red);
  background: transparent;
  border: 1px solid rgba(110, 16, 40, 0.28);
  border-radius: 999px;
  cursor: pointer;
}

.sg-pdf:hover {
  background: var(--aub-red-tint);
}

.sg-pdf .msg-action__icon {
  width: 14px;
  height: 14px;
}

.sg-pdf + .sg-credits {
  margin-left: 0;
}

.sg-credits {
  margin-left: auto;
  padding: 4px 12px;
  font-size: 12.5px;
  line-height: 1.4;
  color: var(--aub-red);
  background: var(--aub-red-tint);
  border: 1px solid rgba(110, 16, 40, 0.18);
  border-radius: 999px;
  white-space: nowrap;
}

.sg-credits__value {
  font-weight: 700;
  font-size: 14px;
  font-variant-numeric: tabular-nums;
}

/* ---- The key under the grid: one chip per section, in its colour ---- */

.sg-key {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: var(--sp-3);
}

.sg-key__chip {
  --sg-fill: var(--aub-red);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 9px 3px 6px;
  font-size: 12px;
  line-height: 1.3;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: 999px;
}

.sg-key__swatch {
  flex: 0 0 auto;
  width: 11px;
  height: 11px;
  border-radius: 3px;
  background: var(--sg-fill);
}

.sg-key__code {
  font-weight: 700;
}

.sg-key__sec {
  color: var(--text-muted);
}

.sg-key__chip--conflict {
  border-color: #e5261a;
}

.sg-key__chip--warning {
  --sg-fill: #e5261a;
  color: #fff;
  background: #e5261a;
  border-color: #e5261a;
  animation: sg-key-pulse 0.9s ease-in-out infinite alternate;
}

.sg-key__chip--warning .sg-key__sec {
  color: rgba(255, 255, 255, 0.85);
}

.sg-key__swatch--warning {
  background: #fff;
}

@keyframes sg-key-pulse {
  from {
    background-color: #e5261a;
  }
  to {
    background-color: #b3150b;
  }
}

/* Below-grid furniture: conflict list, no-time list, unavailable list. */
.sg-furniture {
  margin-top: var(--sp-3);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--border);
}

.sg-furniture__label {
  display: block;
  font-size: var(--micro-size);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--micro-tracking);
  color: var(--text-muted);
  margin-bottom: 6px;
}

.sg-furniture--conflict .sg-furniture__label {
  color: #c4170d;
}

.sg-furniture--conflict .sg-furniture__label::before {
  content: "\26A0";
  margin-right: 6px;
}

.sg-furniture__line {
  margin: 3px 0 0;
  font-size: 13px;
  line-height: 1.45;
  color: var(--text);
}

.sg-furniture--unavailable .sg-furniture__line {
  color: var(--text-muted);
  font-style: italic;
}

.sg-none {
  margin: var(--sp-3) 0 0;
  font-size: 13px;
  color: var(--text-muted);
}

/* Empty state — a friendly placeholder with a clickable example (onboarding for the builder). */
.sg-empty {
  text-align: center;
  padding: var(--sp-6) var(--sp-4) var(--sp-5);
}

.sg-empty__icon {
  font-size: 30px;
  line-height: 1;
}

.sg-empty__title {
  margin: var(--sp-3) 0 0;
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
}

.sg-empty__hint {
  margin: var(--sp-1) 0 var(--sp-4);
  font-size: 13.5px;
  color: var(--text-muted);
}

/* The required planning-view disclaimer — visible on every grid, not hover-hidden (§15.5.4). */
.sg-disclaimer {
  margin-top: var(--sp-3);
  padding-top: var(--sp-2);
  border-top: 1px dashed var(--border-strong);
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--text-faint);
}

/* ---- The example chips under the empty-state composer ----
   The same .example pills the welcome card used, centred under the field, without the card's
   rule above them. */

.hero-examples .examples {
  margin-top: 0;
  padding-top: 0;
  border-top: none;
}

.hero-examples .examples__label {
  text-align: center;
}

.hero-examples .examples__list {
  justify-content: center;
  max-width: 720px;
  margin: 0 auto;
}

/* ---- Responsive: the transcript column on a desktop ---- */

@media (min-width: 1024px) {
  .message__content {
    max-width: min(100%, 78%);
  }

  .bubble--user {
    max-width: min(100%, 600px);
  }

  .message__content--wide {
    max-width: 100%;
  }
}

/* ---- Responsive: the rail becomes a drawer on a phone or a narrow window ---- */

@media (max-width: 820px) {
  .app {
    position: relative;
  }

  .rail {
    position: fixed;
    inset: 0 auto 0 0;
    z-index: 40;
    width: min(var(--rail-width), 86vw);
    margin-left: 0;
    transform: translateX(-100%);
    box-shadow: none;
  }

  .app--rail-hidden .rail {
    margin-left: 0;
  }

  /* On a phone the rail is OPEN only when asked (.app--drawer-open), never by default. */
  .app--drawer-open .rail {
    transform: translateX(0);
    box-shadow: 12px 0 40px rgba(0, 0, 0, 0.45);
  }

  .scrim {
    position: fixed;
    inset: 0;
    z-index: 35;
    background: rgba(20, 12, 15, 0.55);
  }

  .scrim[hidden] {
    display: none;
  }

  .main {
    margin-top: 0;
    border-top-left-radius: 0;
  }

  .topbar {
    border-bottom: 1px solid var(--border);
    min-height: 50px;
  }

  .topbar #rail-open,
  .app--rail-hidden .topbar #rail-open {
    display: inline-flex;
  }

  .topbar__new {
    width: 32px;
    height: 32px;
    padding: 0;
    justify-content: center;
    border: none;
  }

  .topbar__new-label {
    display: none;
  }

  .topbar__title {
    text-align: center;
  }

  .hero__title {
    font-size: 27px;
  }
}

/* The scrim only ever exists at drawer widths. */
@media (min-width: 821px) {
  .scrim {
    display: none !important;
  }
}

/* ---- Responsive: comfortable on a phone ---- */

@media (max-width: 640px) {
  :root {
    --gutter: 14px;
  }

  .message__content {
    max-width: 100%;
  }

  .chat {
    gap: var(--sp-4);
  }

  .sg-card {
    padding: var(--sp-3);
  }

  .msg-action {
    width: 30px;
    height: 30px;
  }

  .msg-actions {
    min-height: 30px;
  }

  .vote-note__row {
    flex-direction: column;
    align-items: stretch;
  }

  .ask__options {
    flex-direction: column;
    align-items: stretch;
  }

  .ask__option--detailed {
    flex: 0 0 auto;
  }

  .hero__title {
    font-size: 24px;
  }

  .hero__blurb {
    font-size: 14px;
    margin-bottom: 18px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .rail {
    transition: none;
  }
  /* The clash keeps its red edge, hatch and ⚠ — only the pulse goes. */
  .sg-block--conflict,
  .sg-key__chip--warning {
    animation: none;
  }
}

/* No entrance animation while a reopened conversation is being replayed (see app.js). */
.app--replaying .message {
  animation: none;
}


/* ---- Report a problem (§21.6): a small sheet over the page ---- */

.support {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-4);
}

.support[hidden] {
  display: none;
}

.support__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(28, 16, 20, 0.42);
}

.support__sheet {
  position: relative;
  width: min(520px, 100%);
  padding: var(--sp-5);
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
}

.support__title {
  margin: 0 0 var(--sp-2);
  font-size: 18px;
}

.support__blurb {
  margin: 0 0 var(--sp-3);
  font-size: 13.5px;
  color: var(--text-muted);
}

.support__input {
  width: 100%;
  box-sizing: border-box;
  padding: 10px 12px;
  font: inherit;
  font-size: 14px;
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  resize: vertical;
}

.support__input:focus {
  outline: 2px solid var(--aub-red);
  outline-offset: 1px;
}

.support__row {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-top: var(--sp-3);
}

.support__status {
  flex: 1;
  font-size: 12.5px;
  color: var(--text-muted);
}

.support__cancel,
.support__send {
  padding: 8px 14px;
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  border-radius: 999px;
  cursor: pointer;
}

.support__cancel {
  color: var(--text);
  background: transparent;
  border: 1px solid var(--border-strong);
}

.support__send {
  color: #fff;
  background: var(--aub-red);
  border: 1px solid var(--aub-red);
}

.support__send:disabled {
  opacity: 0.6;
  cursor: default;
}

/* ---- Degree progress card (kind: "audit", ARCHITECTURE.md §26) ----
   The sg-card's sibling: a sectioned list, one block per report section, codes as chips. Each
   section label carries a quiet tint — green for satisfied, amber for in progress, maroon for
   outstanding, slate for unresolved — so the four states of a LINE read apart at a glance. They
   are states of requirement lines, never of the student: the disclaimer under every report says
   so, and it is never hover-hidden. */
.au-card {
  width: 100%;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
  padding: var(--sp-4);
}

.au-summary {
  margin: var(--sp-2) 0 0;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--text);
}

.au-section {
  margin-top: var(--sp-3);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--border);
}

.au-section__label {
  display: block;
  font-size: var(--micro-size);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--micro-tracking);
  color: var(--text-muted);
  margin-bottom: 6px;
}

.au-section--satisfied .au-section__label {
  color: var(--note-ok-label);
}

.au-section--in-progress .au-section__label {
  color: var(--note-label);
}

.au-section--outstanding .au-section__label {
  color: var(--aub-red-700);
}

.au-section--unresolved .au-section__label {
  color: var(--note-design-label);
}

.au-line {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 6px;
  margin: 4px 0 0;
  font-size: 13px;
  line-height: 1.45;
  color: var(--text);
}

.au-line__name {
  font-weight: 600;
}

.au-line__name::after {
  content: ":";
}

.au-chip {
  display: inline-block;
  padding: 1px 7px;
  border-radius: 999px;
  border: 1px solid var(--border-strong);
  background: var(--surface-sunken);
  font-size: 12px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  color: var(--text);
}

.au-section--satisfied .au-chip {
  border-color: var(--note-ok-border);
  background: var(--note-ok-bg);
}

.au-section--outstanding .au-chip {
  border-color: var(--ask-option-border);
  background: var(--aub-red-tint);
}

.au-line__note,
.au-line__rule {
  margin: 2px 0 0 var(--sp-3);
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--text-muted);
}

.au-line__rule {
  font-style: italic;
}

.au-section--muted .au-line__text {
  color: var(--text-muted);
}

/* The required disclaimer — visible on every report, never hover-hidden (§26). */
.au-disclaimer {
  margin-top: var(--sp-3);
  padding-top: var(--sp-2);
  border-top: 1px dashed var(--border-strong);
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--text-faint);
}

.au-sources {
  margin-top: var(--sp-2);
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--text-faint);
}
