/* Monkey Mail's own rules. Everything structural — masthead, sidebar, landing, cards, badges,
   buttons, tables, forms — comes from brand.css, which is the Wycombe Abbey design system
   vendored unmodified from App-13 Keystone Support. Only add here what that file does not
   already provide, so the two apps keep looking like one system. */

.shell-root { display: flex; flex-direction: column; min-height: 100vh; }

/* brand.css styles `input, textarea, select` as a block with width:100%, padding and a border —
   right for text fields, wrong for checkboxes, which it also catches. Left alone, every checkbox
   is a full-width padded box that pushes its own label across the row. The Support Desk has no
   bare checkboxes to expose it; Monkey Mail's audience picker is nothing but checkboxes.
   Fixed here rather than in brand.css, which stays a verbatim copy. */
input[type="checkbox"],
input[type="radio"] {
  width: auto;
  flex: none;
  padding: 0;
  margin: 0;
  border: none;
  background: none;
  accent-color: var(--navy);
  /* Big enough to hit on a phone without needing a wrapper. */
  inline-size: 17px;
  block-size: 17px;
}

/* Campaign status, on the same solid brand-secondary fills the Support Desk uses for ticket
   status — spotted at a glance down a list rather than read. */
.badge.mm-draft      { background: var(--navy-10); color: var(--navy-50); }
.badge.mm-queued     { background: var(--saffron); color: var(--navy); }
.badge.mm-sending    { background: var(--clementine); color: var(--white); }
.badge.mm-paused     { background: var(--violet); color: var(--white); }
.badge.mm-sent       { background: var(--skye); color: var(--white); }
.badge.mm-failed     { background: var(--scarlett); color: var(--white); }
.badge.mm-cancelled  { background: var(--navy-10); color: var(--navy-50); }
.badge.mm-pending    { background: var(--navy-10); color: var(--navy-50); }
.badge.mm-suppressed { background: var(--rose); color: var(--navy); }
.badge.mm-skipped    { background: var(--navy-10); color: var(--navy-50); }

/* Operational is deliberately loud. It means "no unsubscribe link, the Do Not Contact list does
   not apply" — the composer should never pick it by accident. */
.badge.mm-operational { background: var(--scarlett); color: var(--white); }
.badge.mm-marketing   { background: var(--grey-soft); color: var(--navy-50); }

.notice {
  padding: 11px 14px; border-radius: 6px; margin: 14px 0;
  font-size: calc(14px + var(--font-boost));
}
.notice.warn  { background: var(--saffron-light); border: 1px solid var(--gold); }
.notice.error { background: var(--rose-light); border: 1px solid var(--scarlett); }
.notice.ok    { background: var(--skye-light); border: 1px solid var(--skye); }

.progress { height: 8px; background: var(--navy-10); border-radius: 99px; overflow: hidden; margin: 12px 0; }
.progress > div { height: 100%; background: var(--skye); transition: width .3s var(--ease); }

.hint  { font-size: calc(12px + var(--font-boost)); color: var(--text-muted); margin-top: 5px; }
.muted { color: var(--text-muted); }
.right { text-align: right; }
.stack > * + * { margin-top: 16px; }

/* Multi-select filter pills, matching the Support Desk's filter bar. */
.checks { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.checks label {
  display: flex; align-items: center; gap: 7px; margin: 0; cursor: pointer;
  padding: 6px 13px; border: 1px solid var(--navy-20); border-radius: 99px;
  background: var(--white); font-weight: 400; font-size: calc(13px + var(--font-boost));
}
.checks label.on { background: var(--navy); border-color: var(--navy); color: var(--white); }
.checks input { margin: 0; }

/* Roughly what the recipient sees. Never a substitute for the test send — only a real email
   client is an honest preview — so it is framed as a panel, not presented as the email. */
.preview {
  border: 1px solid var(--border); border-radius: 6px; padding: 18px;
  background: var(--white); max-height: 480px; overflow: auto;
}

.field-row { display: flex; gap: 16px; flex-wrap: wrap; }
.field-row > * { flex: 1; min-width: 220px; }

.actions { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 18px; align-items: center; }

.address-dump {
  max-height: 220px; overflow: auto; margin-top: 10px; padding: 10px;
  background: var(--grey-soft); border-radius: 6px;
  font-size: calc(12px + var(--font-boost)); color: var(--text-muted); word-break: break-all;
}

/* The composer's body field is HTML until the block editor lands in stage 2. */
textarea.html-source {
  min-height: 300px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: calc(12px + var(--font-boost)); line-height: 1.5;
}

.empty { padding: 30px; text-align: center; color: var(--text-muted); }

/* ---- Recipient picker -------------------------------------------------------------------------
   A single column of sixteen year groups wastes most of a laptop screen and all of a 27" one, and
   gives no sense of which half of the school is being addressed. Grouped by division, in a grid
   that takes as many columns as the window allows. */

.scope-buttons { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 14px; }

.audience-summary {
  margin: 0 0 16px; padding: 10px 14px; border-radius: 6px;
  background: var(--grey-soft); font-size: calc(14px + var(--font-boost));
}

.yg-groups { display: flex; flex-direction: column; gap: 20px; }
.yg-group-head { display: flex; align-items: center; gap: 12px; margin-bottom: 8px; }
.yg-group-head .eyebrow { margin: 0; }
.yg-group-head .muted { margin-left: auto; font-size: calc(12px + var(--font-boost)); }
.yg-pick { padding: 3px 10px; font-size: calc(11px + var(--font-boost)); }

.yg-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 10px; }

