/* ==========================================================================
   mail.ruosenzhao.com -- layout and components.
   Colour lives ONLY in assets/tokens.css.  This file adds no colours except:
     * the modal scrim, the paper behind a rendered mail and the blocked-image
       placeholder -- neutral surfaces that must not follow the theme
     * five mailbox identity hues, which are this site's own vocabulary
     * four small site-local corrections to shared tokens, each commented with
       the measured reason (the shared file is not edited; the other sites are
       English and would inherit the change).

   Breakpoints, stated once so they cannot drift (they HAD drifted: the comment
   said 1200 while the code switched at 1100):
     0-779        one pane, nav is a drawer
     780-1099     list + reader, nav is still a drawer
     >=1100       full three columns
   780 is deliberate: 820x1180 is iPad portrait, and it was falling into the
   drawer bucket where a short mail left 64% of the screen empty.
   ========================================================================== */

:root {
  --rail: 232px;                     /* left rail */
  --list: 360px;                     /* message list column */
  --readw: 660px;                    /* reading measure; ~44 Chinese chars @15px */
  --paper: #ffffff;                  /* rendered mail sits on real paper */
  --scrim: rgb(0 0 0 / .58);         /* modal veil, theme-neutral by design */
  --placeholder: #eef1f5;            /* stand-in for a blocked remote image */
  --row-h: 65px;                     /* one list row; skeletons must match */
  --card-edge: var(--edge);          /* structural cards need a real edge */
  --r-xs: 4px;                       /* inline code, tiny chips */
  --reportw: 760px;                  /* reports are documents, not columns */

  /* Inside the mail frame there is no stylesheet from tokens.css, so the few
     values it needs are read out of here by app.js at render time. */
  --mail-paper: #ffffff;
  --mail-ink: #14181d;
  --mail-link: #2563eb;
  --mail-line: #dfe3e8;

  /* Mailbox identity.  Five hues ~60 degrees apart, stable across themes:
     before this, UCSD was dirty brown in light mode and bright yellow in dark,
     so the same mailbox looked like two different things after a theme flip. */
  --id-1: #1d4ed8;  --id-1-ink: #ffffff;
  --id-2: #7c3aed;  --id-2-ink: #ffffff;
  --id-3: #0f766e;  --id-3-ink: #ffffff;
  --id-4: #b45309;  --id-4-ink: #ffffff;
  --id-5: #475569;  --id-5-ink: #ffffff;

  /* File types get their own vocabulary, picked to stay off the five identity
     hues and off --accent.  Borrowing tokens.css here failed twice: --c-doc is
     byte-identical to --accent (a docx and the selected folder were the same
     blue) and --c-code is byte-identical to --id-4.  These hues exist nowhere
     else in the UI, so a colour still means exactly one thing. */
  --att-pdf: #b91c1c;    --att-img: #a21caf;   --att-sheet: #15803d;
  --att-arc: #7c2d12;    --att-doc: #0891b2;   --att-media: #db2777;
  --att-file: var(--muted);

  /* Corrections to shared tokens, measured on this site:
     --edge light #8a94a6 is 2.70:1 on --surface-2 (where every input sits) but
     tokens.css says it is "kept >=3:1".  2.70:1 is below WCAG 1.4.11. */
}

/* --------------------------------------------------------- corrections --- */
:root[data-theme="light"] { --edge: #767f8f; }

:root[data-theme="dark"] {
  /* Measured in dark mode: --surface on --bg was 1.07:1 and a --divider
     hairline 1.16:1, so the report cards merged into one black band and the
     boundaries of every panel were invisible.  Raise the fill one step. */
  --surface: #171c23;
  --surface-2: #1f252e;
  /* a blocked-image box must not glow white on the dark paper (the light
     --placeholder #eef1f5 is 15:1 against #171a1f) */
  --placeholder: #1b2129;
  --mail-paper: #171a1f;
  --mail-ink: #d9dee6;
  --mail-link: #6ea8ff;
  --mail-line: #2a3038;
  /* --edge #5c6a7a is 2.75:1 on the button fill and 2.79:1 on the search fill,
     under WCAG 1.4.11's 3:1 for a control's own boundary.  4.2:1 with this. */
  --edge: #78889a;
  /* #171c23 on #0b0d10 was 1.14:1: the fills of the cards were indistinguishable
     and every panel relied on its border alone. */
  --surface: #1b2129;
  --att-pdf: #f87171;    --att-img: #e879f9;   --att-sheet: #4ade80;
  --att-arc: #fdba74;    --att-doc: #22d3ee;   --att-media: #f472b6;
  --att-file: var(--muted);
}

/* --dim is 4.24:1 on this site's light background and only ever used for text
   a person has to read.  Collapse the third level into the second rather than
   ship text under 4.5:1.  (Loaded after base.css, so this wins.) */
.dim { color: var(--muted); }

*,
*::before,
*::after { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font: var(--fs-md) / var(--lh-base) var(--font);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow: hidden;                  /* the shell owns scrolling, not the page */
  overscroll-behavior: none;
}

button, input, select, textarea { font: inherit; color: inherit; }
button, a, .row, .chip, .acct { touch-action: manipulation; }
h1, h2, h3 { margin: 0; letter-spacing: -.01em; }

/* Not a shared component: a page-level jump target. */
.skip-link {
  position: absolute; left: 8px; top: -60px; z-index: 90;
  background: var(--raised); color: var(--fg); border: 1px solid var(--edge);
  border-radius: var(--r-sm); padding: 8px 14px; text-decoration: none;
}
.skip-link:focus { top: 8px; }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 6px; }

