/* ==========================================================================
   RITE Email Triage — "Morning Edition"
   Editorial, paper-and-ink aesthetic. Display: Fraunces. Body: IBM Plex Sans.
   ========================================================================== */

:root {
  --paper: #f6f1e7;
  --paper-2: #efe8da;
  --paper-3: #e6dcc9;
  --ink: #1f1d1a;
  --ink-2: #4a453e;
  --ink-3: #857d72;
  --rule: rgba(31, 29, 26, 0.16);
  --vermilion: #b4331e;
  --vermilion-soft: rgba(180, 51, 30, 0.1);
  --amber: #d98e2b;
  --amber-soft: rgba(217, 142, 43, 0.14);
  --slate: #3f5e7a;
  --slate-soft: rgba(63, 94, 122, 0.12);
  --moss: #4f6f4a;
  --moss-soft: rgba(79, 111, 74, 0.14);

  --font-display: "Fraunces", Georgia, "Times New Roman", serif;
  --font-body: "IBM Plex Sans", "Segoe UI", sans-serif;
  --font-mono: "IBM Plex Mono", Consolas, monospace;

  --radius: 4px;
  --shadow: 0 1px 0 rgba(31, 29, 26, 0.06), 0 18px 40px -24px rgba(31, 29, 26, 0.45);
  --ease: cubic-bezier(0.22, 1, 0.36, 1);

  /* Schedule grid geometry - one place so the month's gutter, its cells and the week's cells
     cannot drift apart, and so the phone breakpoint can resize all three at once. The gutter is
     a real track and the gap beside it is one too, so the seven day columns are never narrowed
     by the week number. */
  --month-gutter: 34px;   /* fits a two-digit week number at the 10px mono size */
  --month-gutter-gap: 6px;
  --month-cell-h: 96px;
  --week-cell-h: 190px;
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scrollbar-gutter: stable; }
body {
  margin: 0;
  min-height: 100vh;
  color: var(--ink);
  background:
    radial-gradient(1200px 600px at 10% -10%, rgba(217, 142, 43, 0.12), transparent 60%),
    radial-gradient(900px 500px at 110% 10%, rgba(63, 94, 122, 0.12), transparent 55%),
    var(--paper);
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}
a { color: inherit; }
button { font: inherit; color: inherit; }
img { max-width: 100%; display: block; }
[hidden] { display: none !important; }

.grain {
  position: fixed; inset: 0; pointer-events: none; z-index: 0; opacity: 0.35; mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.22 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
}

/* ---------- Typography helpers ---------- */
.eyebrow {
  margin: 0 0 6px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.muted { color: var(--ink-3); }
.link {
  background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--slate); text-decoration: underline; text-underline-offset: 3px; font-size: 13px;
}
.link:hover { color: var(--ink); }
h1, h2, h3 { font-family: var(--font-display); font-weight: 500; letter-spacing: -0.01em; margin: 0; }
h1 { font-size: clamp(28px, 3.4vw, 42px); line-height: 1.05; }
h2 { font-size: 20px; }
h3 { font-size: 12px; font-family: var(--font-mono); text-transform: uppercase; letter-spacing: 0.12em; color: var(--ink-3); font-weight: 500; }
code { font-family: var(--font-mono); font-size: 0.9em; background: var(--paper-2); padding: 1px 5px; border-radius: 3px; }