.yg-card {
  border: 1px solid var(--navy-20); border-radius: 8px; background: var(--white);
  padding: 10px 12px; transition: border-color .12s var(--ease), background .12s var(--ease);
}
.yg-card:hover { border-color: var(--navy-50); }
.yg-card.on { border-color: var(--gold-deep); background: var(--saffron-light); }
/* Some forms picked but not the whole year — visibly different from both states. */
.yg-card.part { border-color: var(--gold-soft); background: #fffdf6; }

.yg-card-head {
  display: flex; align-items: flex-start; gap: 9px; margin: 0; cursor: pointer; font-weight: 400;
}
.yg-card-head input { margin-top: 2px; }
.yg-name { display: block; font-weight: 700; font-size: calc(14px + var(--font-boost)); line-height: 1.25; }
.yg-count { display: block; color: var(--text-muted); font-size: calc(12px + var(--font-boost)); }

.yg-forms { display: flex; flex-wrap: wrap; gap: 5px; margin: 8px 0 0 28px; }
.yg-form {
  display: flex; align-items: center; gap: 5px; margin: 0; cursor: pointer;
  background: var(--grey-soft); padding: 2px 8px; border-radius: 6px;
  font-size: calc(11px + var(--font-boost)); font-weight: 600;
}
.yg-form input { margin: 0; }
.yg-form.on { background: var(--navy); color: var(--white); }
/* A form inside an already-ticked year group is shown ticked but not clickable — the year group
   has already included it, and un-ticking would imply an exclusion the query cannot express. */
.yg-form:has(input:disabled) { opacity: .6; cursor: default; }

/* ---- Block editor -------------------------------------------------------------------------- */

/* Blocks on the left, the real compiled email on the right. .main is flex:1 up to 1800px, so on a
   laptop there is room for both; below that the preview drops underneath rather than squeezing the
   thing being edited. */
.mm-editor { display: grid; grid-template-columns: minmax(0, 1fr) 400px; gap: 20px; align-items: start; }
@media (max-width: 1100px) { .mm-editor { grid-template-columns: minmax(0, 1fr); } }

.mm-editor-preview { position: sticky; top: 12px; }
.mm-preview-head {
  font-size: calc(12px + var(--font-boost)); font-weight: 700; text-transform: uppercase;
  letter-spacing: .4px; color: var(--text-muted); margin-bottom: 8px;
}
.mm-preview-frame {
  width: 100%; height: 640px; border: 1px solid var(--border); border-radius: 6px;
  background: var(--paper);
}

.mm-blocks { display: flex; flex-direction: column; gap: 12px; }
/* NOT overflow:hidden. It was there to clip the header's background to the rounded corners, and it
   silently broke position:sticky for everything inside — an overflow ancestor becomes the sticky
   container, so the formatting bar scrolled away with its own block instead of pinning to the
   viewport. The corners are rounded on the header itself instead. */
.mm-block { border: 1px solid var(--border); border-radius: 6px; background: var(--white); }
.mm-block-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 7px 12px; background: var(--grey-soft); border-bottom: 1px solid var(--border);
  border-radius: 5px 5px 0 0;
}
.mm-block-type {
  font-size: calc(11px + var(--font-boost)); font-weight: 700; text-transform: uppercase;
  letter-spacing: .5px; color: var(--text-muted);
}
.mm-block-tools { display: flex; gap: 4px; }
.mm-icon {
  border: 1px solid var(--navy-20); background: var(--white); border-radius: 5px;
  width: 26px; height: 26px; padding: 0; line-height: 1; cursor: pointer; color: var(--navy);
  font-size: calc(12px + var(--font-boost));
}
.mm-icon:hover:not(:disabled) { background: var(--navy-10); }
.mm-icon:disabled { opacity: .3; cursor: not-allowed; }
.mm-icon.danger:hover:not(:disabled) { background: var(--scarlett); border-color: var(--scarlett); color: var(--white); }
.mm-block-body { padding: 12px 14px; }

.mm-field + .mm-field { margin-top: 10px; }
.mm-field label { margin-top: 0; }
.mm-row { display: flex; gap: 14px; flex-wrap: wrap; align-items: flex-start; margin-top: 10px; }
.mm-row > * { flex: 1; min-width: 180px; }
/* Fields SIDE BY SIDE in a row are still adjacent siblings, so the stacking margin above applied
   between them too and pushed the second one down by 10px — which is what made "Alignment" sit
   lower than "Size". */
.mm-row > .mm-field + .mm-field { margin-top: 0; }

.mm-add-row { display: flex; gap: 7px; flex-wrap: wrap; margin-top: 12px; align-items: center; }
.mm-add { font-size: calc(12px + var(--font-boost)); padding: 6px 12px; }

/* --- rich text --- */
.mm-rte-bar {
  display: flex; gap: 4px; flex-wrap: wrap; padding: 6px; margin-bottom: 8px;
  background: var(--grey-soft); border-radius: 6px;
}
.mm-rte-btn {
  border: 1px solid transparent; background: transparent; border-radius: 4px; cursor: pointer;
  padding: 4px 9px; font-size: calc(13px + var(--font-boost)); color: var(--navy); line-height: 1.2;
}
.mm-rte-btn:hover { background: var(--white); }
.mm-rte-btn.on { background: var(--navy); color: var(--white); }

/* The editing surface itself. Sized and spaced like the compiled email so what is typed already
   looks close to what is sent — the preview beside it is the exact version. */
.mm-rte .tiptap {
  min-height: 90px; padding: 12px 14px; border: 1px solid var(--navy-20); border-radius: 6px;
  background: var(--white); outline: none;
  font-family: Lato, "Helvetica Neue", Helvetica, Arial, sans-serif;
  /* The campaign's OWN base size, set per editor from the theme — not a fixed 16px, and not
     boosted by the A-/A/A+ control.

     Both of those were wrong in the same way. A story card inheriting a 15px base was drawn at
     16px + 2px of boost = 18px, while a text block explicitly set to 16px was drawn at exactly
     16px, so the smaller text looked bigger and the toolbar appeared to be lying. An editing
     surface that misreports relative sizes is worse than one that is simply small.

     The accessibility boost is not lost: it is applied as zoom below, which scales the inline
     px sizes TipTap writes as well as this one, so the proportions survive it. */
  font-size: var(--mm-base-size, 16px);
  zoom: var(--mm-editor-zoom, 1);
  line-height: 1.55; color: var(--navy);
}
.mm-rte .tiptap:focus-within { border-color: var(--gold-deep); }
.mm-rte .tiptap p { margin: 0 0 10px; }
.mm-rte .tiptap p:last-child { margin-bottom: 0; }
.mm-rte .tiptap a { color: var(--indigo); }
.mm-rte .tiptap ul, .mm-rte .tiptap ol { margin: 0 0 10px; padding-left: 22px; }

.mm-columns { display: flex; gap: 14px; flex-wrap: wrap; }
.mm-column { flex: 1; min-width: 200px; }
.mm-subblock { border: 1px solid var(--border); border-radius: 6px; padding: 8px; margin-bottom: 8px; }
.mm-subblock-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; }
.mm-subblock-head .muted { font-size: calc(11px + var(--font-boost)); text-transform: uppercase; letter-spacing: .4px; }
textarea.mm-mini { min-height: 70px; }

/* --- text toolbar: sizing, images, tables --- */

/* brand.css makes every select and input full width, which inside a toolbar means one control per
   line. Same root cause as the checkbox fix above. */
.mm-rte-bar select,
.mm-rte-context input {
  width: auto;
  padding: 3px 8px;
  font-size: calc(12px + var(--font-boost));
  border-radius: 4px;
}
/* width:auto because brand.css makes every select 100% wide, and this one now has to fit
   "16px (default)" and "Mixed" as well as "24px" — a fixed 74px clipped the longest of them. */
.mm-size { width: auto !important; min-width: 74px; }
.mm-size-input { width: 68px !important; }

.mm-sep { width: 1px; align-self: stretch; background: var(--navy-20); margin: 0 3px; }

/* Only appears when the cursor is actually inside an image or a table. */
.mm-rte-context:not(:empty) {
  display: flex; gap: 4px; flex-wrap: wrap; align-items: center;
  padding: 6px; margin: -4px 0 8px; border-radius: 6px;
  background: var(--saffron-light); border: 1px solid var(--gold-soft);
}
.mm-context-label {
  font-size: calc(11px + var(--font-boost)); font-weight: 700; text-transform: uppercase;
  letter-spacing: .5px; color: var(--gold-deep); margin-right: 4px;
}

/* Tables while editing. Styled to look like the compiled email's default so the canvas does not
   promise something the output will not deliver. */
.mm-rte .tiptap table { border-collapse: collapse; width: 100%; margin: 0 0 12px; table-layout: fixed; }
.mm-rte .tiptap th,
.mm-rte .tiptap td {
  border: 1px solid var(--navy-10); padding: 8px 10px; vertical-align: top; position: relative;
}
.mm-rte .tiptap th { background: var(--grey-soft); text-align: left; font-weight: 700; }
.mm-rte .tiptap .selectedCell::after {
  content: ""; position: absolute; inset: 0; background: rgba(222, 172, 53, .22); pointer-events: none;
}
.mm-rte .tiptap .column-resize-handle {
  position: absolute; right: -2px; top: 0; bottom: 0; width: 4px;
  background: var(--gold); cursor: col-resize;
}