/* ---------------------------------------------------------------- boot --- */
.boot {
  height: 100dvh; display: grid; place-content: center; justify-items: center;
  gap: var(--sp-3); color: var(--muted);
}
.boot-mark { font-size: 40px; color: var(--accent); animation: breathe 1.6s var(--ease) infinite; }
@keyframes breathe { 0%, 100% { opacity: .35 } 50% { opacity: 1 } }
@media (prefers-reduced-motion: reduce) { .boot-mark { animation: none } }

/* --------------------------------------------------------------- login --- */
.auth {
  height: 100dvh; display: grid; place-content: center; padding: var(--sp-5);
  overflow-y: auto;
}
.auth .card {
  width: min(400px, 100%); display: flex; flex-direction: column;
  gap: var(--sp-4); padding: var(--sp-5); background: var(--surface);
  border: 1px solid var(--card-edge); border-radius: var(--r-lg); box-shadow: var(--sh-3);
}
.auth-brand {
  width: 42px; height: 42px; display: grid; place-items: center; font-size: 21px;
  color: var(--accent); background: var(--surface-2); border-radius: var(--r-md);
  border: 1px solid var(--card-edge);
}
.auth h1 { font-size: var(--fs-2xl); font-weight: 600; }
.auth > .card > p { color: var(--muted); font-size: var(--fs-sm); margin: 0; }
.field { display: flex; flex-direction: column; gap: var(--sp-2); }
.field label { font-size: var(--fs-xs); color: var(--muted); }
.field input, .field select, .field textarea {
  font-size: 16px;                      /* <16px makes mobile Safari zoom on focus */
  min-height: var(--tap); padding: 0 var(--sp-3);
  background: var(--surface-2); color: var(--fg);
  border: 1px solid var(--edge); border-radius: var(--r-sm);
}
.field textarea { padding: var(--sp-3); line-height: var(--lh-base); resize: vertical; min-height: 120px; }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}
.field.row2 { display: grid; grid-template-columns: auto 1fr; gap: var(--sp-2) var(--sp-3); align-items: center; }
.auth-msg { min-height: 18px; margin: 0; font-size: var(--fs-xs); color: var(--danger); }
.btnrow { display: flex; gap: var(--sp-2); }
.btnrow .btn { flex: 1; justify-content: center; }
.auth-foot { font-size: var(--fs-xs); margin: 0; }

/* --------------------------------------------------------------- shell --- */
.shell { height: 100dvh; display: grid; grid-template-columns: 1fr; min-height: 0; }
.main { display: grid; grid-template-columns: 1fr; min-width: 0; min-height: 0; }

.nav {
  display: flex; flex-direction: column; min-height: 0;
  background: var(--surface); border-right: 1px solid var(--card-edge);
  position: fixed; inset: 0 auto 0 0; width: min(304px, 86vw); z-index: 40;
  transform: translateX(-101%); transition: transform var(--dur) var(--ease);
  padding-bottom: env(safe-area-inset-bottom);
}
body.nav-open .nav { transform: none; }
.scrim {
  position: fixed; inset: 0; background: var(--scrim); z-index: 35;
  border: 0; padding: 0; opacity: 0; transition: opacity var(--dur) var(--ease);
}
body.nav-open .scrim { opacity: 1; }
body:not(.nav-open) .scrim { pointer-events: none; }

.nav-head {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-3) var(--sp-2);
}
.logo { font-size: var(--fs-xl); color: var(--accent); }
.nav-title { font-weight: 600; letter-spacing: -.01em; margin-right: auto; }
.nav-scroll { flex: 1; min-height: 0; overflow-y: auto; padding: 0 var(--sp-2) var(--sp-3); }
/* No uppercase and no letter-spacing: these labels are Chinese, where both are
   no-ops that would only stretch "Mail" into "Mai l". */