/* ---------- Reveal animation ---------- */
.reveal { animation: rise 0.7s var(--ease) both; }
.reveal-delay { animation-delay: 0.12s; }
@keyframes rise { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  padding: 11px 18px; border-radius: var(--radius); border: 1px solid var(--ink);
  background: var(--ink); color: var(--paper); font-weight: 500; font-size: 14px;
  cursor: pointer; text-decoration: none; position: relative;
  transition: transform 0.2s var(--ease), background 0.2s, color 0.2s, border-color 0.2s;
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); }
.btn:disabled { opacity: 0.55; cursor: progress; transform: none; }
.btn-primary { background: var(--vermilion); border-color: var(--vermilion); }
.btn-primary:hover { background: #9c2b18; }
.btn-ghost { background: transparent; color: var(--ink); border-color: var(--rule); }
.btn-ghost:hover { border-color: var(--ink); }
.btn-critical { background: var(--vermilion-soft); color: var(--vermilion); border-color: transparent; }
.btn-critical:hover { background: var(--vermilion); color: var(--paper); }
.btn-ms { background: #fff; color: var(--ink); border-color: var(--rule); }
.btn-ms:hover { border-color: var(--ink); }
.btn-sm { padding: 7px 12px; font-size: 13px; }
#setup-prompt .btn, #setup-detail .btn-primary { width: 100%; }
#cancel-setup { margin-top: 22px; }
.btn-spinner {
  width: 14px; height: 14px; border-radius: 50%; display: none;
  border: 2px solid rgba(255,255,255,0.35); border-top-color: #fff; animation: spin 0.8s linear infinite;
}
.btn.is-busy .btn-spinner { display: inline-block; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ---------- Forms ---------- */
.field { display: grid; gap: 6px; margin-bottom: 14px; }
.field span { font-size: 12px; font-weight: 500; color: var(--ink-2); letter-spacing: 0.02em; }
input, select, textarea {
  font: inherit; color: var(--ink); background: #fffdf8;
  border: 1px solid var(--rule); border-radius: var(--radius); padding: 10px 12px; width: 100%;
  transition: border-color 0.2s, box-shadow 0.2s;
}
input:focus, select:focus, textarea:focus { outline: none; border-color: var(--slate); box-shadow: 0 0 0 3px var(--slate-soft); }
textarea { min-height: 160px; resize: vertical; line-height: 1.6; }
.inline-form { display: grid; grid-template-columns: 1fr auto auto; gap: 8px; margin: 10px 0 16px; }
.inline-form select { width: auto; }

/* ---------- Alerts / banners / toast ---------- */
.alert { padding: 10px 12px; border-radius: var(--radius); font-size: 13px; margin-bottom: 14px; }
.alert-error { background: var(--vermilion-soft); color: var(--vermilion); border: 1px solid rgba(180,51,30,0.3); }
.banner {
  display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap;
  padding: 14px 18px; border-radius: var(--radius); margin-bottom: 22px; font-size: 14px;
}
.banner-warn { background: var(--amber-soft); border: 1px solid rgba(217,142,43,0.4); }
/* Centering is layout-based (a full-width fixed strip + centered pill) rather than the classic
   left:50%/translateX(-50%), so the pill shares app-main's centred column and can never sit at a
   different centre than the content when the vertical scrollbar appears or disappears (paired with
   scrollbar-gutter: stable on html). The strip is full width but click-through (pointer-events:
   none); only the pill takes pointer events. The pill keeps the "rise" entrance - its transform
   animation is on the pill, not the strip, so it never fights the horizontal centring. */
.toast {
  position: fixed; left: 0; right: 0; bottom: 28px; z-index: 60;
  display: flex; justify-content: center; pointer-events: none;
}
.toast-inner {
  pointer-events: auto;
  background: var(--ink); color: var(--paper); padding: 11px 16px; border-radius: var(--radius);
  font-size: 14px; box-shadow: var(--shadow);
  animation: rise 0.35s var(--ease);
}
.toast.is-error .toast-inner { background: var(--vermilion); }

/* ---------- Build stamp ---------- */
/* Fixed bottom-right chip: a small card (the same paper/shadow/rule language as every other
   surface), not text painted over the page. Below the drawer/toast layer, and pointer-events
   none so it is context that never steals clicks. The grain overlay sits at z-index 0 with
   multiply blending, so this needs a solid background to read cleanly above it. */
.app-version {
  position: fixed; right: 14px; bottom: 10px; z-index: 30; pointer-events: none;
  display: inline-flex; align-items: baseline; gap: 5px;
  padding: 5px 11px; border: 1px solid var(--rule); border-radius: 999px;
  background: #fffdf8; box-shadow: var(--shadow);
  font-size: 11.5px; color: var(--ink-3); white-space: nowrap;
}
.app-version-label {
  font-family: var(--font-mono); font-size: 9.5px; text-transform: uppercase;
  letter-spacing: 0.12em; color: var(--ink-3);
}
.app-version-value {
  font-family: var(--font-mono); font-size: 11px; color: var(--ink);
  font-variant-numeric: tabular-nums; letter-spacing: 0.02em;
}

/* ---------- Login page ---------- */
.login-layout {
  position: relative; z-index: 1;
  min-height: 100vh; display: grid; grid-template-columns: minmax(0, 1.3fr) minmax(360px, 480px);
  gap: 48px; padding: clamp(24px, 5vw, 72px); align-items: center; max-width: 1280px; margin: 0 auto;
}
.masthead-kicker { font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-3); }
.masthead-title {
  font-family: var(--font-display); font-weight: 300; font-size: clamp(48px, 7vw, 96px);
  line-height: 0.95; letter-spacing: -0.03em; margin: 18px 0 22px;
  font-variation-settings: "opsz" 144;
}
.masthead-title em { font-style: italic; font-weight: 600; color: var(--vermilion); }
.masthead-standfirst { max-width: 52ch; font-size: 17px; color: var(--ink-2); margin: 0; }
.hero-features { list-style: none; padding: 0; margin: 40px 0 0; border-top: 1px solid var(--rule); }
.hero-features li { display: flex; gap: 18px; padding: 16px 0; border-bottom: 1px solid var(--rule); align-items: baseline; }
.hero-features .feature-num { font-family: var(--font-mono); color: var(--vermilion); font-size: 12px; min-width: 28px; }
.hero-features strong { display: block; font-family: var(--font-display); font-size: 19px; font-weight: 500; }
.hero-features span:not(.feature-num) { color: var(--ink-3); font-size: 14px; }

.login-card {
  background: #fffdf8; border: 1px solid var(--rule); border-radius: 6px; box-shadow: var(--shadow); position: relative;
}
.login-card::before {
  content: ""; position: absolute; inset: 0 auto 0 0; width: 4px; background: var(--vermilion); border-radius: 6px 0 0 6px;
}
.login-card-inner { padding: 36px 36px 28px; }
.card-title { font-size: 30px; margin-bottom: 20px; }
.divider { display: flex; align-items: center; gap: 12px; margin: 22px 0; color: var(--ink-3); font-size: 12px; }
.divider::before, .divider::after { content: ""; flex: 1; height: 1px; background: var(--rule); }
.btn-ms { width: 100%; }
.form .btn { width: 100%; margin-top: 4px; }
.hint { font-size: 12px; color: var(--ink-3); margin: 10px 0 0; }
.fineprint { margin: 22px 0 0; font-size: 12px; color: var(--ink-3); line-height: 1.5; }

/* ---------- Login page: instance-lock panel ---------- */
/* The lock replaces the sign-in FORM, not the page. index.html carries both panels in
   the right-hand card; the server (app/main.py's index route) adds page-login-locked to
   <body> while the license is locked, and these rules swap one for the other. The left
   hero stays: the login screen keeps its shape, and the lock reads as a state of it
   rather than the old full-screen error page.
   [hidden] is spelled out because several rules here set display on their class (a UA
   [hidden] rule has no specificity and loses to all of them). */
.login-lock { display: none; }
.login-lock .card-title { color: var(--vermilion); }
.login-lock-copy { color: var(--ink-2); line-height: 1.55; margin: 0 0 12px; font-size: 15px; }
.page-login-locked #login-signin, .page-login-locked #login-signin [hidden] { display: none; }
.page-login-locked .login-lock { display: block; }

/* ---------- App shell ---------- */
.page-app .btn-ms { width: auto; }
.topbar {
  position: sticky; top: 0; z-index: 20;
  display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 24px;
  padding: 14px clamp(16px, 3vw, 40px); background: rgba(246, 241, 231, 0.88); backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--rule);
}
.topbar-brand { display: flex; align-items: center; gap: 10px; }
/* Envelope mark (app/static/img/logo-mark.svg) + the text lockup, restoring the full
   "RITE Email Triage" wordmark beside the mark. The spans reuse the lockup's typographic
   treatment (see app/static/img/logo.svg); the old pre-lockup block element stays retired. */
.brand-logo { display: block; height: 26px; width: auto; }
.brand-word {
  font-family: var(--font-display); font-size: 22px; line-height: 1;
  letter-spacing: -0.01em; white-space: nowrap;
}
.brand-word .w-rite { font-weight: 700; color: var(--ink); }
.brand-word .w-email { font-weight: 400; color: var(--ink-2); }
.brand-word .w-triage { font-weight: 500; font-style: italic; color: var(--vermilion); }
/* The brand cell shares the top bar grid with centred nav; below 600px the word is dropped
   (consistent with the nav-wrap breakpoint) so the mark alone never collides with the nav. */
@media (max-width: 600px) { .brand-word { display: none; } }
.topbar-nav { display: flex; gap: 4px; justify-content: center; }
.nav-link {
  background: none; border: 0; padding: 8px 14px; border-radius: 999px; cursor: pointer; font-size: 14px;
  color: var(--ink-2); display: inline-flex; align-items: center; gap: 8px; transition: background 0.2s, color 0.2s;
}
.nav-link:hover { background: var(--paper-2); color: var(--ink); }
.nav-link.is-active { background: var(--ink); color: var(--paper); }
.pill { font-family: var(--font-mono); font-size: 11px; padding: 1px 7px; border-radius: 999px; background: var(--paper-3); color: var(--ink); }
.pill-critical { background: var(--vermilion); color: #fff; }
.topbar-user { display: flex; align-items: center; gap: 12px; font-size: 13px; }
.user-graph { width: 9px; height: 9px; border-radius: 50%; background: var(--ink-3); }
.user-graph.is-connected { background: var(--moss); box-shadow: 0 0 0 3px var(--moss-soft); }

/* ---------- User menu (name -> profile settings / sign out) ---------- */
.user-menu-wrap { position: relative; }
.user-menu-btn {
  display: inline-flex; align-items: center; gap: 6px; background: none; border: none; cursor: pointer;
  font: inherit; color: var(--ink); padding: 4px 6px; border-radius: var(--radius);
}
.user-menu-btn:hover { background: var(--paper-3); }
.user-menu-caret { font-size: 10px; color: var(--ink-3); }
.user-menu {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 70; min-width: 210px;
  background: var(--paper); border: 1px solid var(--ink); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 6px; display: flex; flex-direction: column; gap: 2px;
}
.user-menu-email {
  padding: 6px 8px 8px; font-size: 12px; color: var(--ink-3); border-bottom: 1px solid var(--rule);
  margin-bottom: 4px; word-break: break-all;
}
.user-menu-item {
  display: block; width: 100%; text-align: left; background: none; border: none; cursor: pointer;
  font: inherit; color: var(--ink); padding: 8px; border-radius: calc(var(--radius) / 2);
}
.user-menu-item:hover { background: var(--paper-3); }

/* ---------- Timezone combobox (searchable, server-backed zone list) ---------- */
.tz-combo { position: relative; }
.tz-combo-list {
  position: absolute; left: 0; right: 0; top: 100%; z-index: 5; max-height: 220px; overflow-y: auto;
  background: var(--paper); border: 1px solid var(--ink); border-radius: var(--radius);
  box-shadow: var(--shadow); margin-top: 4px;
}
.tz-combo-option {
  display: flex; justify-content: space-between; gap: 10px; width: 100%; text-align: left;
  background: none; border: none; cursor: pointer; font: inherit; color: var(--ink); padding: 7px 10px;
}
.tz-combo-option:hover, .tz-combo-option.is-active { background: var(--paper-3); }
.tz-combo-option-tz { font-variant-numeric: tabular-nums; }
.tz-combo-option-label { color: var(--ink-3); font-size: 12px; }
.tz-combo-empty { padding: 8px 10px; font-size: 13px; color: var(--ink-3); }
.tz-combo-hint { font-size: 12px; margin-top: 5px; }
.tz-combo-hint.is-error { color: var(--vermilion); }

.app-main { position: relative; z-index: 1; max-width: 1240px; margin: 0 auto; padding: 36px clamp(16px, 3vw, 40px) 80px; }
.view { display: none; }
.view.is-active { display: block; }
.view-head { display: flex; justify-content: space-between; align-items: flex-end; gap: 24px; flex-wrap: wrap; margin-bottom: 28px; padding-bottom: 18px; border-bottom: 2px solid var(--ink); }
.toolbar { display: flex; gap: 10px; align-items: center; }
.toolbar input { width: 260px; }
.toolbar select { width: auto; }
.segmented { display: inline-flex; border: 1px solid var(--rule); border-radius: 999px; padding: 3px; background: var(--paper-2); }
.segmented button { border: 0; background: none; padding: 6px 14px; border-radius: 999px; cursor: pointer; font-size: 13px; color: var(--ink-2); }
.segmented button.is-active { background: var(--ink); color: var(--paper); }

/* ---------- Today / brief ---------- */
.brief-header { display: grid; grid-template-columns: 1fr auto; gap: 32px; align-items: end; margin-bottom: 26px; }
.brief-title { font-size: clamp(34px, 4.5vw, 56px); font-weight: 400; letter-spacing: -0.025em; }
.brief-title span { font-style: italic; font-weight: 600; }
.brief-summary { max-width: 70ch; font-size: 17px; color: var(--ink-2); margin: 14px 0 0; font-family: var(--font-display); line-height: 1.5; }
.last-triaged { font-family: var(--font-mono); font-size: 11.5px; letter-spacing: 0.02em; color: var(--ink-3); margin: 10px 0 0; }

/* ---------- Profile modal: signature section ---------- */
.sig-toggle-row { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--ink-2); cursor: pointer; }
.sig-toggle-row input[type="checkbox"] { width: auto; margin: 0; }
.sig-actions { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.sig-actions .tz-combo-hint { flex: 1; min-width: 0; }
.sig-btn-row { display: flex; gap: 8px; }

/* ---------- WYSIWYG rich-text editor (signature + draft reply body) ---------- */
.rte { border: 1px solid var(--rule); border-radius: var(--radius); background: #fffdf8; overflow: hidden; }
.rte-toolbar {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px; padding: 6px 8px;
  border-bottom: 1px solid var(--rule); background: var(--paper-2, #f3ede2);
}
.rte-btn {
  width: 30px; height: 28px; display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid transparent; background: transparent; color: var(--ink); cursor: pointer;
  border-radius: 6px; font-size: 13px; font-family: var(--font-body);
}
.rte-btn:hover { background: #fff; border-color: var(--rule); }
.rte-btn:disabled { opacity: 0.45; cursor: default; }
.rte-select { width: auto; padding: 3px 6px; font-size: 12px; border-radius: 6px; }
.rte-color { width: 30px; height: 28px; padding: 0; border: 1px solid transparent; border-radius: 6px; background: transparent; }
.rte-sep { width: 1px; height: 20px; background: var(--rule); margin: 0 3px; }
.rte-btn-row { display: inline-flex; gap: 2px; }
.rte-editable {
  padding: 10px 12px; font-size: 14px; line-height: 1.6; overflow-y: auto; position: relative;
}
.rte-editable:focus { outline: none; }
.rte-editable:empty::before { content: attr(data-placeholder); color: var(--ink-3); pointer-events: none; }
.rte-editable img { max-width: 100%; height: auto; }
.rte-editable[contenteditable="false"] { background: var(--paper-2, #f3ede2); color: var(--ink-2); }
.rte-source {
  width: 100%; min-height: 140px; border: none; border-radius: 0; resize: vertical;
  font-family: var(--font-mono); font-size: 12px;
}
.rte-source:focus { outline: none; box-shadow: none; border: none; }

/* ---------- Profile modal: reply font section ---------- */
.reply-font-row { display: flex; gap: 8px; }
.reply-font-row select { flex: 1; min-width: 0; }
/* The font-size input is a plain text field (type=text + inputMode=numeric), so it has
   no native spinner at all - nothing to fight over space with the "pt" suffix. */
.reply-font-row .size-field { position: relative; flex: none; width: 90px; }
.reply-font-row .size-field input { padding-right: 24px; }
/* Kept as a safety net in case a native number input is ever reintroduced here (e.g.
   a browser that ignores type=text's lack of a spinner). */
.reply-font-row .size-field input::-webkit-outer-spin-button,
.reply-font-row .size-field input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.reply-font-row .size-suffix {
  position: absolute; right: 10px; top: 50%; transform: translateY(-50%);
  font-size: 12px; pointer-events: none;
}

.reply-font-preview {
  border: 1px solid var(--paper-3); border-radius: 8px; padding: 10px 12px; background: #fff;
  color: var(--ink-2); margin-top: 2px;
}

.brief-actions { display: flex; flex-direction: column; gap: 10px; align-items: stretch; }

/* License seat usage (Admin → People). Deliberately not the triage bar's shape or
   colour: that one sweeps to mean "work is happening", and a seat count is a static
   fact. Uses the same tokens so it reads as the same app. */
.seat-bar {
  width: 100%; height: 6px; border-radius: 999px; background: var(--paper-3);
  overflow: hidden; margin: 0 0 8px;
}
.seat-bar-fill {
  height: 100%; min-width: 2%; border-radius: 999px; background: var(--moss);
  transition: width 0.4s var(--ease);
}
.seat-bar-fill.is-nearly-full { background: var(--amber); }
.seat-bar-fill.is-full { background: var(--vermilion); }

/* Queue an address before its owner signs in (Admin → People). Sits under the
   directory it feeds, reads as one row of the list rather than a floating form. */
.person-add {
  display: flex; gap: 8px; align-items: center; margin: 12px 0 0;
}
.person-add input[type="email"] { flex: 1 1 auto; min-width: 0; }

.triage-progress { margin: 0 0 26px; animation: rise 0.3s var(--ease) both; }
.triage-progress-bar {
  width: 100%; height: 6px; border-radius: 999px; background: var(--paper-3); overflow: hidden;
}
.triage-progress-fill {
  height: 100%; width: 6%; min-width: 6%; border-radius: 999px; background: var(--vermilion);
  transition: width 0.4s var(--ease);
}
.triage-progress.is-indeterminate .triage-progress-fill {
  width: 30% !important; animation: triage-indeterminate 1.3s ease-in-out infinite;
}
@keyframes triage-indeterminate {
  0% { transform: translateX(-100%); }
  100% { transform: translateX(333%); }
}
.triage-progress-text {
  margin: 8px 0 0; font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.03em; color: var(--ink-3);
}

.stat-strip {
  display: grid; grid-template-columns: repeat(5, 1fr); border-top: 1px solid var(--ink); border-bottom: 1px solid var(--rule);
  margin-bottom: 36px;
}
.stat { padding: 18px 16px 16px; border-right: 1px solid var(--rule); }
.stat:last-child { border-right: 0; }
.stat-num { display: block; font-family: var(--font-display); font-size: 40px; font-weight: 300; line-height: 1; letter-spacing: -0.03em; }
.stat:first-child .stat-num { color: var(--vermilion); }
.stat-label { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-3); }

/* ---------- Admin: Microsoft 365 setup panel (Admin tab card) ---------- */
.ms-setup { border: 1px solid var(--rule); border-radius: 6px; padding: 22px 24px; margin-bottom: 36px; background: var(--paper-2); }
.ms-setup .column-head { justify-content: flex-start; gap: 12px; }

/* ---------- Microsoft 365 setup page (/microsoft-setup) ---------- */
.setup-page { max-width: 860px; }
.setup-intro { font-size: 16px; color: var(--ink-2); font-family: var(--font-display); line-height: 1.55; max-width: 70ch; margin: 0 0 18px; }
.setup-steps { margin: 28px 0 0; padding-left: 26px; display: grid; gap: 30px; counter-reset: setup-step; }
.setup-steps > li { padding-left: 6px; }
.setup-steps > li::marker { content: counter(setup-step, decimal-leading-zero) "  "; counter-increment: setup-step; font-family: var(--font-mono); font-size: 13px; color: var(--vermilion); }
.setup-steps h3 { font-size: 17px; font-family: var(--font-display); text-transform: none; letter-spacing: -0.01em; color: var(--ink); font-weight: 600; margin-bottom: 8px; }
.setup-steps p { margin: 8px 0; line-height: 1.6; }
.setup-checklist { margin: 8px 0; padding-left: 20px; display: grid; gap: 8px; line-height: 1.55; }
.setup-permissions-table { margin: 10px 0 14px; font-size: 13px; }
.setup-permissions-table code { font-size: 12px; }
.copy-field { display: flex; align-items: center; gap: 8px; margin: 8px 0; }
.copy-field code {
  flex: 1; overflow-x: auto; white-space: nowrap; padding: 8px 10px; background: #fffdf8;
  border: 1px solid var(--rule); border-radius: var(--radius);
}
.copy-btn.is-copied { background: var(--moss-soft); border-color: transparent; color: var(--moss); }

.today-grid { display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(280px, 1fr); gap: 40px; }
.column-head { display: flex; justify-content: space-between; align-items: baseline; padding-bottom: 10px; border-bottom: 1px solid var(--ink); margin-bottom: 8px; }
.column-tools { display: flex; gap: 14px; align-items: center; }
.column-side > section + section { margin-top: 32px; }
.empty { color: var(--ink-3); font-style: italic; font-family: var(--font-display); padding: 22px 0; }
.chart { border: 1px solid var(--rule); border-radius: var(--radius); background: var(--paper); }
/* History chart spans the full column - figsize (11:3.4) matches natural width - and pins its
   bottom edge to the container so the rendered height never rounds a hair short and scrolls. */
.chart-wide { display: block; width: 100%; height: auto; min-height: 0; margin-bottom: 26px; }
/* Wraps the history chart's <img> so the hover tooltip has a positioned ancestor that is exactly
   the image's box - the tooltip's left/top are computed from the pointer's position within it. */
.chart-history-wrap { position: relative; }
.chart-tooltip {
  position: absolute; z-index: 6; transform: translate(-50%, calc(-100% - 10px));
  pointer-events: none; min-width: 130px; padding: 8px 10px;
  background: #fffdf8; border: 1px solid var(--rule); border-radius: var(--radius);
  box-shadow: 0 4px 14px rgba(31, 29, 26, 0.14); font-size: 12px; color: var(--ink-2);
}
.chart-tooltip-title { font-weight: 600; color: var(--ink); margin-bottom: 4px; }
.chart-tooltip-row { display: flex; align-items: center; gap: 6px; line-height: 1.5; }
.chart-tooltip-swatch { width: 8px; height: 8px; border-radius: 2px; flex: none; }
.chart-tooltip-total { margin-top: 4px; padding-top: 4px; border-top: 1px solid var(--rule); }


/* ---------- Action list ---------- */
.action-list { list-style: none; margin: 0; padding: 0; counter-reset: act; }
.action-item {
  display: grid; grid-template-columns: 28px 1fr auto; gap: 14px; align-items: start;
  padding: 14px 0; border-bottom: 1px solid var(--rule); animation: rise 0.4s var(--ease) both;
}
.action-item::before {
  counter-increment: act; content: counter(act, decimal-leading-zero);
  font-family: var(--font-mono); font-size: 12px; color: var(--ink-3); padding-top: 3px;
}
.action-item.is-done { opacity: 0.5; }
.action-item.is-done .action-title { text-decoration: line-through; }
.action-title { font-family: var(--font-display); font-size: 18px; font-weight: 500; line-height: 1.3; margin: 0; }
.action-meta { display: flex; gap: 10px; align-items: center; margin-top: 5px; font-size: 12px; color: var(--ink-3); flex-wrap: wrap; }
.action-meta .link { font-size: 12px; }
.action-buttons { display: flex; gap: 6px; }
.check {
  width: 30px; height: 30px; border-radius: 50%; border: 1px solid var(--rule); background: transparent; cursor: pointer;
  display: inline-grid; place-items: center; transition: background 0.2s, color 0.2s, border-color 0.2s;
}
.check:hover, .check.is-checked { background: var(--moss); border-color: var(--moss); color: #fff; }
/* The done circle is 30px, the row's other controls are 36px (btn-sm: 7px padding + 1px border
   either side over a 13px/1.55 line). The row aligns its columns to the top, so leaving the
   circle there kept its top flush but left all 6px of the difference as a gap underneath -
   which reads as the circle sitting too high next to Block time and Dismiss. Centring it puts
   half the difference above and half below, which is what .block-chip already does (the line
   below is the reason that chip measured an even gap top and bottom). */
.action-buttons .check { align-self: center; }

/* ---------- Snoozed group (Today) ---------- */
/* Collapsed by default: a snooze hides the noise, the group keeps the hiding honest. Mirrors
   the recipient-list disclosure (caret rotates open), and the rows reuse .action-item -
   is-snoozed only dims them, never strikes through: a snoozed to-do is not a finished one. */
.snoozed-group { margin-top: 14px; border-top: 1px solid var(--rule); padding-top: 10px; }
.snoozed-group summary {
  display: flex; align-items: center; gap: 8px; cursor: pointer; list-style: none;
  font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--ink-3);
}
.snoozed-group summary::-webkit-details-marker { display: none; }
.snoozed-group summary .caret { transition: transform 0.2s var(--ease); }
.snoozed-group[open] summary .caret { transform: rotate(90deg); }
.snoozed-group .snoozed-count { color: var(--ink-2); }
.action-item.is-snoozed { opacity: 0.7; }

/* ---------- The "Actions" menu (Today action cards) ---------- */
/* Full-width rows inside the shared rename-dialog shell - one backdrop, one Escape, one
   styling; a dropdown of absolutely-positioned buttons would have needed all three again. */
.action-menu { display: flex; flex-direction: column; }
.action-menu-item {
  display: block; width: 100%; text-align: left; background: transparent; border: 0;
  border-bottom: 1px solid var(--rule); padding: 11px 2px; cursor: pointer;
  font-family: var(--font-body); font-size: 14px; color: var(--ink);
}
.action-menu-item:last-child { border-bottom: 0; }
.action-menu-item:hover { color: var(--moss); }

/* ---------- Action details dialog: notes ---------- */
.note-list { max-height: 180px; overflow-y: auto; margin-bottom: 10px; display: flex; flex-direction: column; gap: 8px; }
.note-row { display: flex; flex-direction: column; gap: 2px; font-size: 13px; }
.note-row .note-date { font-family: var(--font-mono); font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--ink-3); }
.note-row .note-text { white-space: pre-wrap; }
.note-list:empty::after { content: "No notes yet."; color: var(--ink-3); font-size: 12px; }
.note-head { margin-top: 4px; }
.rename-dialog textarea { min-height: 56px; }
.rename-dialog .field-label { margin-bottom: 12px; }

/* ---------- Tags ---------- */
.tag {
  display: inline-flex; align-items: center; gap: 6px; font-family: var(--font-mono); font-size: 11px;
  letter-spacing: 0.08em; text-transform: uppercase; padding: 2px 8px; border-radius: 3px;
  background: var(--paper-3); color: var(--ink-2);
}
.tag::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.tag-critical { background: var(--vermilion-soft); color: var(--vermilion); }
/* A RITEManage staff bar (docs/15 D addendum): amber, matching RITEManage's
   'blocked' badge - distinct from a local Reject's red. */
.tag-blocked { background: var(--amber-soft); color: #9a5f12; }
.tag-high { background: var(--amber-soft); color: #9a5f12; }
.tag-normal { background: var(--slate-soft); color: var(--slate); }
.tag-low { background: var(--paper-3); color: var(--ink-3); }
.tag-sent, .tag-approved { background: var(--moss-soft); color: var(--moss); }
.tag-rejected, .tag-failed { background: var(--vermilion-soft); color: var(--vermilion); }
.tag-pending { background: var(--amber-soft); color: #9a5f12; }
.tag-plain::before { display: none; }

/* ---------- Email list ---------- */
.email-list { display: grid; gap: 0; }
.email-row {
  display: grid; grid-template-columns: 110px minmax(0, 1fr) auto; gap: 18px; align-items: start;
  padding: 16px 0; padding-left: 14px; border-bottom: 1px solid var(--rule); cursor: pointer; animation: rise 0.4s var(--ease) both;
  transition: background 0.15s;
}
.email-row:hover { background: rgba(255, 253, 248, 0.7); }
/* Critical rows carry a 3px border in place of the plain row's left inset, so 11px + the border
   keeps their text on the same 14px line as every other row. */
.email-row.is-critical { border-left: 3px solid var(--vermilion); padding-left: 11px; }
.email-when { font-family: var(--font-mono); font-size: 12px; color: var(--ink-3); padding-top: 4px; }
.email-subject { font-family: var(--font-display); font-size: 19px; font-weight: 500; margin: 0 0 3px; line-height: 1.25; }
.email-sender { font-size: 13px; color: var(--ink-2); }
.email-summary { font-size: 14px; color: var(--ink-2); margin: 6px 0 0; max-width: 80ch; }
/* The tag cluster's right edge is the row's right edge, so the ⚑ outlook tag sits flush with the
   content column's border, and the tooltip that appears over it on hover overlaps that border.
   Insetting the cluster's box pulls the tag - and the tooltip anchored to it - in from the edge.
   Mobile drops the cluster to the left of a single-column row, where the inset is pointless. */
.email-tags { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; padding-right: 22px; }
.mini-list { list-style: none; margin: 0; padding: 0; }
.mini-list li { padding: 10px 0; border-bottom: 1px solid var(--rule); font-size: 14px; display: grid; gap: 3px; cursor: pointer; }
.mini-list li strong { font-family: var(--font-display); font-weight: 500; font-size: 16px; }
.mini-list li small { color: var(--ink-3); }

/* People directory (merged Mailbox approvals + Tenant users): one row per person. The
   facts sit on top and the action buttons sit under them, still on one line (not stacked
   per action) - then the row's bottom border closes it off. Keeps .mini-list's stacked
   look; only the buttons get a tidy horizontal row of their own. */
.person-row .row-actions { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 6px; }
.person-row .row-actions .btn { white-space: nowrap; }
/* Coded meta facts (route, decision-maker, date) that carry a hover definition. The dotted
   underline says "there's more here" without shouting - the full meaning is in the title. */
.meta-term { cursor: help; text-decoration: underline dotted; text-decoration-color: var(--rule); text-underline-offset: 2px; }
.meta-term:hover { text-decoration-color: var(--ink-3); }

/* ---------- Drafts ---------- */
.draft-list { display: grid; gap: 22px; }
.draft-card {
  background: #fffdf8; border: 1px solid var(--rule); border-radius: 6px; box-shadow: var(--shadow);
  overflow: hidden; animation: rise 0.45s var(--ease) both;
}
.draft-head { display: flex; justify-content: space-between; gap: 16px; padding: 16px 20px; border-bottom: 1px solid var(--rule); background: var(--paper-2); }
.draft-head h2 { font-size: 18px; }
.draft-to { font-size: 13px; color: var(--ink-2); margin-top: 2px; }
.draft-context { padding: 14px 20px; font-size: 13px; color: var(--ink-2); border-bottom: 1px dashed var(--rule); }
.draft-body { padding: 18px 20px 6px; }
.draft-body textarea { font-family: var(--font-body); background: transparent; border-color: transparent; padding: 0; min-height: 120px; }
.draft-body textarea:focus { border-color: var(--rule); padding: 10px; background: #fff; }
.draft-foot { display: flex; justify-content: space-between; align-items: center; gap: 12px; padding: 12px 20px 16px; flex-wrap: wrap; }
.draft-foot .group { display: flex; gap: 8px; flex-wrap: wrap; }
.draft-error { color: var(--vermilion); font-size: 13px; padding: 0 20px 12px; }
/* The reviewer's own note, kept from the compose/revise that produced this body. Set apart from
   the draft itself because it is not part of the message - it is what the message was asked to
   become, and the thing to check the new body against. */
.draft-note { padding: 12px 20px; font-size: 13px; border-bottom: 1px dashed var(--rule); background: var(--paper-2); }
/* A standalone draft's subject is the user's (a reply's is its thread's), so it is editable right
   where it is displayed rather than in a dialog. Borderless until focused so the card header still
   reads as a heading. */
.draft-subject { width: 100%; margin-top: 4px; background: transparent; border-color: transparent; font-family: var(--font-display); font-size: 18px; padding: 0; }
.draft-subject:focus { border-color: var(--rule); padding: 4px 8px; background: #fff; }

/* ---------- Compose dialog (manual drafts) ---------- */
.rename-dialog.compose-dialog { width: min(560px, 100%); }
.compose-dialog textarea { min-height: 130px; font-family: var(--font-body); }
.compose-dialog .draft-recipients { padding: 0 0 10px; }
.compose-hint { font-size: 12.5px; }

/* ---------- Reply from an inbox row ---------- */
/* Resting at rest always; hover answers only the button actually under the pointer. The row-level
   hover rules that used to live here lifted *both* verbs whenever the pointer was anywhere near -
   you can't reach Regenerate without crossing the row, so Reply lit up as a liar. Per-button
   :hover/:focus is the whole effect now; :focus-within stays off too, same reason. */
.email-actions { display: flex; gap: 6px; }
.email-act {
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--moss-soft); border: 1px solid transparent; border-radius: var(--radius);
  padding: 4px 10px; font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--moss); cursor: pointer; white-space: nowrap;
}
.email-act:hover, .email-act:focus-visible { background: rgba(79, 111, 74, 0.24); border-color: var(--moss); }

/* ---------- Drawer: inline compose + the drafts section ---------- */
/* The compose panel sits between the action points and the message it answers - Outlook's shape.
   A moss wash sets it apart from the read-only sections around it without a second card border
   competing with the review card it carries. */
#drawer-compose-section { background: var(--moss-soft); border-radius: var(--radius); padding: 14px 16px; }
.drawer-compose-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 8px; }
.drawer-compose-head h3 { margin: 0; }
#drawer-compose-body > textarea { width: 100%; font-family: var(--font-body); }
.drawer-draft { border: 1px solid var(--rule); border-radius: var(--radius); padding: 12px 14px; margin-bottom: 10px; background: #fffdf8; }
.drawer-draft-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 6px; }
.drawer-draft-head .group { display: flex; gap: 6px; margin-left: auto; }
/* The drafts list shows the shared review card in its read-only flavour, which means a full
   .draft-card (with its own head and foot) inside the drawer's own framed head. Two subject lines
   and the "In reply to" line, twice, would be noise - the drawer's head already says all of it,
   so the card's is suppressed and only the formatted body with its real spacing shows through. */
.drawer-draft .draft-card { border: 0; padding: 0; background: transparent; box-shadow: none; }
.drawer-draft .draft-card > .draft-head { display: none; }
.drawer-draft .draft-card > .draft-context { display: none; }
.drawer-draft .draft-card > .draft-foot { padding: 10px 0 0; }
.drawer-draft .draft-card > .draft-foot .muted { display: none; }

/* ---------- Rename dialog (admin: local account email / display name) ---------- */
.rename-backdrop {
  position: fixed; inset: 0; z-index: 60; display: flex; align-items: center; justify-content: center;
  background: rgba(31, 29, 26, 0.35); animation: fade 0.25s both; padding: 20px;
}
.rename-dialog {
  background: var(--paper); border: 1px solid var(--ink); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 24px 26px; width: min(420px, 100%);
  /* The scroll box. It lives on the dialog rather than on any one panel's content so a wide
     payload (a meeting body full of tables) grows the popup sideways instead of opening a second
     scrollbar inside it - two nested scroll wheels over each other is the thing that reads as a
     bug. flex: 1 lets a tall dialog shrink to the viewport and hand the overflow to this one
     scroll, which is the only one the user then has to find. */
  max-height: calc(100vh - 40px); overflow: auto;
  display: flex; flex-direction: column;
}
.rename-dialog h3 { margin-bottom: 16px; }
.rename-dialog .draft-foot { padding: 12px 0 0; }

/* Profile settings carries far more content (timezone + signature + reply font) than the
   rename/confirm dialogs this class is shared with - give it room to breathe and keep the
   .rename-dialog max-height/overflow above as the safety net if a viewport is ever short
   enough for even this wider, tighter version to overflow. */
.rename-dialog.profile-dialog { width: min(600px, 100%); }
.sig-actions .tz-combo-hint { font-size: 12px; line-height: 1.45; }

/* ---------- Profile settings modal: security sections + password grid -------
   Sections stay open - no boxes, no fold-outs. The 2FA section shows its state in a
   small chip beside the label; the password block is one compact grid. */

/* Current password spans the top row; the new pair sits under it with the button
   beside those - one compact block instead of a field per line. */
.pw-grid { display: grid; grid-template-columns: 1fr 1fr auto; gap: 8px; margin-bottom: 16px; }
.pw-grid input:first-child { grid-column: 1 / -1; }
@media (max-width: 480px) {
  .pw-grid { grid-template-columns: 1fr; }
  .pw-grid input:first-child { grid-column: auto; }
}

/* One label style for every heading in the Profile settings modal - the modal title,
   "Email signature", and the two security headings. The app's established eyebrow
   treatment (see .eyebrow): mono, uppercase, letter-spaced, quiet ink. */
.section-label {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--ink-3);
}
.rename-dialog.profile-dialog .section-label { display: block; margin: 18px 0 8px; }
.rename-dialog.profile-dialog h3.section-label { margin-top: 0; margin-bottom: 16px; }
.rename-dialog.profile-dialog .field .section-label { margin-top: 0; }
/* State chip riding beside a section label (2FA's enabled / not enabled).
   Non-mono on purpose - it is a value, not another label. */
.security-value { margin-left: 8px; font-family: var(--font-body); font-size: 12px; font-weight: 400; text-transform: none; letter-spacing: 0; color: var(--ink-2); }

/* ---------- Table ---------- */
.table { width: 100%; border-collapse: collapse; font-size: 14px; }
.table th { text-align: left; font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-3); padding: 8px 10px; border-bottom: 2px solid var(--ink); }
.table td { padding: 10px; border-bottom: 1px solid var(--rule); font-variant-numeric: tabular-nums; }
/* Cells holding a control (settings table: the field and the Save/Reset pair). Table cells default
   to vertical-align: baseline, and a button's baseline sits ~7px higher than a 44px field's - so the
   whole control column rendered high and its bottom rule landed ~7px above the other cells' rule
   (measured 57px vs 64px). Middle-aligning the control cells lines every rule up and centres each
   control. Scoped to :has(control) so plain text cells elsewhere keep their baseline alignment. */
.table td:has(input, select, textarea, button) { vertical-align: middle; }
.table td > .row-actions { display: flex; gap: 6px; }
/* Keep the Save/Reset pair on one line even when the row is squeezed narrow. */
.table td > .row-actions { flex-wrap: nowrap; }
.table td > .row-actions .btn { white-space: nowrap; }
/* Keep Save/Reset on one line, side by side, with the pair centred and the row rule aligned. A <td>
   forced to display:flex supplies the gap and lays the buttons out horizontally, but stops
   contributing its content width to the column (so width:1% is needed to make the column hug the
   buttons) AND it breaks the cell's normal table layout - which is why the flex cell sat high and
   dropped the row's bottom rule. So: do NOT make the cell a flex box. Keep it a plain table cell
   (vertical-align: middle centres the pair, and the cell keeps its border-bottom), and lay the
   buttons out as inline-blocks. gap does nothing between inline-blocks, so the pair is spaced with
   the second button's margin-left instead. */
#settings-table .row-actions { display: table-cell; vertical-align: middle; width: 1%; white-space: nowrap; }
#settings-table .row-actions .btn { display: inline-block; white-space: nowrap; }
#settings-table .row-actions .btn + .btn { margin-left: 6px; }
/* One uniform height for the settings fields and rows. A <select> and a text <input> render ~0.5px
   apart at the same padding (different intrinsic line-box), so the row rules step a hair wherever
   the field type changes (the Yes/No selects vs the text fields). Fixed field + row heights make
   every rule land on the same line down the table. Scoped to #settings-table so the login and
   account forms keep their natural control sizing. */
#settings-table td input, #settings-table td select { height: 44px; }
/* Shorten the Settings column and widen the field with the room it frees. The longest label
   ("Microsoft client secret expiry") renders ~118px in this table's text, so a 176px cap (118 text +
   ~28 padding + slack) holds every label to one line while releasing the slack the column had been
   holding for the stretched table; that freed width flows to the value column, which the widened
   field below then fills. */
#settings-table td:nth-child(1), #settings-table th:nth-child(1) { max-width: 216px; }
#settings-table td:nth-child(2) input, #settings-table td:nth-child(2) select {
  width: 19.2em; max-width: 19.2em; min-width: 0; text-overflow: ellipsis;
}
/* Settings are grouped into subsections via SETTING_GROUPS in app.js (one <tbody> per group) - the
   fixed 65px height targets setting rows only, so group header rows size to their content. */
#settings-table tbody tr:not(.setting-group-row) { height: 65px; }
/* The default_timezone row uses createTzCombobox, whose input carries a <p class="tz-combo-hint">
   helper line. It is empty here (no text is set until you type, and there is no room for a caption
   in the table), yet it still reserves its 5px margin + 12px line - which stacked under the 44px
   field and pushed that one row ~12px taller than every other row. :empty targets only the blank
   helper, so a populated hint (or the profile dialog's, outside this table) stays visible. */
#settings-table .tz-combo-hint:empty { display: none; }
/* Subsection headers: one <tbody> per group, its first row is a full-width caption styled like a
   run-in label - mono small-caps like the table's own column headers, on the same paper-2 tint the
   tag pills use, so groups read as tidy bands without a heavy border grid. */
.setting-group-row td {
  padding: 7px 10px; background: var(--paper-2); border-bottom: 1px solid var(--rule);
  font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink-2); vertical-align: middle;
}
.setting-group-row .group-count { color: var(--ink-3); text-transform: none; letter-spacing: 0.04em; }

/* ---------- Triage history (chronological feed) ---------- */
/* History groups by calendar day, but within a day it is ONE stream, newest first: each run's
   brief and every action-point event sit where they happened, so the day reads top-to-bottom as
   what occurred. The #history-kind-filter select narrows the feed to one event type. */
.history-empty { color: var(--ink-3); }
.history-filter { display: flex; align-items: center; gap: 8px; }
.history-filter-label { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-3); }
.history-filter select { height: 34px; font-size: 13px; padding: 0 8px; border: 1px solid var(--rule); border-radius: var(--r); background: var(--card); color: var(--ink); }
.history-day { margin-bottom: 34px; }
.history-day-head {
  display: flex; align-items: baseline; gap: 12px; margin-bottom: 12px;
  padding-bottom: 8px; border-bottom: 2px solid var(--ink);
}
.history-day-title { font-family: var(--font-display); font-size: 20px; font-weight: 500; margin: 0; }
.history-day-runs { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-3); }
.history-day-empty { color: var(--ink-3); font-size: 13px; }
.history-stream { display: flex; flex-direction: column; gap: 10px; }
/* Shared shell for both event kinds: a left time gutter keeps the stream's rhythm scannable. */
.history-event-time { font-family: var(--font-mono); font-size: 13px; color: var(--ink); font-variant-numeric: tabular-nums; white-space: nowrap; }
.history-kind-chip {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--ink-3); background: var(--paper-3); border: 1px solid var(--rule);
  border-radius: 999px; padding: 2px 8px; white-space: nowrap;
}
/* A brief: the run's card in the stream - time, chip, status, counts across the head. */
.history-brief { border: 1px solid var(--rule); border-radius: var(--r); background: var(--card); padding: 12px 16px; }
.history-event-head { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.history-run-counts { font-family: var(--font-mono); font-size: 12px; color: var(--ink-3); }
.history-run-error { color: var(--vermilion); font-size: 13px; margin-top: 6px; }
.history-summary { font-size: 13px; color: var(--ink-2); margin: 8px 0 0; line-height: 1.5; }
/* An action: a compact row - time, kind chip, title, email context, block, status, actioned. */
.history-action { display: grid; grid-template-columns: auto auto minmax(0, 1fr) auto auto auto auto; gap: 12px; align-items: center; padding: 8px 12px; border: 1px solid var(--rule); border-radius: var(--r); background: var(--card); }
.history-action-title { font-size: 14px; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.history-action-context { font-size: 12px; color: var(--ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 260px; }
.history-action-block { font-family: var(--font-mono); font-size: 11px; color: var(--ink-3); white-space: nowrap; }
.history-action-draft { font-family: var(--font-mono); font-size: 11px; color: var(--ink-3); white-space: nowrap; }
.history-action-status { font-size: 12px; color: var(--ink-3); }
.history-action-when { font-family: var(--font-mono); font-size: 12px; color: var(--ink-3); font-variant-numeric: tabular-nums; white-space: nowrap; }
@media (max-width: 600px) {
  .history-action { grid-template-columns: auto auto minmax(0, 1fr); }
  .history-action-context, .history-action-block, .history-action-draft { grid-column: 3 / -1; }
  .history-action-when { grid-column: 1 / -1; }
}



/* ---------- Schedule tab (docs/14 M3-13) ----------
   Agenda of one day: mirrored Outlook events + proposed/booked focus blocks, merged
   chronologically, plus a 14-day jump rail. Same paper language as the rest of the app:
   mono micro-labels for the when-column, display face for titles, tag pills for status. */
.schedule-layout { display: grid; grid-template-columns: 1fr; gap: 22px; }
.day-rail { display: flex; gap: 6px; overflow-x: auto; padding: 2px 0 8px; }
.day-chip {
  display: grid; gap: 1px; justify-items: center; min-width: 44px; padding: 6px 8px; cursor: pointer;
  background: #fffdf8; border: 1px solid var(--rule); border-radius: var(--radius);
  font-family: var(--font-mono); transition: background 0.15s, border-color 0.15s;
}
.day-chip:hover { border-color: var(--ink-3); }
.day-chip .day-name { font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-3); }
.day-chip .day-num { font-size: 16px; }
.day-chip.is-active { background: var(--ink); border-color: var(--ink); color: var(--paper); }
.day-chip.is-active .day-name { color: var(--paper-3); }
.agenda-list { display: grid; gap: 0; }
/* The side column must be sized, not left `auto`. Two things conspired against it: an `auto` track
   shrinks toward 0 as a free-floating grid item is squeezed, and the `rise` animation below leaves
   a non-none transform on every card, which makes the card a containing block for floats - so the
   float trick cannot opt the time column out of the track sizing here either. With the third track
   collapsed to nothing, justify-items:end and the foot's flex-end pushed against an edge that had
   itself collapsed to x=0, and the status chip plus Book/Dismiss painted from the left instead -
   touching the vertical rule and stacking two and three deep. A definite width keeps the track
   real, and the padding is the gap the chip and buttons need off the rule. */
.agenda-card {
  display: grid; grid-template-columns: 140px minmax(0, 1fr) minmax(180px, max-content); gap: 18px;
  align-items: start;
  padding: 14px 16px 14px 14px; border-bottom: 1px solid var(--rule);
  animation: rise 0.4s var(--ease) both;
}
.agenda-card.is-cancelled { opacity: 0.55; }
.agenda-card.agenda-block { border-left: 3px solid var(--slate); padding-left: 14px; }
.agenda-card.agenda-block.is-proposed { border-left-color: var(--amber); background: rgba(255, 253, 248, 0.6); }
.agenda-card.agenda-block.is-stale { border-left-color: var(--vermilion); }
.agenda-when { font-family: var(--font-mono); font-size: 12px; color: var(--ink-2); padding-top: 3px; display: grid; gap: 1px; }
.agenda-muted { color: var(--ink-3); }
.agenda-title { font-family: var(--font-display); font-size: 17px; font-weight: 500; margin: 0 0 3px; line-height: 1.25; }
.agenda-meta { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; font-size: 13px; color: var(--ink-2); }
.agenda-side { display: grid; gap: 8px; justify-items: end; }
.agenda-rsvp { display: flex; gap: 6px; margin-top: 8px; }
.agenda-foot { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
.block-status {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase;
  padding: 2px 8px; border-radius: 999px; border: 1px solid var(--rule); color: var(--ink-3);
}
.block-status.block-proposed { background: var(--amber-soft); color: #9a5f12; border-color: transparent; }
.block-status.block-booked { background: var(--moss-soft); color: var(--moss); border-color: transparent; }
.block-status.block-stale { background: var(--vermilion-soft); color: var(--vermilion); border-color: transparent; }
.block-status.block-cancelled { background: var(--paper-3); color: var(--ink-3); border-color: transparent; }
/* Small status pill on Today's action cards ("booked 14:00" / "proposed 09:30") — links to Schedule. */
.block-chip {
  align-self: center; font-family: var(--font-mono); font-size: 11px; text-decoration: none; white-space: nowrap;
  padding: 3px 8px; border-radius: 999px; border: 1px solid var(--rule); color: var(--ink-3);
}
.block-chip.block-proposed { background: var(--amber-soft); color: #9a5f12; border-color: transparent; }
.block-chip.block-booked { background: var(--moss-soft); color: var(--moss); border-color: transparent; }
.block-chip.block-stale { background: var(--vermilion-soft); color: var(--vermilion); border-color: transparent; }
/* A booked block the user (or the auto-complete sweep) marked finished: the chip dims and the
   agenda card behind it shows its Undo control. */
.block-chip.is-completed { opacity: 0.55; text-decoration: line-through; }
.agenda-freeslots { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; padding: 12px 0 4px; font-size: 13px; }
.free-chip {
  font-family: var(--font-mono); font-size: 11px; padding: 2px 8px; border-radius: 999px;
  background: var(--slate-soft); color: var(--slate);
}
.slot-chips { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; margin-top: 10px; font-size: 13px; }
#schedule-toolbar .segmented { flex: 0 0 auto; }
.field-label { display: grid; gap: 4px; font-size: 13px; color: var(--ink-2); margin-bottom: 10px; }
.field-check { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--ink-2); margin-bottom: 10px; }
.field-check input { width: auto; }

/* ---------- Calendar: an openable event ----------
   A mirrored meeting now opens the way Outlook opens one, so the agenda card has to look
   openable: the cursor and the hover lift are what tell a user that clicking the row does
   something before they click it. */
.agenda-card.is-clickable { cursor: pointer; }
.agenda-card.is-clickable:hover { background: #fffdf8; box-shadow: var(--shadow); }
.agenda-card.is-clickable:focus-visible { outline: 2px solid var(--slate); outline-offset: -2px; }
.month-item:not(.is-block) { cursor: pointer; }
.month-item:not(.is-block):hover { text-decoration: underline; }

/* min()/vw, not a fixed px: the body is somebody else's Word document, and the complaint this
   answers is "there's a horizontal scrollbar inside the popup". Give the width to the dialog and
   it is one familiar scroll; keep it at 660px and a wide invite forces an inner one. */
.rename-dialog.event-dialog { width: min(820px, 100vw - 40px); }
.event-when { font-family: var(--font-mono); font-size: 12px; margin: -10px 0 14px; }
/* No max-height/overflow of its own - the dialog scrolls (see .rename-dialog), and a second
   scroller nested inside it is what made the body hard to reach. min-width: 0 keeps a wide body
   table from pushing this grid open, which is how the old inner scrollbar was born. */
.event-body { display: grid; gap: 12px; min-width: 0; flex: 1; }
.event-field { display: grid; gap: 2px; font-size: 14px; margin: 0; }
.event-field-label {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink-3);
}

/* Attendees as chips, not rows. One person per line meant a nine-person meeting pushed the body
   off the fold and made the dialog look like a mailing list; a wrapping row of names is a third
   the height, and the wrap happens at the edge of the line rather than at a fixed column count. */
.event-attendees { display: grid; gap: 2px; min-width: 0; }
.event-attendee-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 5px; min-width: 0; }
.event-attendee-chip {
  display: inline-flex; align-items: center; gap: 6px; max-width: 100%; font-size: 13px;
  padding: 3px 10px; border: 1px solid var(--rule); border-radius: 999px; background: var(--paper-2);
}
.event-attendee-chip.is-me { border-color: var(--slate); background: var(--slate-soft); }
.event-attendee-chip.is-declined { border-color: var(--vermilion-soft); }
/* The collapsed view is names only. Truncated, because the chip row has to wrap on a name and not
   on "Christopher Frederiksen-Smith". */
.event-attendee-chip-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* The expand control is a button, not a click-anywhere row: it is the only thing in the dialog
   that changes what you are looking at, so it should look like one. */
.event-attendee-toggle {
  align-self: start; margin-top: 7px; background: none; border: 0; padding: 0; cursor: pointer;
  font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--slate); border-bottom: 1px solid var(--rule);
}
.event-attendee-toggle:hover { color: var(--ink); }

/* The status table, hidden until asked for. */
.event-attendee-detail { margin: 0; }
.event-attendee-detail[hidden] { display: none; }
.event-attendee {
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto; gap: 4px 10px; align-items: baseline;
  padding: 5px 0; border-bottom: 1px solid var(--rule); font-size: 14px;
}
.event-attendee-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.event-attendee-email { grid-column: 1 / -1; font-size: 12px; }
.attendee-status {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase;
  padding: 2px 8px; border-radius: 999px; background: var(--paper-3); color: var(--ink-3);
}
.attendee-status.is-accepted { background: var(--moss-soft); color: var(--moss); }
.attendee-status.is-tentativelyAccepted { background: var(--amber-soft); color: #9a5f12; }
.attendee-status.is-declined { background: var(--vermilion-soft); color: var(--vermilion); }
.attendee-status.is-organizer { background: var(--slate-soft); color: var(--slate); }
.event-not-mirrored {
  font-size: 13px; color: #9a5f12; background: var(--amber-soft); padding: 9px 11px;
  border-radius: var(--radius); margin: 4px 0 0;
}
/* Somebody else's meeting notes, sanitised on write. Constrained rather than trusted: no markup
   from a calendar invite gets to decide how wide this dialog is or what it overlays. The width
   rules are what stop a Word-generated table (Outlook writes fixed cell widths in points) from
   becoming a horizontal scrollbar inside the body box. */
.event-body-html {
  border: 1px solid var(--rule); border-radius: var(--radius); padding: 12px 14px;
  font-size: 14px; line-height: 1.5; background: var(--paper-2); overflow-wrap: break-word;
  min-width: 0; max-width: 100%;
}
.event-body-html img { max-width: 100%; height: auto; }
.event-body-html table { max-width: 100%; table-layout: fixed; }
.event-body-html :is(td, th) { overflow-wrap: break-word; word-break: break-word; }
.event-body-html :is(h1, h2, h3, h4) { font-size: 15px; margin: 0.6em 0 0.3em; }
.event-body-html a { color: var(--slate); text-decoration: underline; }
/* Word/Outlook heads are stripped by the sanitizer; a stray one still must not dictate layout. */
.event-body-html :is(html, body, head) { display: contents; }

/* ---------- Calendar: attendee picker ---------- */
.attendee-field { position: relative; margin-bottom: 10px; }
.attendee-chips { display: flex; gap: 6px; flex-wrap: wrap; }
.attendee-chips:empty { display: none; }
.attendee-chip {
  display: inline-flex; align-items: center; gap: 6px; font-size: 13px; padding: 3px 6px 3px 10px;
  border-radius: 999px; background: var(--slate-soft); color: var(--slate); max-width: 100%;
}
.attendee-chip > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chip-x {
  border: 0; background: transparent; color: inherit; cursor: pointer; font-size: 14px;
  line-height: 1; padding: 2px 4px; border-radius: 999px;
}
.chip-x:hover { background: rgba(31, 29, 26, 0.12); }
.attendee-results {
  position: absolute; z-index: 30; left: 0; right: 0; top: calc(100% - 6px);
  background: #fffdf8; border: 1px solid var(--rule); border-radius: var(--radius);
  box-shadow: var(--shadow); overflow: hidden; display: grid;
}
.attendee-option {
  display: grid; grid-template-columns: minmax(0, auto) minmax(0, 1fr) auto; gap: 8px; align-items: baseline;
  text-align: left; border: 0; background: transparent; padding: 8px 12px; cursor: pointer;
  border-bottom: 1px solid var(--rule); font-size: 14px; color: var(--ink);
}
.attendee-option:last-child { border-bottom: 0; }
.attendee-option:hover, .attendee-option.is-cursor { background: var(--paper-2); }
.attendee-option-name { font-weight: 500; }
.attendee-option-email, .attendee-option-src { font-size: 12px; }
.attendee-option-src { font-family: var(--font-mono); font-size: 10px; text-transform: uppercase; color: var(--ink-3); }
.attendee-empty { padding: 9px 12px; margin: 0; font-size: 13px; }
.teams-check { width: auto; }

/* ---------- Schedule: week overlay ----------
   The week borrows the month cell's whole visual language (same paper, same mono day
   number, same item ellipsis) and differs only in geometry: seven columns, taller cells,
   so the titles that the month has to truncate can actually be read. */
.week-wrap { display: grid; gap: 12px; }
.week-head { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.week-title { font-size: 22px; margin: 0; min-width: 260px; text-align: center; }
/* Same minmax(0, ...) reason as .month-grid: seven equal columns, never one column widened by
   an unbreakable title. Fixed height so all seven cells are the same height. */
.week-grid {
  display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 6px;
  grid-auto-rows: var(--week-cell-h);
}
.week-cell {
  display: flex; flex-direction: column; gap: 3px; align-items: stretch; text-align: left; cursor: pointer;
  /* Height from the grid's rows (see .week-grid); no overflow:hidden, so nothing inside the
     cell is clipped away from view. */
  min-height: 0; padding: 6px 8px; background: var(--paper-2); border: 1px solid var(--rule);
  border-radius: var(--radius); font: inherit; color: inherit; transition: border-color 0.2s var(--ease);
}
.week-cell > * { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.week-cell:hover { border-color: var(--ink-3); }
.week-cell.is-today { border: 1.5px solid var(--ink); }
.week-cell.is-selected { box-shadow: inset 0 0 0 1.5px var(--amber); }
.week-daynum { font-family: var(--font-mono); font-size: 12px; color: var(--ink-2); }
.week-cell.is-today .week-daynum { color: var(--ink); font-weight: 700; }
.week-more { font-family: var(--font-mono); font-size: 10px; color: var(--ink-3); }

/* ---------- Schedule: month overlay ---------- */
.month-wrap { display: grid; gap: 12px; }
.month-head { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.month-title { font-size: 22px; margin: 0; min-width: 200px; text-align: center; }
/* The month's key and its two click affordances, kept in the header instead of a paragraph under
   the grid where they read as a caption nobody re-reads. The title keeps its centre with the key
   beside it; the hint is pushed right by auto margin, and it is what drops out on a phone - once
   the cells are small the tap-any-day gesture needs no explaining, and the row number is
   discoverable by tapping it. */
.month-legend {
  display: flex; align-items: center; gap: 12px; margin: 0;
  font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--ink-3); white-space: nowrap;
}
.legend-key { display: inline-flex; align-items: center; gap: 5px; }
.legend-mark { color: var(--ink-2); font-size: 11px; line-height: 1; }
.legend-mark.is-block { color: var(--slate); }
.month-hint { font-size: 12px; margin: 0 0 0 auto; white-space: nowrap; }
/* Nine explicit tracks: a 34px gutter for the week number, an empty spacer the width of one
   gap, then the seven days at equal width. minmax(0, ...) rather than the default
   minmax(auto, 1fr) is what makes the seven days uniform: a track's floor is its content's
   min-content width, so a single long unbreakable word (a hyphenated "Project-Standup", or the
   nowrap'd start time) would otherwise push that column wider than its six neighbours - 1fr is
   a maximum, not a limit. Zero floors every track equally. Fixed row height so rows match as
   well as columns.
   Both rows fill nine cells: the header carries an empty span where the week number goes, and
   each week number is followed by an empty span where the spacer goes. Anything less and
   auto-placement wraps the row early - Saturday lands on track 1 and the seventh day is
   measured as an 18px sliver, which is the bug this grid has now had twice. So placement is
   never left to auto: every cell below names its track, and a test walks the rows in source
   order to prove each row really is nine cells. */
.month-grid {
  display: grid;
  grid-template-columns: var(--month-gutter) var(--month-gutter-gap) repeat(7, minmax(0, 1fr));
  column-gap: var(--month-gutter-gap);
  grid-auto-rows: var(--month-cell-h);
}
/* The header is its own grid item, laying out on a copy of the day tracks via subgrid. That is
   not cosmetic: nth-of-type counts element types among siblings, and the day cells are buttons
   exactly like the week number. Keeping the seven weekday names in a container of their own
   means no header span can ever join a day cell's type count and skew the column arithmetic.
   Every cell - header name or day - names its own line rather than being auto-placed.
   Auto-placement is what broke this grid twice: a floated label eating the gutter track, then a
   short row wrapping Saturday back onto track 1. Spans are no better - see the subgrid note.
   Line map: 1 gutter | 2 spacer | 3..9 the seven days. */
.month-head-row {
  display: grid; align-items: center; grid-column: 1 / -1;
  grid-template-columns: var(--month-gutter) var(--month-gutter-gap) repeat(7, minmax(0, 1fr));
}
/* Where subgrid is available the header borrows the parent's real tracks, so a name sits on the
   identical track - and identical rounding - as the day beneath it. Each name still names its
   own line: subgrid supplies the tracks, the per-name lines say which one. */
.month-dow {
  font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--ink-3); padding: 2px 4px; min-width: 0; overflow: hidden;
  grid-column: 3;
}
.month-head-row .month-dow:nth-of-type(2) { grid-column: 4; }
.month-head-row .month-dow:nth-of-type(3) { grid-column: 5; }
.month-head-row .month-dow:nth-of-type(4) { grid-column: 6; }
.month-head-row .month-dow:nth-of-type(5) { grid-column: 7; }
.month-head-row .month-dow:nth-of-type(6) { grid-column: 8; }
.month-head-row .month-dow:nth-of-type(7) { grid-column: 9; }
@supports (grid-template-columns: subgrid) {
  .month-head-row { grid-template-columns: subgrid; }
}
.month-cell { grid-column: 3; }
/* The week number and the gutter spacer are spans, so nth-of-type here counts only the button
   day cells - exactly the seven-per-row rhythm these rules assume. */
.month-cell:nth-of-type(7n+2) { grid-column: 4; }
.month-cell:nth-of-type(7n+3) { grid-column: 5; }
.month-cell:nth-of-type(7n+4) { grid-column: 6; }
.month-cell:nth-of-type(7n+5) { grid-column: 7; }
.month-cell:nth-of-type(7n+6) { grid-column: 8; }
.month-cell:nth-of-type(7n+0) { grid-column: 9; }
/* The row's title, in its own gutter lane - never carved out of a day column, and never floated
   (a floated label becomes grid content in the gutter track and shoves every day right). */
.weeknum-label {
  grid-column: 1;
  display: flex; align-items: center; justify-content: center; min-width: 0; padding: 1px 2px;
  font-family: var(--font-mono); font-size: 10px; color: var(--ink-3);
  background: none; border: 1px solid transparent; border-radius: var(--radius); cursor: pointer;
}
.weeknum-label:hover { color: var(--ink); border-color: var(--rule); }
.weeknum-spacer { grid-column: 2; }
/* No margin on the day cells: the spacer track is what keeps Sunday off the gutter, so Sunday
   is exactly one 1fr track wide like the other six. */
.month-cell {
  display: flex; flex-direction: column; gap: 3px; align-items: stretch; text-align: left; cursor: pointer;
  /* Height comes from the grid's rows; no overflow:hidden here, because the row-start cell
     holds a focusable nested control and a clipped box would cut its focus ring off. Long
     titles are handled by the ellipsis on each child instead. */
  min-height: 0; padding: 6px 8px; background: var(--paper-2); border: 1px solid var(--rule);
  border-radius: var(--radius); font: inherit; color: inherit; transition: border-color 0.2s var(--ease);
}
.month-cell > * { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.month-cell:hover { border-color: var(--ink-3); }
.month-cell.is-out { opacity: 0.4; }
.month-cell.is-today { border: 1.5px solid var(--ink); }
.month-cell.is-selected { box-shadow: inset 0 0 0 1.5px var(--amber); }
.month-daynum { font-family: var(--font-mono); font-size: 12px; color: var(--ink-2); }
.month-cell.is-today .month-daynum { color: var(--ink); font-weight: 700; }
.month-item {
  /* Times lead every item (see monthCell/weekCell); each must sit whole on one line, so the
     ellipsis cuts the title and the time stays readable - never wrap a bare time onto its own. */
  font-size: 11px; line-height: 1.35; color: var(--ink-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.month-item.is-block { color: var(--slate); }
.month-item.is-cancelled { text-decoration: line-through; color: var(--ink-3); }
.month-more { font-family: var(--font-mono); font-size: 10px; color: var(--ink-3); }

/* ---------- Drawer ---------- */
.drawer-backdrop { position: fixed; inset: 0; background: rgba(31, 29, 26, 0.35); z-index: 40; animation: fade 0.25s both; }
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }
.drawer {
  position: fixed; top: 0; right: 0; bottom: 0; width: min(680px, 100vw); z-index: 50;
  background: var(--paper); border-left: 1px solid var(--rule); box-shadow: -30px 0 60px -30px rgba(31,29,26,0.5);
  transform: translateX(100%); transition: transform 0.4s var(--ease); display: flex; flex-direction: column;
}
.drawer.is-open { transform: none; }
.drawer-head { display: flex; justify-content: space-between; gap: 16px; padding: 24px 28px 18px; border-bottom: 2px solid var(--ink); }
.drawer-head h2 { font-size: 24px; line-height: 1.2; }
.drawer-from { margin: 6px 0 0; font-size: 13px; color: var(--ink-2); }
.drawer-body { overflow-y: auto; padding: 8px 28px 40px; }
.drawer-section { padding: 20px 0; border-bottom: 1px solid var(--rule); }
.drawer-section h3 { margin-bottom: 10px; }
.drawer-summary { font-family: var(--font-display); font-size: 18px; margin: 0 0 6px; }
.drawer-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 14px; }
.email-body { white-space: pre-wrap; word-break: break-word; font-family: var(--font-body); font-size: 14px; line-height: 1.6; color: var(--ink-2); margin: 0; background: #fffdf8; border: 1px solid var(--rule); padding: 16px; border-radius: var(--radius); max-height: 50vh; overflow: auto; }
/* .drawer-draft itself and the compose panel are styled up in the drawer-draft block near the
   compose styles; the old plain-text <pre> rule died with the text-blob rendering. */
.drawer-draft .draft-body { max-height: 40vh; overflow-y: auto; }

/* ---------- Responsive ---------- */
@media (max-width: 980px) {
  .login-layout { grid-template-columns: 1fr; gap: 28px; align-items: start; }
  .today-grid { grid-template-columns: 1fr; }
  .stat-strip { grid-template-columns: repeat(3, 1fr); }
  .stat:nth-child(3n) { border-right: 0; }
  .topbar { grid-template-columns: 1fr auto; }
  .topbar-nav { grid-column: 1 / -1; justify-content: flex-start; overflow-x: auto; }
  .brief-header { grid-template-columns: 1fr; }
  .brief-actions { flex-direction: row; flex-wrap: wrap; }
  /* Two month lines need the month's name, the arrows, and the dot key; the click sentence is
     the fourth thing competing for that row. Its auto margin is what would otherwise drop it
     alone onto a line under the arrows - the under-grid caption this moved off in the first
     place - so it stops here rather than at the phone breakpoint. */
  .month-hint { display: none; }
  .month-legend { margin-left: auto; }
}
@media (max-width: 600px) {
  .email-row { grid-template-columns: 1fr; gap: 6px; }
  .email-tags { justify-content: flex-start; padding-right: 0; }
  .stat-strip { grid-template-columns: repeat(2, 1fr); }
  .inline-form { grid-template-columns: 1fr; }
  .toolbar { flex-wrap: wrap; }
  .toolbar input { width: 100%; }
  .month-legend { margin-left: auto; }
  /* The week's row is arrows + a long title ("Week 39 · 20 Sep – 26 Sep"), which leaves no room for
     the key beside them; taking its own centred line matches what the month does one line below. */
  .week-head .month-legend { order: 3; width: 100%; margin-left: 0; justify-content: center; gap: 10px; }
  /* Phones keep the seven-column month (it is a survey, not a reader) but shrink the gutter to
     the bare number's own lane. Heights relax to auto so a tall week's rows are not clipped
     where the screen is shortest. */
  :root { --month-gutter: 22px; --month-gutter-gap: 4px; --month-cell-h: 60px; }
  .month-cell { padding: 4px 5px; }
  /* A phone header cannot hold the month title *and* a key, so the key takes a line of its own
     under the month - centred, rather than squeezing the arrows off the month's centre. */
  .month-legend { order: 3; width: 100%; margin-left: 0; justify-content: center; gap: 10px; }
  /* Phones lose the titles but must not lose the *times* - "when am I busy" is the one thing
     worth reading from a month, and it survives here as the marker (● meeting, ◆ block). */
  .month-item { font-size: 0; }
  .month-item::before { content: attr(data-mark); font-size: 11px; }
  /* Seven columns is unreadable on a phone: the week collapses to one day per row, which
     keeps every title the desktop week shows - there is simply no room to be a grid here. */
  .week-grid { grid-template-columns: 1fr; }
  .week-cell { min-height: 0; }
  .week-title { min-width: 0; flex: 1; }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* --- Settings tab (reply style, font, timezone) -------------------------------- */
/* Each preference is its own editorial card - paper panel, hairline rule, the soft ink shadow the
   rest of the app carries - with a mono index numeral and an underlined heading. The cards sit in a
   two-up grid at equal (half) width and auto-place left-to-right, so Reply style and Timezone share
   the top row and Reply font starts the next. Collapses to a single column on a narrow window. */
/* The display must ride on .is-active, not the bare id: an id selector (specificity 1,0,0)
   outranks the generic ".view { display: none }" (0,1,0), so a bare "#view-settings { display:
   grid }" would beat the hide and leave these cards laid out - and visibly painted - at the bottom
   of every other view. Everything else here (tracks, placement) is display-independent and can
   safely live on the id. */
#view-settings.is-active { display: grid; }
/* Three rows: the header owns row 1 (its natural height, so cards can never float above it), the
   two card rows are row 2 (top) and row 3 (bottom). The action bar auto-places after the cards. */
#view-settings {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-template-rows: auto 1fr 1fr;
  gap: 24px 28px;
  align-items: start;
}
#view-settings > .view-head { grid-column: 1 / -1; grid-row: 1; }
#view-settings > .settings-actions { grid-column: 1 / -1; }
/* Reply style is the tall lede card, so it holds the whole left column (spanning both card rows);
   Timezone tops the right column and Reply font stacks directly beneath it there. Explicit column
   + row placement (never row 1, which is the header) means DOM order can't shove a card above the
   header. align-items: start keeps each card its own height. Collapses to one column below.
   The Planning card (04, added later) is deliberately unpinned: the auto-placement puts it in the
   left column beside Reply font's bottom row, which is where its (short) content wants to sit. */
#view-settings > .settings-group { min-width: 0; }
#view-settings > .settings-group:nth-of-type(1) { grid-column: 1; grid-row: 2 / 5; }
#view-settings > .settings-group:nth-of-type(2) { grid-column: 2; grid-row: 2; }
#view-settings > .settings-group:nth-of-type(3) { grid-column: 2; grid-row: 3; }
#view-settings > .settings-group:nth-of-type(4) { grid-column: 1; grid-row: 4; }
.settings-group {
  background: var(--paper); border: 1px solid var(--rule); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 22px 24px 24px;
}
/* Numbered, editorial section head: a mono index beside the display title, underlined like the
   column heads elsewhere in the app, with a short lede beneath. */
.settings-group-head {
  display: flex; align-items: baseline; gap: 12px; padding-bottom: 12px; margin-bottom: 16px;
  border-bottom: 2px solid var(--ink);
}
.settings-index {
  font-family: var(--font-mono); font-size: 12px; color: var(--vermilion);
  letter-spacing: 0.06em; flex: 0 0 auto;
}
.settings-group-head h2 { font-size: 19px; line-height: 1.1; }
/* The head owns the rule and the space below it, so the lede sits close beneath without a negative
   margin (which would misplace it if the head were ever absent). */
.settings-group-head + .settings-lede { margin-top: 0; }
.settings-lede { font-size: 13px; color: var(--ink-3); line-height: 1.6; margin: 0 0 18px; }
.settings-lede code { font-family: var(--font-mono); font-size: 12px; }
.settings-group .field:last-child { margin-bottom: 0; }
/* A .field is a grid, so each child is a stretched grid item - which would pull the segmented pill
   to the full card width. Keep it hugging its two labels on its own row instead. */
.settings-group .field .segmented { justify-self: start; }
.settings-actions { display: flex; align-items: center; gap: 14px; margin-top: 4px; }
.settings-actions .draft-error { flex: 1; margin: 0; }
@media (max-width: 720px) {
  /* Single column: drop the explicit tracks and placement so header, the three cards, and the
     action bar stack top to bottom in DOM order. */
  #view-settings { grid-template-columns: 1fr; grid-template-rows: none; }
  #view-settings > .view-head,
  #view-settings > .settings-group,
  #view-settings > .settings-actions { grid-column: 1; grid-row: auto; }
}

/* --- Draft recipients (To / Cc / Bcc) ----------------------------------------- */
.draft-recipients {
  display: grid; gap: 8px; padding: 12px 20px; border-bottom: 1px solid var(--rule);
  background: var(--paper-2, #f7f2e8);
}
/* Collapsed (the default): only the summary row shows. The editor keeps its full contents in the
   DOM so nothing is lost, it simply does not take vertical space until asked for. */
.draft-recipients.is-collapsed .rcpt-body { display: none; }
.draft-recipients .rcpt-summary-row { display: flex; }
.draft-recipients .rcpt-toggle {
  display: flex; align-items: center; gap: 8px; width: 100%; text-align: left;
  border: 0; background: transparent; cursor: pointer; padding: 2px 0; color: var(--ink-2);
  font-size: 12.5px;
}
.draft-recipients .rcpt-caret {
  flex: 0 0 auto; font-size: 10px; color: var(--ink-3); transition: transform 0.12s ease;
}
.draft-recipients:not(.is-collapsed) .rcpt-caret { transform: rotate(90deg); }
.draft-recipients .rcpt-summary {
  color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.draft-recipients .rcpt-summary-row:hover .rcpt-summary { color: var(--ink); }

.draft-recipients .rcpt-row { display: flex; gap: 8px; align-items: flex-start; }
.draft-recipients .rcpt-label {
  flex: 0 0 44px; font-size: 11px; font-weight: 600; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--ink-3); padding-top: 7px;
}
.draft-recipients .rcpt-chips {
  display: flex; flex-wrap: wrap; gap: 6px; align-items: center; flex: 1;
}
.rcpt-chip {
  display: inline-flex; align-items: center; gap: 6px; border: 1px solid var(--rule);
  border-radius: 999px; padding: 3px 4px 3px 10px; background: #fffdf8; font-size: 12.5px;
}
.rcpt-chip .rcpt-remove {
  border: 0; background: transparent; cursor: pointer; font-size: 14px; line-height: 1;
  color: var(--ink-3); padding: 2px 6px;
}
.rcpt-chip .rcpt-remove:hover { color: var(--crit, #a3320e); }
.rcpt-chip.is-unknown { border-style: dashed; color: var(--ink-3); font-style: italic; }
.rcpt-input {
  flex: 1; min-width: 160px; border: 1px dashed transparent; background: transparent;
  padding: 4px 6px; font-size: 12.5px;
}
.rcpt-input:focus { outline: none; border-color: var(--rule); background: #fff; }
.rcpt-replyall { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--ink-2); }
.rcpt-replyall input { width: auto; }
.rcpt-hint { font-size: 11.5px; color: var(--ink-3); line-height: 1.5; }