.mm-rte .tiptap img { max-width: 100%; height: auto; border-radius: 2px; }
/* ProseMirror's selected-node class — makes it obvious which image the context bar is acting on. */
.mm-rte .tiptap img.ProseMirror-selectednode { outline: 3px solid var(--gold); outline-offset: 2px; }

.mm-theme-bar {
  display: flex; gap: 14px; flex-wrap: wrap; align-items: flex-end;
  padding: 10px 12px; margin-bottom: 12px;
  background: var(--grey-soft); border-radius: 6px;
}
.mm-theme-field label { margin: 0 0 3px; }
.mm-theme-field select { width: auto; min-width: 170px; padding: 5px 9px; }
.mm-theme-note { flex: 1 1 260px; margin: 0; }

/* The preview panel is narrower than the email, so the frame is rendered at TRUE width and scaled
   to fit rather than squeezed — squeezing it would trigger the email's own mobile media query and
   show the phone layout while claiming to be the email. */
.mm-preview-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.mm-preview-modes { display: flex; gap: 4px; }
.mm-preview-mode {
  border: 1px solid var(--navy-20); background: var(--white); border-radius: 4px; cursor: pointer;
  padding: 3px 9px; font-size: calc(11px + var(--font-boost)); font-weight: 600;
  text-transform: none; letter-spacing: 0; color: var(--navy);
}
.mm-preview-mode.on { background: var(--navy); border-color: var(--navy); color: var(--white); }

.mm-preview-stage {
  overflow: hidden; border: 1px solid var(--border); border-radius: 6px; background: var(--paper);
}
.mm-preview-frame {
  border: 0; background: var(--paper); transform-origin: top left; display: block;
}

/* Autosave state, beside the campaign title. Silent autosave is indistinguishable from no
   autosave, which is why this is always visible rather than a toast that disappears. */
.mm-save {
  font-size: calc(12px + var(--font-boost)); font-weight: 600;
  padding: 4px 10px; border-radius: 99px; white-space: nowrap;
}
.mm-save.ok      { background: var(--skye-light); color: var(--skye); }
.mm-save.pending { background: var(--saffron-light); color: var(--gold-deep); }
.mm-save.error   { background: var(--rose-light); color: var(--scarlett); }

/* Merge-field pickers. Nobody should have to remember that the token is {{contact.salutation}}
   and not {{salutation}} — a typo there reaches every inbox as an empty gap. */
.mm-field-picker { width: auto !important; min-width: 96px; padding: 3px 8px; font-size: calc(12px + var(--font-boost)); }
.mm-subject-row { display: flex; gap: 8px; align-items: stretch; }
.mm-subject-row > input { flex: 1; }
.mm-subject-row > select { flex: 0 0 auto; }
.hint code {
  background: var(--grey-soft); padding: 1px 5px; border-radius: 3px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .92em;
}

/* The send confirmation. Deliberately a panel on the page rather than a browser prompt: a prompt
   can be dismissed by accident, and its cancel path used to end the send with no message at all. */
.mm-confirm { border: 2px solid var(--scarlett); margin-top: 16px; }
.mm-confirm h3 { margin-top: 0; }
.mm-confirm-row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-top: 12px; }
.mm-confirm-row label { margin: 0; white-space: nowrap; }
.mm-confirm-problem { color: var(--scarlett); font-weight: 700; margin-top: 10px; }

/* The formatting bar follows you down a long story rather than making you scroll back up to bold
   a word. Offset by the masthead, which is sticky too. Can be switched off — a stuck bar is a
   nuisance on a short block, and on a laptop screen every pinned row costs reading height. */
/* The masthead scrolls away with the page rather than holding 58px of every screen — on a laptop
   that is a whole story card's worth of height, and the crest does not need to be permanently
   visible. brand.css pins it; this unpins it for this app only.

   The formatting bar therefore sticks to the very top, with nothing above it to clear. */
.sticky-header-group { position: static; }

.mm-rte-bar { position: sticky; top: 0; z-index: 4; }
body.mm-no-sticky .mm-rte-bar { position: static; }
.mm-rte-context { position: sticky; top: 44px; z-index: 3; }
body.mm-no-sticky .mm-rte-context { position: static; }

.mm-colour { width: auto !important; min-width: 84px; padding: 3px 8px; font-size: calc(12px + var(--font-boost)); }

.mm-wordcount {
  font-size: calc(11px + var(--font-boost)); color: var(--text-muted);
  text-align: right; margin-top: 5px;
}

/* Quotes and rules, matched to what the compiler emits so the canvas does not promise something
   the email will not deliver. */
.mm-rte .tiptap blockquote {
  margin: 14px 0; padding: 2px 0 2px 16px; border-left: 3px solid var(--gold); font-style: italic;
}
.mm-rte .tiptap hr { border: 0; border-top: 1px solid var(--navy-10); margin: 16px 0; }

/* ---- Wizard ---------------------------------------------------------------------------------- */

.mm-wizard h3 { margin: 14px 0 6px; font-weight: 300; font-size: calc(22px + var(--font-boost)); }
.mm-wizard-bar { height: 4px; background: var(--navy-10); border-radius: 99px; overflow: hidden; margin: 8px 0 4px; }
.mm-wizard-bar > div { height: 100%; background: var(--gold); transition: width .25s var(--ease); }