.nav-group {
  font-size: var(--fs-xs); color: var(--muted); margin: var(--sp-4) var(--sp-3) var(--sp-2);
}
.nav-hint { font-size: var(--fs-xs); color: var(--muted); margin: var(--sp-2) var(--sp-3) 0; line-height: 1.4; }
.nav-foot {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3); border-top: 1px solid var(--divider); font-size: var(--fs-xs);
}
.nav-foot span { margin-right: auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---- mailbox rows ---- */
.accts { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.acct {
  position: relative;
  width: 100%; display: grid;
  /* Three columns could not work: at a 232px rail the fixed 84px badge column
     left 63px for the address, so the local part measured 0px wide and all five
     mailboxes read as "@gmail.com".  The badge now rides on the name line and
     the address gets the whole column. */
  grid-template-columns: 34px minmax(0, 1fr);
  align-items: center; gap: var(--sp-3);
  min-height: 58px; padding: var(--sp-2) var(--sp-3);
  background: transparent; border: 1px solid transparent; border-radius: var(--r-md);
  cursor: pointer; text-align: left; color: inherit;
}
.acct:hover { background: var(--surface-2); }
.acct[aria-current="true"] { background: var(--surface-2); border-color: var(--edge); }
.acct[aria-current="true"]::before {
  content: ""; position: absolute; left: 0; top: 50%; transform: translateY(-50%);
  width: 3px; height: 26px; border-radius: 0 3px 3px 0; background: var(--accent);
}
.acct-mark {
  width: 34px; height: 34px; border-radius: var(--r-sm); display: grid; place-items: center;
  font-size: var(--fs-xs); font-weight: 700; letter-spacing: .02em;
  color: var(--on-accent); background: var(--accent);
}
/* one identity hue per mailbox; the ink is a token so a re-skin still works */
.acct-mark.id-1 { background: var(--id-1); color: var(--id-1-ink); }
.acct-mark.id-2 { background: var(--id-2); color: var(--id-2-ink); }
.acct-mark.id-3 { background: var(--id-3); color: var(--id-3-ink); }
.acct-mark.id-4 { background: var(--id-4); color: var(--id-4-ink); }
.acct-mark.id-5 { background: var(--id-5); color: var(--id-5-ink); }
.acct-main { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.acct-top { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; }
.acct-top .acct-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.acct-label { font-weight: 600; font-size: var(--fs-sm); }
/* The domain is the only thing that tells the five mailboxes apart, so it never
   gets an ellipsis; the local part does. */
.acct-mail { font-size: var(--fs-xs); color: var(--muted); display: flex; min-width: 0; white-space: nowrap; }
.acct-mail .local { overflow: hidden; text-overflow: ellipsis; }
.acct-mail .domain { flex: none; }
.acct-meta { display: none; }   /* the count lives on the name line now */
/* Both counters are the same pill in the same place; only the tone differs, so
   the reading column never jumps between rows. */
.badge {
  min-width: 0; padding: 2px 7px; border-radius: var(--r-full); flex: none;
  background: var(--accent); color: var(--on-accent); border: 1px solid transparent;
  font-size: var(--fs-xs); font-weight: 700; font-variant-numeric: tabular-nums; text-align: center;
  white-space: nowrap;
}
.badge.soft { background: var(--surface-2); color: var(--muted); border-color: var(--card-edge); font-weight: 600; }

/* ---- reports nav row ---- */
.navrow {
  position: relative;
  width: 100%; display: flex; align-items: center; gap: var(--sp-3); min-height: 58px;
  padding: var(--sp-2) var(--sp-3); background: transparent; border: 1px solid transparent;
  border-radius: var(--r-md); cursor: pointer; text-align: left; color: inherit;
}
.navrow:hover { background: var(--surface-2); }
.navrow[aria-current="true"] { background: var(--surface-2); border-color: var(--edge); }
.navrow[aria-current="true"]::before {
  content: ""; position: absolute; left: 0; top: 50%; transform: translateY(-50%);
  width: 3px; height: 26px; border-radius: 0 3px 3px 0; background: var(--accent);
}
.navrow-ic { color: var(--c-note); display: grid; place-items: center; width: 34px; }
.navrow-main { min-width: 0; display: flex; flex-direction: column; }
.navrow-t { font-weight: 600; font-size: var(--fs-sm); }
.navrow-s { font-size: var(--fs-xs); color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---------------------------------------------------------------- pane --- */
.pane { display: flex; flex-direction: column; min-width: 0; min-height: 0; background: var(--bg); }
.pane-list { border-right: 1px solid var(--card-edge); }
.pane-head {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3); min-height: 64px; border-bottom: 1px solid var(--divider);
}
.pane-titles { min-width: 0; margin-right: auto; }
.pane-titles h1, .pane-titles h2 { font-size: var(--fs-lg); font-weight: 600; }
.pane-titles p {
  margin: 2px 0 0; font-size: var(--fs-xs);
  /* a long address (ruosenzhao@link.cuhk.edu.cn · 2847 messages) wrapped to two
     lines in a 201px column and pushed the toolbar from 64px to 83px */
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.filters { padding: var(--sp-3) var(--sp-3) var(--sp-2); display: flex; flex-direction: column; gap: var(--sp-3); }
.searchrow .q-all { min-height: 44px; padding: 0 var(--sp-3); font-size: var(--fs-xs); }
.searchrow .q-all[aria-pressed="true"] {
  background: var(--accent); border-color: var(--accent); color: var(--on-accent); font-weight: 600;
}
.searchrow { padding-right: 4px; }
/* one scrollable line: wrapping chips used to eat four rows of vertical space */
.folders {
  display: flex; flex-wrap: nowrap; gap: var(--sp-2);
  overflow-x: auto; overscroll-behavior-x: contain;
  margin: 0 calc(var(--sp-3) * -1); padding: 0 var(--sp-3) var(--sp-1);
  scrollbar-width: none;
  /* With the scrollbar hidden there was nothing to say the row continued: on a
     1440 screen only 2.4 of 7 folders were visible.  Fade the last 28px. */
  mask-image: linear-gradient(90deg, #000 calc(100% - 28px), transparent);
  -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 28px), transparent);
}
.folders::-webkit-scrollbar { display: none; }
.folders .chip {
  flex: none; display: inline-flex; align-items: center; gap: 6px;
  min-height: var(--tap); padding: 0 var(--sp-3);
  background: var(--surface); border: 1px solid var(--card-edge); border-radius: var(--r-full);
  color: var(--muted); font-size: var(--fs-sm); cursor: pointer;
}
@media (hover: hover) { .folders .chip:hover { color: var(--fg); border-color: var(--edge); } }
.folders .chip[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: var(--on-accent); font-weight: 600; }
/* Was opacity:.8, which dropped the selected count to 1.96:1 and the light-mode
   unselected one to 3.75:1 -- the number you look at first was the faintest
   thing on the screen. */
.folders .chip .n { font-size: var(--fs-xs); font-variant-numeric: tabular-nums; color: var(--muted); }
.folders .chip[aria-pressed="true"] .n { color: var(--on-accent); font-weight: 600; }

.searchrow {
  display: flex; align-items: center; gap: var(--sp-2); padding: 0 var(--sp-3);
  min-height: 48px; background: var(--surface-2);
  border: 1px solid var(--edge); border-radius: var(--r-full);
}
.searchrow:focus-within { border-color: var(--accent); }
.searchrow .s-ic { color: var(--muted); flex: none; }
.searchrow input {
  flex: 1; min-width: 0; border: 0; background: transparent;
  /* no outline:none here: the focus ring is the site-wide :focus-visible one,
     not a private box-shadow that only this control has */
  font-size: 16px; min-height: 44px;
}
.searchrow input::placeholder { color: var(--muted); }
.searchrow input::-webkit-search-cancel-button { display: none; }
.searchrow .clear {
  border: 0; background: transparent; color: var(--muted); cursor: pointer;
  width: var(--tap); height: var(--tap); margin-right: -10px;
  border-radius: var(--r-full); font-size: var(--fs-sm); flex: none;
}
.scopeline { font-size: var(--fs-xs); margin: 0; }

/* Two chip sizes and no more.  The folder chips are 44px (a control, on a
   tablet, with a thumb); a label that is not clickable stays at 28px. */
.chip-tap { min-height: var(--tap); padding: 0 var(--sp-3); }

/* ---- message rows ---- */
.rows {
  flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  /* 12px, so the row's own highlight box starts exactly where the folder chips
     and the search box do (they used to sit 21px apart) */
  padding: var(--sp-2) var(--sp-3); scrollbar-gutter: stable;
}
.row {
  position: relative;
  width: 100%; display: grid; grid-template-columns: 6px minmax(0, 1fr); gap: var(--sp-2);
  align-items: start; text-align: left; padding: 6px 0;
  background: transparent; border: 1px solid transparent; border-radius: var(--r-md);
  cursor: pointer; color: inherit; min-height: var(--row-h);
}
.row + .row { margin-top: 6px; }
.row:hover { background: var(--surface); }
.row[aria-current="true"] { background: var(--surface); border-color: var(--edge); }
.row[aria-current="true"]::before {
  content: ""; position: absolute; left: 0; top: 50%; transform: translateY(-50%);
  width: 3px; height: 26px; border-radius: 0 3px 3px 0; background: var(--accent);
}
.row-dot { width: 6px; height: 6px; margin-top: 6px; border-radius: var(--r-full); background: transparent; }
.row.unread .row-dot { background: var(--accent); }
/* Reading order is sender, subject, first line of the body.  The old row spent
   91px on two facts and repeated its own folder name on every line; this one
   spends ~64px on three. */
.row-main { min-width: 0; display: flex; flex-direction: column; line-height: 1.25; }
.row-top { display: flex; gap: var(--sp-2); align-items: baseline; line-height: 1.2; }
.row-from {
  font-weight: 500; font-size: var(--fs-sm); line-height: 1.25; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* A fixed date column, or the whole right edge of the list shifted 38px
   depending on whether a row said "00:11" or "10/13 23:52". */
.row-date {
  margin-left: auto; flex: none; width: 76px; text-align: right;
  font-size: var(--fs-xs); line-height: 1.25; font-variant-numeric: tabular-nums; color: var(--muted);
}
.row-subj {
  font-size: var(--fs-md); line-height: 1.3; color: var(--fg);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.row-prev {
  font-size: var(--fs-xs); line-height: 1.25; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Read state is carried by weight and by the dot, not by a fourth grey: the old
   row painted sender, subject, preview and date all in rgb(90,102,117), so a
   read list was one flat texture and the sender was the *smallest* line. */
.row.unread .row-from { font-weight: 600; color: var(--fg); }
.row.unread .row-subj { font-weight: 600; }
.row-meta { display: flex; gap: var(--sp-2); align-items: center; flex: none; margin-left: auto; }
.row-clip { display: inline-flex; align-items: center; gap: 2px; color: var(--muted); font-size: var(--fs-xs); }
.row-clip b { font-weight: 600; font-variant-numeric: tabular-nums; }
/* only rendered while searching across mailboxes, where the row has to say
   whose mail it is */
.row-acct { display: inline-flex; align-items: center; gap: 4px; font-size: var(--fs-xs); color: var(--muted); }

.pane-foot { display: flex; justify-content: center; padding: var(--sp-2) var(--sp-3); border-top: 1px solid var(--divider); }
.pane-foot .btn { min-height: var(--tap); padding: 0 var(--sp-5); border-radius: var(--r-full); }

/* ---- reader ---- */
.read-head {
  display: flex; align-items: center; gap: var(--sp-2); min-height: 64px;
  padding: var(--sp-2) var(--sp-3); border-bottom: 1px solid var(--divider);
}
/* The header used to be a full-width bar while the letter is a centred column:
   the tags sat 73px left of the subject and the close button 43px right of the
   text.  Same column, same edges. */
/* The four controls used to be block-level children of a block wrapper, so
   each one took its own line: 192px of header on a 390px phone (and 104px even
   at 1280, with the close button wrapped under the tag chip).  One row. */
.read-head-inner {
  max-width: calc(var(--readw) + var(--sp-4) * 2); padding: var(--sp-2) var(--sp-3);
  display: flex; align-items: center; gap: var(--sp-2);
}
.read-tags { margin-right: auto; display: flex; gap: var(--sp-2); flex-wrap: wrap; min-width: 0; }
.read-tags .chip { display: inline-flex; align-items: center; gap: 6px; }
.read-tags .dot { width: 8px; height: 8px; border-radius: var(--r-full); flex: none; background: var(--muted); }
.dot.id-1 { background: var(--id-1); }
.dot.id-2 { background: var(--id-2); }
.dot.id-3 { background: var(--id-3); }
.dot.id-4 { background: var(--id-4); }
.dot.id-5 { background: var(--id-5); }
.read-body { flex: 1; min-height: 0; overflow-y: auto; scrollbar-gutter: stable; }

.mail { max-width: var(--readw); margin: 0 auto; padding: var(--sp-4) var(--sp-4) var(--sp-6); }
.mail-subject { font-size: var(--fs-xl); font-weight: 600; line-height: var(--lh-tight); word-break: break-word; }

/* One real subject in the archive is 2639 characters and rendered as a 2200px
   banner -- three screens of subject before any body. */
.mail-subject.clamped {
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden; max-height: 4.6em;
}
.subj-more { margin-top: var(--sp-2); min-height: 36px; }
/* a real field grid so every label lines up and every value starts at one edge */
.mail-meta {
  margin-top: var(--sp-4); display: grid; grid-template-columns: max-content minmax(0, 1fr);
  gap: var(--sp-1) var(--sp-3); font-size: var(--fs-sm);
  padding: var(--sp-3); background: var(--surface); border: 1px solid var(--card-edge); border-radius: var(--r-md);
}
.mail-meta .k { color: var(--muted); font-size: var(--fs-xs); text-align: right; padding-top: 2px; }
.mail-meta .v { word-break: break-word; }
.mail-meta .addr { color: var(--muted); font-family: var(--mono); font-size: var(--fs-xs); }
.mail-tools { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin-top: var(--sp-4); }
.mail-actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
/* the note explaining the blocked images used to sit 2981px below the viewport */
.mail-note {
  margin: var(--sp-2) 0 0; padding: var(--sp-2) var(--sp-3); border-radius: var(--r-sm);
  background: var(--surface-2); border: 1px solid var(--card-edge);
  font-size: var(--fs-xs); color: var(--muted);
}
.mail-seg {
  display: flex; gap: 6px; padding: 3px; width: fit-content; margin-left: auto;
  background: var(--surface-2); border-radius: var(--r-full); border: 1px solid var(--card-edge);
}
.mail-seg button {
  border: 0; background: transparent; color: var(--muted); cursor: pointer;
  /* 38px next to 44px action buttons, in the same toolbar row */
  min-height: var(--tap); padding: 0 var(--sp-4); border-radius: var(--r-full); font-size: var(--fs-sm);
}
.mail-seg button[aria-pressed="true"] { background: var(--surface); color: var(--fg); font-weight: 600; }
.mail-frame {
  width: 100%; border: 1px solid var(--card-edge); border-radius: var(--r-md);
  background: var(--mail-paper); display: block; margin-top: var(--sp-4);
  /* in dark mode a brand mail still paints its own white tables -- that is the
     letter as sent and real clients keep it -- so the sheet gets a shadow to
     read as an object sitting on the desk rather than a hole in the page */
  box-shadow: var(--sh-1);
}
.mail-text {
  margin: var(--sp-4) 0 0; padding: var(--sp-4); background: var(--surface);
  border: 1px solid var(--card-edge); border-radius: var(--r-md);
  /* same reading size as the HTML body: switching format used to resize the
     text and change the family at the same time */
  font-family: var(--mono); font-size: var(--fs-md); line-height: var(--lh-loose);
  white-space: pre-wrap; word-break: break-word; overflow-wrap: anywhere;
}
.atts { margin-top: var(--sp-5); }
.atts h3 { font-size: var(--fs-sm); color: var(--muted); font-weight: 600; margin-bottom: var(--sp-2); }
.att {
  display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2) var(--sp-3);
  background: var(--surface); border: 1px solid var(--card-edge); border-radius: var(--r-md);
}
.att + .att { margin-top: var(--sp-2); }
.att-ic {
  width: 36px; height: 36px; flex: none; display: grid; place-items: center;
  border-radius: var(--r-sm); background: var(--surface-2);
  font-size: var(--fs-xs); font-weight: 700; font-family: var(--mono);
}
/* one hue per type family, from this site's own palette (see --att-* above) */
.att-ic.t-doc { color: var(--att-doc); }
.att-ic.t-pdf { color: var(--att-pdf); }
.att-ic.t-img { color: var(--att-img); }
.att-ic.t-sheet { color: var(--att-sheet); }
.att-ic.t-arc { color: var(--att-arc); }
.att-ic.t-media { color: var(--att-media); }
.att-ic.t-file { color: var(--att-file); }
.att-main { min-width: 0; flex: 1; }
.att-name { font-size: var(--fs-sm); font-weight: 600; word-break: break-all; display: block; }
.att-size { font-size: var(--fs-xs); color: var(--muted); font-variant-numeric: tabular-nums; }
.att .btn { flex: none; padding: 0 var(--sp-3); font-size: var(--fs-sm); }

.card { border-color: var(--card-edge); border-radius: var(--r-md); }

/* ---- empty / skeleton ---- */
.empty { display: grid; place-content: center; justify-items: center; text-align: center; gap: var(--sp-3); padding: var(--sp-6) var(--sp-4); color: var(--muted); min-height: 50%; }
.empty-ic { font-size: 30px; color: var(--muted); }
.empty h2 { font-size: var(--fs-md); color: var(--fg); font-weight: 600; margin: 0; }
.empty-actions { display: flex; gap: var(--sp-2); }
.empty p { margin: 0; font-size: var(--fs-sm); max-width: 34ch; }
.empty code { font-family: var(--mono); font-size: var(--fs-xs); background: var(--surface-2); padding: 1px 5px; border-radius: var(--r-xs); }
.empty .btn { margin-top: var(--sp-2); }
.sk { border-radius: var(--r-sm); background: var(--surface); animation: pulse 1.3s ease-in-out infinite; }
@keyframes pulse { 0%, 100% { opacity: .5 } 50% { opacity: .95 } }
@media (prefers-reduced-motion: reduce) { .sk { animation: none } }
/* Same height as a real row, or the list jumps by 19px per row on load.  The
   bars mirror the three real lines; a single grey slab said nothing about what
   was loading. */
.sk-row {
  height: calc(var(--row-h) - 6px); margin: 6px 0 0; padding: 8px 4px 0 16px;
  display: flex; flex-direction: column; gap: 6px;
}
.sk-row .sk { background: var(--surface-2); flex: none; }
.sk-bar-1 { height: 12px; width: 42%; }
.sk-bar-2 { height: 14px; width: 88%; }
.sk-bar-3 { height: 12px; width: 68%; }

/* ------------------------------------------------------------ reports --- */
.pane-reports { grid-column: 1 / -1; }
/* the head, the list and the button all share one column now; they used to sit
   197px and 211px apart */
.pane-reports .pane-head { padding: 0; }
.head-inner {
  width: 100%; max-width: var(--readw); margin: 0 auto;
}
.pane-reports .head-inner { max-width: var(--reportw); padding: var(--sp-2) var(--sp-4); }
.pane-reports .head-inner {
  /* the horizontal padding matches .report's, so the head text and the card
     text share one left edge (they used to sit 2-7px apart and the eye sees
     that as sloppy even without knowing why) */
  display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-2) var(--sp-4);
}
/* both-edges, because the gutter is only on the right of the scroller and that
   pushed the centred column 7px left of the sticky header above it */
.reports-wrap { flex: 1; min-height: 0; overflow-y: auto; padding: var(--sp-4); scrollbar-gutter: stable both-edges; }
.report-form { max-width: var(--reportw); margin: 0 auto var(--sp-4); padding: var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-3); }
.reports { max-width: var(--reportw); margin: 0 auto; display: flex; flex-direction: column; gap: var(--sp-3); }
.report {
  position: relative;
  background: var(--surface); border: 1px solid var(--card-edge); border-radius: var(--r-md);
  padding: var(--sp-4);
  box-shadow: inset 3px 0 0 var(--edge);   /* follows the card's radius, unlike border-left */
}
/* Colour is reserved for the two kinds that ask something of you.  Previously
   five kinds wore five hues borrowed from the attachment palette, which is the
   same "one colour, several meanings" habit the palette exists to stop -- and a
   the Summary badge has never once needed to shout. */
.report[data-kind="alert"] { box-shadow: inset 3px 0 0 var(--danger); }
.report[data-kind="task"] { box-shadow: inset 3px 0 0 var(--warn); }
.report-top { display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap; }
/* an h2 now (so each report is a navigable, named section), so no margins */
.report-title { margin: 0; font-weight: 600; font-size: var(--fs-lg); line-height: var(--lh-tight); }
.report-kind {
  font-size: var(--fs-xs); font-weight: 700; letter-spacing: .02em;
  padding: 1px 8px; border-radius: var(--r-full);
  background: var(--surface-2); color: var(--muted); border: 1px solid var(--card-edge);
}
/* the chip carries the same hue as the card's bar, so "coloured" means exactly
   one thing in both places */
.report[data-kind="alert"] .report-kind { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 45%, transparent); }
.report[data-kind="task"] .report-kind { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 45%, transparent); }
.report-by { font-size: var(--fs-xs); color: var(--muted); margin-top: var(--sp-2); }
.report-by b { color: var(--fg); font-weight: 600; }
/* was capped at 68ch inside a 726px card, leaving 23% of every card permanently
   empty on the right */
.report-body { margin-top: var(--sp-3); font-size: var(--fs-sm); line-height: var(--lh-loose); white-space: pre-wrap; word-break: break-word; }
.report-body b { color: var(--fg); }
/* a "## Yesterday at a glance" line reads as a sub-heading instead of two literal hashes */
.report-body .md-h { display: block; font-weight: 600; color: var(--fg); margin: var(--sp-2) 0 2px; }
.report-body .md-h:first-child { margin-top: 0; }
.report-body .mailref { color: var(--mail-link); text-decoration: underline; text-underline-offset: 2px; word-break: break-all; }
.report-body code { font-family: var(--mono); font-size: var(--fs-xs); background: var(--surface-2); padding: 1px 5px; border-radius: var(--r-xs); }
.report-body.clamped { max-height: 6.3em; overflow: hidden;
  mask-image: linear-gradient(180deg, #000 60%, transparent);
  -webkit-mask-image: linear-gradient(180deg, #000 60%, transparent); }
.report-acct { color: var(--muted); }
.report .report-more { margin-top: var(--sp-2); }
.report-unread { display: inline-block; width: 8px; height: 8px; border-radius: var(--r-full); background: var(--accent); }
.report-filters { max-width: var(--reportw); margin: 0 auto var(--sp-3); display: flex; flex-wrap: wrap; gap: var(--sp-2); }
/* the only control on the reports page was 27px tall */
.report-filters .chip { min-height: var(--tap); padding: 0 var(--sp-3); display: inline-flex; align-items: center; }

/* ------------------------------------------------------------- toasts --- */
.toasts {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(var(--sp-5) + env(safe-area-inset-bottom));
  display: flex; flex-direction: column; gap: var(--sp-2); z-index: 60; pointer-events: none;
}
.toast {
  background: var(--raised); color: var(--fg); border: 1px solid var(--card-edge);
  border-radius: var(--r-full); padding: var(--sp-2) var(--sp-4); box-shadow: var(--sh-2);
  font-size: var(--fs-sm); max-width: min(90vw, 460px);
}
.toast[data-tone="bad"] { border-color: var(--danger); }

/* ================================================================ media == */

/* safe area applies at every width: iPad 9th/10th landscape is 1080px wide,
   which is >=1100-ish territory and was getting no inset at all */
body[data-view="mail"] .pane { padding-bottom: env(safe-area-inset-bottom); }

@media (max-width: 1099px) {
  .scrim { display: block; }
  .pane-head .nav-toggle { display: grid; }
  /* without this there was no way to change mailbox while reading on a phone
     or on iPad portrait -- both nav toggles live in the list pane, which is
     hidden in the read screen */
  body[data-screen="read"] .read-head .nav-toggle { display: grid; }
}
@media (max-width: 779px) {
  body[data-screen="list"] .pane-read { display: none; }
  body[data-screen="read"] .pane-list { display: none; }
  .read-head .back { display: grid; }
  .mail { padding: var(--sp-4) var(--sp-3) var(--sp-6); }
  .mail-seg { margin-left: 0; }
  .reports-wrap { padding: var(--sp-3); }
  .pane-titles p { display: none; }
  /* the list is the whole screen here; a 780px-wide subject line is unreadable */
  .rows { padding: var(--sp-2) var(--sp-3); }
}
/* >=780 is two panes.  These are not height-gated: the grid, the back arrow
   and the drawer button must behave the same on a 390-tall laptop window as on
   a tablet.  Only the folder strip's wrapping is gated, because in landscape it
   would stack seven chips into a 300px-tall column (measured, 844x390). */
@media (min-width: 780px) {
  .main { grid-template-columns: var(--list) minmax(0, 1fr); }
  .read-head .back { display: none !important; }
}
/* At >=1100 the strip is 355-380px wide and only ever showed 3.3 of 7 folders:
   wrap instead of hiding them behind a horizontal scroll.  Below that the pane
   is 320px and wrapping stacks them three rows deep (152px measured), which
   costs more than it reveals -- there the strip keeps scrolling. */
@media (min-width: 1100px) and (min-height: 521px) {
  .folders {
    flex-wrap: wrap; overflow-x: visible;
    mask-image: none; -webkit-mask-image: none;
  }
}
/* 780-1099 is iPad portrait and small laptops.  The reader had 44% of the screen
   while the list had 56%, and both panes showed the same drawer button. */
@media (min-width: 780px) and (max-width: 1099px) {
  .main { grid-template-columns: 320px minmax(0, 1fr); }
  .read-head .nav-toggle { display: none; }
}
@media (min-width: 1100px) {
  .shell { grid-template-columns: var(--rail) minmax(0, 1fr); }
  .nav { position: static; transform: none; width: auto; inset: auto; z-index: auto; }
  .scrim, .nav-toggle { display: none !important; }
  .pane-reports { grid-column: 1 / -1; }
}
@media (min-width: 1200px) {
  :root { --rail: 248px; --list: 380px; }
}

/* Phone held sideways: 192px of fixed chrome out of 390px left 2.6 rows.  The
   previous attempt only lowered min-height on containers whose content already
   set the height, so nothing moved -- the content has to shrink too.  This sits
   last on purpose: it has to win over the width breakpoints, which all match on
   an 844x390 phone as well (they once re-wrapped the folder strip and turned the
   filter bar into a 300px-tall column of stacked chips). */
@media (max-height: 520px) and (orientation: landscape) {
  .pane-head { min-height: 0; padding: 4px var(--sp-3); }
  .pane-head .btn-icon { min-height: 36px; min-width: 36px; }
  .pane-titles h1 { font-size: var(--fs-md); }
  .pane-titles p { display: none; }
  /* one line: the folder strip scrolls, the search box keeps the right side */
  .filters { flex-direction: row; flex-wrap: nowrap; align-items: center; padding: 4px var(--sp-3); gap: var(--sp-2); }
  .folders {
    flex: 1 1 auto; min-width: 0; margin: 0; padding: 0;
    flex-wrap: nowrap; overflow-x: auto;
    mask-image: linear-gradient(90deg, #000 calc(100% - 20px), transparent);
    -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 20px), transparent);
  }
  .folders .chip { min-height: 36px; padding: 0 var(--sp-2); font-size: var(--fs-xs); }
  .searchrow { flex: 0 0 42%; min-width: 140px; min-height: 40px; padding-right: 0; }
  .searchrow input { min-height: 36px; }
  .searchrow .q-all { min-height: 36px; padding: 0 var(--sp-2); }
  .scopeline { display: none; }
  .read-head { min-height: 0; padding: 4px var(--sp-3); }
  .read-head .btn-icon { min-height: 36px; min-width: 36px; }
  .pane-foot { padding: 4px; }
  .pane-foot .btn { min-height: 36px; }
}