.mm-choices { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
.mm-choice {
  display: flex; align-items: flex-start; gap: 11px; margin: 0; cursor: pointer; font-weight: 400;
  padding: 12px 14px; border: 1px solid var(--navy-20); border-radius: 8px; background: var(--white);
}
.mm-choice:hover { border-color: var(--navy-50); }
.mm-choice.on { border-color: var(--gold-deep); background: var(--saffron-light); }
.mm-choice input { margin-top: 3px; }
.mm-choice .hint { margin-top: 3px; }
.mm-choice strong { font-size: calc(15px + var(--font-boost)); }

/* The app's own mark. The school crest stays where it is — that is the institution; this is the
   tool. Sized to sit on the baseline of the app title without pushing the masthead taller. */
.mm-mark { height: 1.15em; width: auto; vertical-align: -0.18em; margin-left: 6px; }
.landing-hero-mark { display: block; margin: 0 auto 14px; }

/* Bold has to LOOK bold. brand.css loads Lato at 400/700/900, so the editing canvas asks for the
   real weights rather than letting the browser synthesise a smeared fake one from Regular. */
.mm-rte .tiptap { font-synthesis-weight: none; }
.mm-rte .tiptap strong, .mm-rte .tiptap b { font-weight: 700; }
.mm-rte .tiptap h1, .mm-rte .tiptap h2, .mm-rte .tiptap h3 { font-weight: 700; }
.mm-weight { min-width: 106px; }

/* ---- Collapsible sidebar ---------------------------------------------------------------------
   brand.css hides the hamburger above 900px, where the sidebar is a permanent column rather than
   a drawer. It earns its place there too: collapsed, the menu is a rail of icons and the editor
   gets the 172px back, which on a 13" laptop is most of a story card. */
.masthead .menu-toggle { display: inline-flex; }

.sidebar nav a { display: flex; align-items: center; gap: 9px; }
.nav-icon { flex: 0 0 auto; width: 20px; text-align: center; font-size: 1.05em; }
.nav-text { white-space: nowrap; overflow: hidden; }

body.mm-rail .sidebar { width: 56px; padding-left: 6px; padding-right: 6px; }
body.mm-rail .nav-text,
body.mm-rail .sidebar-section-label { display: none; }
body.mm-rail .sidebar nav a { justify-content: center; padding: 10px 0; }
/* Without this the divider is the only thing left in a rail with no labels, and reads as a fault. */
body.mm-rail .sidebar-divider { margin: 8px 4px; }

.sidebar { transition: width .18s var(--ease); }

/* Under 900px the sidebar is an overlay drawer and the button opens it, so the rail must not
   apply — a 56px drawer would be absurd. */
@media (max-width: 900px) {
  body.mm-rail .sidebar { width: 172px; padding-left: 10px; padding-right: 10px; }
  body.mm-rail .nav-text, body.mm-rail .sidebar-section-label { display: revert; }
  body.mm-rail .sidebar nav a { justify-content: flex-start; padding: 8px 10px; }
}

/* On a narrow screen the subject and its field picker cannot share a line — the picker's minimum
   width squeezed the input down to a single visible character. */
@media (max-width: 700px) {
  .mm-subject-row { flex-wrap: wrap; }
  .mm-subject-row > input { flex: 1 1 100%; }
  .mm-subject-row > select, .mm-subject-row > button { flex: 1 1 auto; }
  .mm-theme-bar { gap: 10px; }
  .mm-theme-field select { min-width: 0; width: 100%; }
}

/* Proof that a picture is actually in there. Without it the only evidence is the word "Replace"
   on a button, and identifying WHICH picture means reading the preview and working backwards. */
.mm-thumb-link { display: block; flex: 0 0 auto; line-height: 0; }
.mm-thumb {
  height: 128px; width: auto; max-width: 260px; object-fit: cover;
  border: 1px solid var(--navy-20); border-radius: 6px; background: var(--grey-soft);
  display: block;
}
.mm-thumb-link:hover .mm-thumb { border-color: var(--gold-deep); }
.mm-thumb-missing {
  width: 200px; height: 128px; display: flex; align-items: center; justify-content: center;
  font-size: calc(12px + var(--font-boost)); color: var(--scarlett);
  border-style: dashed; border-color: var(--scarlett);
}
/* The row wraps rather than squeezing the picture when the buttons do not fit beside it. */
.mm-add-row:has(.mm-thumb-link) { align-items: flex-start; }

/* ---- Full-screen preview ----------------------------------------------------------------------
   The side panel is about 400px of a laptop screen — fine for glancing at while writing, useless
   for deciding whether the email actually looks right. Same compiled HTML, whole screen, nothing
   else on it. */
.mm-full {
  position: fixed; inset: 0; z-index: 200; background: var(--navy);
  display: flex; flex-direction: column;
}
.mm-full-bar {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 10px 16px; background: var(--navy-90); color: var(--white);
  border-bottom: 1px solid var(--navy-70);
}
.mm-full-bar strong { font-size: calc(14px + var(--font-boost)); letter-spacing: .3px; }
.mm-full-bar .spacer { flex: 1; }
.mm-full-sizes { display: flex; gap: 6px; }
.mm-full-sizes .btn { padding: 5px 12px; font-size: calc(12px + var(--font-boost)); }
.mm-full-sizes .btn.on { background: var(--gold); border-color: var(--gold); color: var(--navy); }

/* Scrolls on its own, so the whole email is reachable however long it is. */
.mm-full-stage { flex: 1; overflow: auto; display: flex; justify-content: center; padding: 20px 12px 40px; }
.mm-full-frame {
  border: 0; background: var(--paper); height: 100%; min-height: 100%;
  box-shadow: 0 10px 40px rgba(0, 0, 0, .45); border-radius: 4px;
}
.mm-preview-full { white-space: nowrap; }

/* ---- Events list ------------------------------------------------------------------------------ */
.mm-events { display: flex; flex-direction: column; gap: 10px; margin-top: 4px; }
.mm-event {
  border: 1px solid var(--border); border-radius: 6px; padding: 10px 12px; background: var(--paper);
}
.mm-event-row { display: flex; gap: 12px; align-items: flex-end; flex-wrap: wrap; }
.mm-event-when { flex: 1 1 140px; }
.mm-event-when label { margin: 0 0 3px; }
.mm-event-tools { display: flex; gap: 4px; margin-left: auto; padding-bottom: 2px; }
.mm-event label { margin-top: 8px; }

.mm-header-opts { flex: 1 1 100%; border-top: 1px solid var(--navy-20); padding-top: 10px; margin-top: 4px; }
.mm-header-opts > div { margin-top: 4px; }
/* Two columns of switches rather than one tall column — four of these read as a 2x2 block.
   auto-fit was tried and gave three columns on a wide screen, which puts the fourth switch on a
   row of its own. Below 560px they stack, where two columns would wrap every label anyway. */
.mm-opt-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 2px 18px; }
.mm-opt-grid > div { margin-top: 0; }
@media (max-width: 560px) { .mm-opt-grid { grid-template-columns: 1fr; } }

/* ---- The three sections of a campaign ----------------------------------------------------------
   Settings, writing, and choosing who gets it are three distinct jobs. As a run of identical white
   cards they read as one long form with no landmarks; tinted and numbered, the eye can find its
   place after scrolling. Tints are deliberately near-white — enough to separate, not enough to
   compete with the content sitting on them. */

.mm-section {
  border: 1px solid var(--border); border-radius: 10px;
  padding: 18px 20px; margin-bottom: 20px;
}
.mm-section-setup   { background: #fbf8f2; border-color: #ece4d6; }
.mm-section-content { background: #f6f8fc; border-color: #dde5f0; }
.mm-section-audience{ background: #f5f9f3; border-color: #dbe7d7; }
.mm-section-review  { background: var(--white); border-color: var(--gold); border-width: 2px; }

.mm-section-head { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 16px; }
.mm-section-num {
  flex: 0 0 auto; width: 27px; height: 27px; border-radius: 50%;
  background: var(--navy); color: var(--white);
  display: flex; align-items: center; justify-content: center;
  font-size: calc(13px + var(--font-boost)); font-weight: 700;
}
.mm-section-title {
  margin: 0; font-size: calc(18px + var(--font-boost)); font-weight: 700;
  letter-spacing: .01em; line-height: 1.2;
}
.mm-section-head .hint { margin-top: 2px; }

/* Cards and inputs sitting on a tint stay white, so fields still read as fields. */
.mm-section .card { background: var(--white); }
.mm-section input, .mm-section select, .mm-section textarea { background: var(--white); }

/* Block cards, tinted by what they are ---------------------------------------------------------
   A newsletter under construction is a column of a dozen near-identical grey cards, and finding
   the one story card among nine text blocks meant reading every header. The tints come from the
   brand's own pastel set — the same values brand.css uses for notices — so the palette stays the
   school's rather than a set of colours invented here. Each pairs a pastel head with a stronger
   version of the same hue for the label and the left edge, which is what carries the distinction
   for anyone who cannot separate the pastels themselves. */
.mm-block-head { border-left: 3px solid var(--navy-20); }
.mm-block-heading  .mm-block-head { background: var(--saffron-light);  border-left-color: var(--gold); }
.mm-block-text     .mm-block-head { background: var(--grey-soft);      border-left-color: var(--navy-50); }
.mm-block-image    .mm-block-head { background: var(--info-blue-light); border-left-color: var(--info-blue); }
.mm-block-card     .mm-block-head { background: var(--lilac-light);    border-left-color: var(--violet); }
.mm-block-events   .mm-block-head { background: var(--skye-light);     border-left-color: var(--skye); }
.mm-block-button   .mm-block-head { background: var(--rose-light);     border-left-color: var(--sienna); }
.mm-block-columns  .mm-block-head { background: var(--pink-light);     border-left-color: var(--ruby); }
.mm-block-html     .mm-block-head { background: var(--grey-warm);      border-left-color: var(--navy-50); }
/* A divider and a spacer are furniture, not content. Left deliberately plain so the eye skips
   them, which is what they are for. */
.mm-block-divider  .mm-block-head,
.mm-block-spacer   .mm-block-head { background: var(--white); border-left-color: var(--navy-20); }

.mm-block-heading .mm-block-type { color: var(--gold-deep); }
.mm-block-image   .mm-block-type { color: #2c5c8a; }
.mm-block-card    .mm-block-type { color: #7d4576; }
.mm-block-events  .mm-block-type { color: #246300; }
.mm-block-button  .mm-block-type { color: var(--sienna); }
.mm-block-columns .mm-block-type { color: #b2416c; }

/* The per-type number. Same size as the label, deliberately lighter: "TEXT 3" should read as one
   thing with an index, not as two words of equal weight. */
.mm-block-n { font-weight: 400; opacity: .75; }

/* Primary actions ------------------------------------------------------------------------------
   brand.css makes .btn navy with white text. On a page of white cards that reads as black — and
   Send, Review recipients and Save all looked like the same heavy slab. Gold with navy text is
   the school's own accent, it is unmistakably a button, and it leaves navy free for the one
   button that should still feel grave. Overridden here rather than in brand.css, which stays a
   verbatim copy of the Support Desk's. */
.btn {
  background: var(--gold);
  color: var(--navy);
  border: 1px solid var(--gold-deep);
}
.btn:hover:not(:disabled) { background: var(--gold-soft); }
.btn.secondary { background: var(--surface); color: var(--text); border: 1px solid var(--border); }
.btn.secondary:hover:not(:disabled) { background: var(--grey-soft); border-color: var(--navy-50); }
/* Kept loud: these two are the irreversible ones. */
.btn.danger  { background: var(--scarlett); border-color: var(--scarlett); color: var(--white); }
.btn.success { background: var(--skye); border-color: var(--skye); color: var(--white); }

/* The whole-school shortcuts, each carrying the number of pupils it covers. The count sits in a
   chip rather than in the label text so it stays legible when the button is the dark "on" state
   and so the three buttons keep the same shape whether the number is 8 or 238. */
.scope-btn { display: inline-flex; align-items: center; gap: 9px; }
.scope-n {
  background: var(--navy); color: var(--white); border-radius: 99px;
  padding: 1px 8px; font-size: calc(11px + var(--font-boost)); font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* Send report and statistics ------------------------------------------------------------------
   Both pages are long, and a long page of identical white cards is one the eye slides off. Each
   block gets a title with a gold rule under it, so scrolling past gives a sense of place. */
.rep-block {
  background: var(--surface); border: 1px solid var(--border); border-radius: 8px;
  padding: 18px 20px; margin-bottom: 16px;
}
.rep-title {
  margin: 0 0 4px; font-size: calc(17px + var(--font-boost)); font-weight: 700; color: var(--navy);
  padding-bottom: 8px; border-bottom: 2px solid var(--gold);
}
.rep-note { margin: 10px 0 14px; max-width: 78ch; }
.rep-block h4 {
  margin: 20px 0 8px; font-size: calc(12px + var(--font-boost)); text-transform: uppercase;
  letter-spacing: .6px; color: var(--text-muted);
}

/* Facts about one thing: a label column that stays narrow and a value column that wraps. Grid
   rather than a table because a table would let one long value widen the labels. */
.rep-facts { display: grid; grid-template-columns: minmax(150px, 210px) 1fr; gap: 1px 20px; margin: 0; }
.rep-facts dt {
  font-size: calc(13px + var(--font-boost)); color: var(--text-muted); padding: 7px 0;
  border-top: 1px solid var(--border);
}
.rep-facts dd {
  margin: 0; padding: 7px 0; border-top: 1px solid var(--border);
  font-size: calc(14px + var(--font-boost)); overflow-wrap: anywhere;
}
.rep-facts dt:first-of-type, .rep-facts dd:first-of-type { border-top: none; }
/* Not known is a real answer and looks like one — never an empty cell, which reads as zero. */
.rep-unknown { color: var(--text-muted); font-style: italic; }

.rep-figures { display: flex; flex-wrap: wrap; gap: 10px; margin: 4px 0 6px; }
.rep-figure {
  flex: 1 1 140px; background: var(--paper); border: 1px solid var(--border);
  border-radius: 8px; padding: 12px 14px; border-top: 3px solid var(--navy-20);
}
.rep-figure.good { border-top-color: var(--skye); }
.rep-figure.bad  { border-top-color: var(--scarlett); }
.rep-figure-n {
  font-size: calc(26px + var(--font-boost)); font-weight: 700; line-height: 1.1;
  color: var(--navy); font-variant-numeric: tabular-nums;
}
.rep-figure-l { font-size: calc(13px + var(--font-boost)); color: var(--text); margin-top: 2px; }
.rep-figure-s { font-size: calc(11px + var(--font-boost)); color: var(--text-muted); margin-top: 3px; }

/* Two columns on a laptop, one on a phone. 420px is where a table inside one starts to squeeze. */
.rep-cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(420px, 1fr)); gap: 16px; }
.rep-cols > .rep-block { margin-bottom: 0; }

.rep-scroll { overflow-x: auto; }
.rep-tall { max-height: 520px; overflow-y: auto; }
.rep-scroll table { width: 100%; }
.rep-tall thead th { position: sticky; top: 0; background: var(--surface); z-index: 1; }

.rep-bars { display: flex; flex-direction: column; gap: 6px; }
.rep-bar-row { display: grid; grid-template-columns: minmax(90px, 160px) 1fr auto; align-items: center; gap: 10px; }
.rep-bar-label { font-size: calc(13px + var(--font-boost)); overflow-wrap: anywhere; }
.rep-bar-track { background: var(--navy-10); border-radius: 99px; height: 10px; overflow: hidden; }
.rep-bar-fill { height: 100%; background: var(--navy); border-radius: 99px; }
.rep-bar-value {
  font-size: calc(13px + var(--font-boost)); font-weight: 700; font-variant-numeric: tabular-nums;
  min-width: 3ch; text-align: right;
}

/* First contact — one real person, one moment. Navy so it reads as the find it is. */
.rep-first { background: var(--navy); color: var(--paper); border-radius: 8px; padding: 14px 16px; margin: 14px 0; }
.rep-first-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 10px; }
.rep-first-head .eyebrow { color: var(--gold); margin: 0; }
.rep-first-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px 18px; }
.rep-first-k { font-size: calc(11px + var(--font-boost)); color: #9aa0b4; text-transform: uppercase; letter-spacing: .5px; }
.rep-first-v { font-size: calc(14px + var(--font-boost)); font-weight: 700; margin-top: 1px; }
.rep-first .hint { color: #9aa0b4; margin-top: 12px; }

/* Charts. Inline SVG, sized by its viewBox, so it scales with the card and prints. */
.chart { width: 100%; margin: 6px 0 2px; }
.chart svg { width: 100%; height: auto; display: block; }
.chart-tick { font-size: 10px; fill: var(--text-muted); }
.chart-centre { font-size: 22px; font-weight: 700; fill: var(--navy); }
.chart-donut { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.chart-donut svg { width: 150px; height: 150px; flex: none; }
.chart-key { list-style: none; margin: 0; padding: 0; flex: 1 1 160px; }
.chart-key li { display: flex; align-items: center; gap: 8px; padding: 3px 0; font-size: calc(13px + var(--font-boost)); }
.chart-key li strong { margin-left: auto; font-variant-numeric: tabular-nums; }
.chart-swatch { width: 11px; height: 11px; border-radius: 3px; flex: none; }

/* Past campaigns ------------------------------------------------------------------------------
   Cards rather than rows: what identifies last term's newsletter is its name and its subject
   line, and both need more than a table cell's worth of room. */
.arch-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 12px; margin-top: 12px; }
.arch-card {
  border: 1px solid var(--border); border-radius: 8px; padding: 14px; background: var(--paper);
  display: flex; flex-direction: column; gap: 6px;
}
.arch-card-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; font-size: calc(12px + var(--font-boost)); }
/* Overrides `.rep-block h4`, which is a small uppercase section label — right for "BY YEAR
   GROUP", wrong for a campaign's own name, which came out shouting. */
/* Two classes deep on purpose: `.rep-block h4` is (0,1,1) and outranks a bare `.arch-name`
   whatever the order in this file. */
.arch-card .arch-name {
  margin: 2px 0 0; font-size: calc(16px + var(--font-boost)); font-weight: 700;
  text-transform: none; letter-spacing: 0; color: var(--navy);
}
.arch-subject { margin: 0; color: var(--text-muted); font-size: calc(13px + var(--font-boost)); }
.arch-count { margin: 0; font-size: calc(13px + var(--font-boost)); font-variant-numeric: tabular-nums; }
.arch-actions { display: flex; gap: 6px; flex-wrap: wrap; margin-top: auto; padding-top: 8px; }
.arch-actions .btn { padding: 6px 11px; font-size: calc(12px + var(--font-boost)); }

/* The frozen pre-send checks. Amber rather than red: these were known and sent anyway, which is
   a record of a decision, not an error to be alarmed about now. */
.rep-checks { margin: 6px 0 0; padding-left: 20px; }
.rep-checks li { margin: 4px 0; font-size: calc(13px + var(--font-boost)); color: var(--gold-deep); }

/* Placeholders ---------------------------------------------------------------------------------
   Light enough to read as an example rather than as content, dark enough to actually read. navy-50
   is the same muted tone the hints use and clears 4.5:1 on white; the greys browsers default to do
   not. Nothing is ever pre-filled into a field for someone to delete — see NEW_BLOCK. */
::placeholder { color: var(--navy-50); opacity: 1; }
input::placeholder, textarea::placeholder { font-style: italic; }

/* The rich-text areas are contenteditable and take no placeholder attribute, so the hint is drawn
   over the empty editor. pointer-events:none keeps the click going through to the text. */
.mm-rte[data-empty]::before {
  content: attr(data-placeholder);
  /* z-index is load-bearing: TipTap's own editor element is position:relative with a white
     background, so without it the placeholder is painted and then covered over. */
  position: absolute; z-index: 1; pointer-events: none;
  color: var(--navy-50); font-style: italic;
  padding: 12px 14px;
  font-size: calc(15px + var(--font-boost));
}
.mm-rte { position: relative; }

/* Which block the preview was just clicked on. A ring that fades, not a selection that stays:
   it answers "which one is this" and then gets out of the way. */
@keyframes mm-flash {
  from { box-shadow: 0 0 0 3px var(--gold); }
  to   { box-shadow: 0 0 0 3px rgba(222, 172, 53, 0); }
}
.mm-block.mm-flash { animation: mm-flash 1.4s var(--ease); }
/* The preview's own cursor, so it reads as something you can click into rather than a picture. */
.mm-preview-frame { cursor: pointer; }

/* The add buttons, in the colour of the block each one makes -------------------------------------
   Same tints as the block cards below them, so pressing "+ Story card" and seeing a lilac card
   appear is one idea rather than two. Kept as tinted outlines rather than solid fills: nine solid
   buttons would shout louder than the campaign itself. */
/* Every rule below is written two classes deep. `.btn.secondary` is (0,2,0) and would otherwise
   win against a single class whatever the order, which is what made the first attempt at this
   render nine white buttons. */
.mm-add-palette .mm-add { border-width: 1px; border-style: solid; font-weight: 700; }
.mm-add-palette .mm-add-heading { background: var(--saffron-light);   border-color: var(--gold);      color: var(--gold-deep); }
.mm-add-palette .mm-add-text    { background: var(--grey-soft);       border-color: var(--navy-50);   color: var(--navy); }
.mm-add-palette .mm-add-image   { background: var(--info-blue-light); border-color: var(--info-blue); color: #2c5c8a; }
.mm-add-palette .mm-add-card    { background: var(--lilac-light);     border-color: var(--violet);    color: #7d4576; }
.mm-add-palette .mm-add-events  { background: var(--skye-light);      border-color: var(--skye);      color: #246300; }
.mm-add-palette .mm-add-button  { background: var(--rose-light);      border-color: var(--sienna);    color: var(--sienna); }
.mm-add-palette .mm-add-columns { background: var(--pink-light);      border-color: var(--ruby);      color: #b2416c; }
.mm-add-palette .mm-add-divider,
.mm-add-palette .mm-add-spacer  { background: var(--white);           border-color: var(--navy-20);   color: var(--navy-50); }
.mm-add-palette .mm-add:hover:not(:disabled) { filter: brightness(0.96); }

/* What the campaign is made of. A divider above it, because it is a summary of the thing rather
   than another control. */
.mm-used { border-top: 1px solid var(--border); margin-top: 14px; padding-top: 10px; }
.mm-used-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 8px; }
.mm-used-head .eyebrow { margin: 0; }
.mm-used-total { font-size: calc(12px + var(--font-boost)); color: var(--text-muted); font-variant-numeric: tabular-nums; }
/* auto-fill, so it wraps to as many rows as it needs — two on a laptop, one on a phone — without
   anyone deciding in advance how many there should be. */
.mm-used-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 6px; }
.mm-used-chip {
  display: flex; align-items: baseline; gap: 7px; padding: 5px 10px;
  border: 1px solid var(--border); border-left-width: 3px; border-radius: 6px;
  background: var(--white); font-size: calc(13px + var(--font-boost));
}
.mm-used-chip strong { font-size: calc(15px + var(--font-boost)); font-variant-numeric: tabular-nums; min-width: 1.4ch; }
.mm-used-heading { background: var(--saffron-light);   border-left-color: var(--gold); }
.mm-used-text    { background: var(--grey-soft);       border-left-color: var(--navy-50); }
.mm-used-image   { background: var(--info-blue-light); border-left-color: var(--info-blue); }
.mm-used-card    { background: var(--lilac-light);     border-left-color: var(--violet); }
.mm-used-events  { background: var(--skye-light);      border-left-color: var(--skye); }
.mm-used-button  { background: var(--rose-light);      border-left-color: var(--sienna); }
.mm-used-columns { background: var(--pink-light);      border-left-color: var(--ruby); }

/* Admin: the two fixed bases a campaign type can sit under. Presented as headings rather than as
   an editable field, because moving a type between them would change the unsubscribe rule for
   everything sent under it, past and future. */
.adm-basis { border: 1px solid var(--border); border-radius: 8px; padding: 14px; margin-top: 14px; }
.adm-basis-head { display: flex; align-items: flex-start; gap: 10px; margin-bottom: 8px; }
.adm-basis-head .hint { margin-top: 2px; }
.adm-basis table { margin-top: 6px; }
.adm-basis .mm-add { padding: 4px 9px; font-size: calc(12px + var(--font-boost)); margin-right: 4px; }

/* The emoji picker ------------------------------------------------------------------------------
   Appended to <body> and positioned against its button, so it is never clipped by a card's
   overflow or trapped inside the editor's scrolling column. */
.emoji-pop {
  position: fixed; z-index: 2000; width: 340px;
  background: var(--surface); border: 1px solid var(--navy-20); border-radius: 10px;
  box-shadow: 0 12px 32px rgba(27, 32, 52, .18); padding: 10px;
  display: flex; flex-direction: column; gap: 8px;
}
.emoji-search { width: 100% !important; padding: 6px 10px; font-size: calc(13px + var(--font-boost)); }
.emoji-tabs { display: flex; gap: 2px; flex-wrap: wrap; }
.emoji-tab {
  border: 1px solid transparent; background: none; border-radius: 6px; cursor: pointer;
  font-size: 17px; line-height: 1; padding: 5px 6px;
}
.emoji-tab:hover { background: var(--grey-soft); }
.emoji-tab.on { background: var(--saffron-light); border-color: var(--gold); }
.emoji-grid { overflow-y: auto; max-height: 260px; }
.emoji-heading {
  font-size: calc(11px + var(--font-boost)); text-transform: uppercase; letter-spacing: .5px;
  color: var(--text-muted); margin: 6px 0 4px; position: sticky; top: 0; background: var(--surface);
}
/* A fixed eight columns rather than auto-fill: emoji differ in advance width, and a grid that
   reflows as you scroll between groups is unpleasant to aim at. */
.emoji-row { display: grid; grid-template-columns: repeat(8, 1fr); gap: 2px; }
.emoji-cell {
  border: 0; background: none; cursor: pointer; border-radius: 6px;
  font-size: 21px; line-height: 1; padding: 5px 0;
}
.emoji-cell:hover { background: var(--saffron-light); }
.mm-emoji-btn { font-size: 15px; }
/* A field with its own emoji button beside it. */
.mm-input-emoji { display: flex; gap: 6px; align-items: center; }
.mm-input-emoji input { flex: 1 1 auto; }
.mm-input-emoji .mm-icon { flex: none; }
.mm-subject-emoji { padding: 6px 10px; }

/* A card's buttons, one row each, with the remove control at the end of the row. */
.mm-btn-edit { display: flex; gap: 10px; align-items: flex-end; margin-bottom: 8px; }
.mm-btn-edit > div { flex: 1 1 0; min-width: 0; }
.mm-btn-edit > .mm-icon { flex: none; margin-bottom: 1px; }

/* Text pinned to a fixed size, which will not follow the campaign's base size. Amber rather than
   red: it is a choice someone made, and sometimes the right one — a pull quote, a line of fine
   print — so this points it out rather than telling anyone off. */
.mm-pinned:not(:empty) {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 8px; padding: 8px 11px; border-radius: 6px;
  background: var(--saffron-light); border: 1px solid var(--gold);
  font-size: calc(12px + var(--font-boost)); color: var(--gold-deep);
}
.mm-pinned .mm-add { margin-left: auto; }

/* Named text styles, shown in the editor as they will compile. The email gets real inline pixel
   sizes from shared/compile.ts; these are so the writing surface does not lie about them. */
.mm-rte .tiptap .mm-lead  { font-size: 1.15em; line-height: 1.5; }
.mm-rte .tiptap .mm-small { font-size: 0.82em; line-height: 1.5; color: #6b7080; }
/* The house style for a link: bold, underlined, pale sky behind it. Matches LINK_STYLE in
   shared/compile.ts, so the editor shows what the family will see. */
.mm-rte .tiptap a {
  font-weight: 700; text-decoration: underline;
  background: #e3eefa; padding: 1px 3px; border-radius: 3px;
}
.mm-style { width: auto !important; min-width: 124px; }

/* The "preview as this recipient" frame on the review screen. An iframe, not injected HTML: the
   app's stylesheet must not reach the email being checked, and the email's own @font-face and
   media query must not reach the app. */
.mm-sample-wrap {
  margin-top: 10px; border: 1px solid var(--border); border-radius: 6px;
  background: var(--paper); overflow: hidden;
}
.mm-sample-frame { width: 100%; height: 520px; border: 0; display: block; background: var(--paper); }

/* Every recipient, one line each and numbered.
   Deliberately NOT a comma-separated run: that is what a To: field looks like, and this list is
   read by someone deciding whether it is safe to send to hundreds of families. The format should
   not imply the one thing the app exists to prevent. */
.address-list {
  max-height: 260px; overflow: auto; margin: 8px 0 0; padding: 10px 10px 10px 38px;
  background: var(--grey-soft); border-radius: 6px;
  font-size: calc(12px + var(--font-boost)); color: var(--text);
}
.address-list li { padding: 2px 0; }
.address-list li::marker { color: var(--text-muted); font-variant-numeric: tabular-nums; }
.addr-email { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.addr-name { color: var(--text-muted); margin-left: 8px; }

/* Thumbs up or down against the last test. Deliberately large and blunt: this is the last thing
   read before a newsletter reaches hundreds of families, and "it changed" in grey body text was
   too easy to read past. */
.mm-verdict {
  display: flex; align-items: flex-start; gap: 12px;
  margin: 10px 0; padding: 12px 14px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--surface);
}
.mm-verdict.good { background: var(--skye-light); border-color: var(--skye); }
.mm-verdict.bad  { background: var(--saffron-light); border-color: var(--gold-deep); }
.mm-verdict-mark { font-size: 24px; line-height: 1.1; }

/* ---- The About view (#/about) ---------------------------------------------------------------
   Ported from the standalone about.html page. Everything is scoped under .about-view for one
   specific reason: brand.css sets a global `tr:hover td { background }` and uppercases every
   `th`, and those reach into any table rendered in the app. The email preview learned this the
   hard way and ended up in an iframe; a page of prose does not need an iframe, it needs the
   rules written so they win. Body copy follows the masthead's A-/A/A+ control via --font-boost,
   with a 0px fallback so the same markup still renders correctly outside the app shell. */
.about-view { max-width: 1080px; }
.about-view .aa-head { padding: 4px 0 26px; border-bottom: 1px solid var(--navy-10); }
.about-view .aa-head h1 { font-size: calc(34px + var(--font-boost, 0px)); line-height: 1.12; margin: 8px 0 14px; color: var(--navy); font-weight: 900; }
.about-view .aa-head h1 strong { color: var(--gold-deep); font-weight: 900; }
.about-view .aa-standfirst { font-size: calc(16px + var(--font-boost, 0px)); line-height: 1.6; color: var(--navy-70); max-width: 68ch; margin: 0; }

.about-view .aa-tabs { display: flex; gap: 6px; margin: 22px 0 0; flex-wrap: wrap; }
.about-view .aa-tab {
  appearance: none; border: 1px solid var(--navy-20); background: var(--white);
  color: var(--navy-70); font: inherit; font-weight: 700; font-size: calc(14px + var(--font-boost, 0px));
  padding: 9px 18px; border-radius: 999px; cursor: pointer; transition: all .14s ease;
}
.about-view .aa-tab:hover { border-color: var(--navy-50); color: var(--navy); }
.about-view .aa-tab[aria-selected="true"] { background: var(--navy); border-color: var(--navy); color: var(--white); }

.about-view .aa-panel[hidden] { display: none; }
.about-view .aa-section { padding: 34px 0; border-bottom: 1px solid var(--navy-10); }
.about-view .aa-section:last-child { border-bottom: 0; }
.about-view .aa-n { font-size: 12px; font-weight: 900; letter-spacing: .14em; color: var(--gold-deep); }
.about-view .aa-eyebrow { font-size: 11px; font-weight: 700; letter-spacing: .16em; text-transform: uppercase; color: var(--navy-50); margin-left: 10px; }
.about-view .aa-section h2 { font-size: calc(24px + var(--font-boost, 0px)); line-height: 1.2; margin: 10px 0 18px; color: var(--navy); font-weight: 900; }
.about-view .aa-subhead { font-size: calc(15px + var(--font-boost, 0px)); font-weight: 900; color: var(--navy); margin: 30px 0 12px; }
.about-view .aa-section p { font-size: calc(15px + var(--font-boost, 0px)); line-height: 1.72; color: var(--navy-70); margin: 0 0 15px; max-width: 74ch; }
.about-view .aa-section p.lede { font-size: calc(16.5px + var(--font-boost, 0px)); color: var(--navy-90); }
.about-view .aa-section strong { color: var(--navy); font-weight: 700; }
.about-view .aa-section ul { margin: 0 0 16px; padding-left: 20px; max-width: 74ch; }
.about-view .aa-section li { font-size: calc(15px + var(--font-boost, 0px)); line-height: 1.72; color: var(--navy-70); margin-bottom: 8px; }

.about-view .aa-table-wrap { overflow-x: auto; margin: 6px 0 10px; border: 1px solid var(--navy-10); border-radius: 10px; }
/* A four- or five-column table has nowhere to go on a phone: every cell wraps to three words
   and the thing becomes unreadable. Give those a floor and let the wrapper scroll sideways. */
.about-view .aa-table-wrap.wide table { min-width: 660px; }
.about-view .aa-scroll-hint { display: none; font-size: 12px; color: var(--navy-50); margin: 6px 0 0; font-style: italic; }
@media (max-width: 900px) {
  .about-view .aa-table-wrap.wide + .aa-scroll-hint { display: block; }
}
.about-view table { width: 100%; border-collapse: collapse; background: var(--white); }
.about-view th {
  text-align: left; padding: 11px 14px; background: var(--grey-soft); color: var(--navy);
  font-weight: 900; font-size: calc(12px + var(--font-boost, 0px)); letter-spacing: .03em;
  border-bottom: 1px solid var(--navy-10); white-space: nowrap;
  /* brand.css uppercases every th in the app. These are sentence-case column headings. */
  text-transform: none;
}
.about-view td {
  padding: 11px 14px; border-bottom: 1px solid var(--navy-10); color: var(--navy-70);
  font-size: calc(13.5px + var(--font-boost, 0px)); line-height: 1.55; vertical-align: top;
}
.about-view tbody tr:last-child td { border-bottom: 0; }
/* brand.css tints every row on hover. That is right for a list you click and wrong for a
   reference table you read, and it is the same specificity as the rule above, so it has to be
   turned off by name rather than out-weighted. */
.about-view tbody tr:hover td { background: var(--white); }
.about-view td:first-child { color: var(--navy); font-weight: 700; }
.about-view td.yes { color: #2c6b3f; font-weight: 700; }
.about-view td.no { color: var(--navy-50); }
.about-view .aa-table-caption,
.about-view .aa-sources { font-size: calc(12.5px + var(--font-boost, 0px)); line-height: 1.62; color: var(--navy-50); margin: 10px 0 0; max-width: 78ch; }
.about-view .aa-sources { padding-top: 10px; border-top: 1px dashed var(--navy-20); margin-top: 16px; }
.about-view .aa-sources a { color: var(--info-blue); }

.about-view .aa-figs { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; margin: 4px 0 22px; }
.about-view .aa-fig { background: var(--grey-soft); border: 1px solid var(--navy-10); border-radius: 10px; padding: 16px 16px 14px; }
.about-view .aa-fig b { display: block; font-size: calc(26px + var(--font-boost, 0px)); line-height: 1; color: var(--navy); font-weight: 900; }
.about-view .aa-fig span { display: block; font-size: calc(12px + var(--font-boost, 0px)); color: var(--navy-50); margin-top: 7px; line-height: 1.4; }

.about-view .aa-note { border-left: 3px solid var(--gold); background: var(--saffron-light); padding: 15px 18px; border-radius: 0 8px 8px 0; margin: 20px 0; }
.about-view .aa-note p:last-child { margin-bottom: 0; }
.about-view .aa-note.rule { border-left-color: var(--scarlett); background: var(--rose-light); }
.about-view .aa-note.good { border-left-color: var(--skye); background: var(--skye-light); }

@media (max-width: 620px) {
  .about-view .aa-head h1 { font-size: calc(27px + var(--font-boost, 0px)); }
  .about-view .aa-section h2 { font-size: calc(21px + var(--font-boost, 0px)); }
  .about-view .aa-fig b { font-size: calc(22px + var(--font-boost, 0px)); }
}

/* ---- The public About page (/about) ---------------------------------------------------------
   Same .about-view content as the in-app #/about route, wrapped for a standalone document.
   .landing is a column flex container, so this needs an explicit width: left at auto its
   hypothetical cross size is its MAX-content width, the flex line grows to match, and one
   660px-wide table drags the page header off the right edge on a phone. */
.about-standalone {
  max-width: 1080px; width: 100%; min-width: 0; box-sizing: border-box;
  margin: 0 auto; padding: 34px 22px 70px; flex: 1;
}
.about-standalone .about-view { max-width: none; }
.about-standalone .aa-head { padding-top: 0; }
.aa-enter { margin: 34px 0 0; }
.aa-enter a { font-size: 15px; font-weight: 700; color: var(--info-blue); }
@media (max-width: 620px) { .about-standalone { padding: 24px 16px 50px; } }

/* The way in to the About page from the landing page: a quiet pill at the top of the footer,
   not a second call to action competing with "Enter Monkey Mail". It sits INSIDE .landing-footer
   rather than above it — as its own band it left a pale strip of page background stranded
   between the dark hero and the navy footer, which read as a mistake. */
.landing-about-link { padding: 0 0 20px; }
.landing-about-link a {
  display: inline-block; font-size: 13px; font-weight: 700;
  color: rgba(255, 255, 255, 0.82); border: 1px solid rgba(255, 255, 255, 0.28);
  border-radius: 999px; padding: 8px 18px; text-decoration: none; transition: all .14s ease;
}
.landing-about-link a:hover {
  color: var(--navy); background: var(--gold); border-color: var(--gold);
}
