/* V Mail — styles (SPEC section 12)
   Quiet, flat, functional: system font, one accent, hairline separators instead of
   boxes, no colour-coded chips. Light + dark via prefers-color-scheme. */

/* The headline face (SPEC 53.5), served from the app itself: Funnel Display,
   one variable file per script range (latin 17 KB, latin-ext 9.5 KB), under
   the SIL Open Font License in fonts/OFL.txt. The pages preload the latin
   file, and swap means a title is never held back waiting for it. */
@font-face {
  font-family: "Funnel Display";
  font-style: normal;
  font-weight: 300 800;
  font-display: swap;
  src: url("/static/fonts/funnel-display-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Funnel Display";
  font-style: normal;
  font-weight: 300 800;
  font-display: swap;
  src: url("/static/fonts/funnel-display-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  --font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", system-ui, sans-serif;
  /* Mail text, as opposed to --font's UI chrome: each platform's face drawn
     for body copy (San Francisco, then Segoe UI Variable Text) with Arial --
     the one every machine has -- last. Kept in sync with READ_FONT in app.js,
     which has to repeat it as a literal for the message iframe. */
  --font-read: -apple-system, BlinkMacSystemFont, "Segoe UI Variable Text", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --bg: #ffffff;
  --bg-2: #f7f7f8;
  --bg-3: #eeeef0;
  --card: #ffffff;
  --text: #17171a;
  --text-2: #66666d;
  --text-3: #9a9aa1;
  --hair: rgba(0, 0, 0, 0.09);
  --hair-soft: rgba(0, 0, 0, 0.055);
  --hover: rgba(0, 0, 0, 0.035);
  --sel: rgba(27, 124, 245, 0.1);
  /* Brand blue, from the 2A design handoff -- the source of truth for the mark
     and for every accented control, so the two are one colour. */
  --accent: #1b7cf5;
  --accent-text: #1268e0;
  --accent-bg: rgba(27, 124, 245, 0.1);
  --danger: #e5352b;
  --danger-bg: rgba(229, 53, 43, 0.1);
  --warn: var(--accent-2);
  --warn-bg: var(--accent-2-bg);
  --ok: #2aa952;
  --ok-bg: rgba(42, 169, 82, 0.12);
  --purple: #8e5be6;
  --purple-bg: rgba(142, 91, 230, 0.1);
  --shadow: 0 14px 44px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.06);
  /* Concentric radii: an inner control's radius is the outer one minus the
     padding between them, so nested corners share a centre. */
  --radius: 8px;
  --radius-sm: 6px;
  --radius-lg: 14px;
  --radius-xl: 18px;
  --topbar-h: 50px;
  /* Motion, on one scale (SPEC 38.5). Four durations, two curves, and every
     transition and animation in this file is written in these tokens. A raw
     millisecond or a cubic-bezier anywhere below this block is a bug, and a
     test says so. By role:
       --t-fast   state: hover, colour, a control's opacity
       --t        pop: menus, cards, toasts, the modal, backdrops
       --t-slide  travel: panes, sheets, drawers, folds, and content arriving
                  into any of them
       --t-fade   the opacity layer of a travel. Shorter than the movement, so
                  a thing is fully there before it has finished settling.
     The loops (spin, pulse, shimmer) are indicators, not motion: they keep
     their own periods. */
  --ease: cubic-bezier(0.2, 0.8, 0.2, 1);
  /* Expo-out: fast off the line, long soft landing. What a slide should feel like. */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  /* Tightened for a snappier feel (SPEC 53.5): still long enough for a
     slide to read as a movement, never long enough to wait on. */
  --d-fast: 80ms;
  --d: 120ms;
  --d-fade: 150ms;
  --d-slide: 260ms;
  --t-fast: var(--d-fast) var(--ease);
  --t: var(--d) var(--ease);
  --t-slide: var(--d-slide) var(--ease-out);
  --t-fade: var(--d-fade) var(--ease-out);
  /* The welcome page is the one place where motion is the content (SPEC 62):
     a curtain, words rising out of a mask, a band that runs with the scroll.
     Its tempo is its own, written here once like every other duration. */
  --d-intro: 1100ms;
  --d-stage: 900ms;
  --d-marquee: 34s;
  --d-loop: 5200ms;
  --d-draw: 1600ms;
  --t-stage: var(--d-stage) var(--ease-out);
  --t-loop: var(--d-loop) var(--ease-out);
  --t-draw: var(--d-draw) var(--ease-out);
  /* A phone moves the way iOS does (SPEC 83): a push, a sheet, a drawer or a
     folding bar starts at once and lands long and soft, on the system's curve. */
  --ease-ios: cubic-bezier(0.32, 0.72, 0, 1);
  --d-push: 380ms;
  --t-push: var(--d-push) var(--ease-ios);
  /* How far anything travels while it settles into place. */
  --travel: 8px;
  /* Complementary accent: amber, the opposite of the interface blue on the
     colour wheel. Reserved for "this needs you" -- flags, replies owed,
     high priority -- so it stays rare enough to mean something. */
  --accent-2: #ff9f0a;
  --accent-2-bg: rgba(255, 159, 10, 0.14);
  /* Glass: the navigation and control layer floats over content and lets it
     show through. Content itself never uses these. */
  --glass: rgba(255, 255, 255, 0.62);
  --glass-strong: rgba(255, 255, 255, 0.78);
  --glass-border: rgba(255, 255, 255, 0.55);
  --glass-edge: rgba(0, 0, 0, 0.08);
  --glass-hi: rgba(255, 255, 255, 0.85);
  --glass-blur: 22px;
  /* For surfaces that overlap text -- a floating panel, a sheet, a menu.
     Glass that lets the words underneath bleed through is not glass, it is a
     legibility bug; these keep the blur and the rim but almost no
     transparency. */
  --glass-solid: color-mix(in srgb, var(--bg) 94%, transparent);
  /* The glass stack (SPEC 53): the mark's three sheets are the whole system.
     A cool field is the ground; on it, sheets of glass that grow more solid
     the closer they come to you -- the mailboxes behind, the list in the
     middle, the message you are reading in front. */
  --field: #e9eef6;
  --sheet-back: rgba(255, 255, 255, 0.46);
  --sheet-mid: rgba(255, 255, 255, 0.84);
  --sheet-front: var(--card);
  /* a chosen row or mailbox, pulled forward out of its sheet */
  --sheet-pick: var(--card);
  --sheet-rim: rgba(255, 255, 255, 0.9);
  --sheet-shadow: 0 1px 2px rgba(22, 44, 84, 0.05), 0 18px 44px -30px rgba(22, 44, 84, 0.38);
  --sheet-lift: 0 1px 2px rgba(22, 44, 84, 0.08), 0 6px 18px -8px rgba(22, 44, 84, 0.22);
  --radius-sheet: 22px;
  --gap-sheet: 10px;
  /* Headlines: Funnel Display, shipped with the app (the @font-face above),
     then each platform's own display cut while it loads. */
  --font-display: "Funnel Display", -apple-system, BlinkMacSystemFont, "SF Pro Display", "Segoe UI Variable Display", "Segoe UI", system-ui, sans-serif;
  --sidebar-w: 212px;
  --list-w: 352px;
  /* The panel's column. A plain length-percentage rather than a minmax(), so
     it can be interpolated: the reader gives way as the panel arrives instead
     of the layout snapping and hiding the slide inside the jump. */
  --panel-w: clamp(300px, 34%, 520px);
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
  color-scheme: light dark;
}

/* Theme: the system decides unless Settings says otherwise. data-theme on
   <html> is set from the user's preference (and cached in localStorage so
   the first paint is already right). */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #161618;
    --bg-2: #111113;
    --bg-3: #232326;
    --card: #1c1c1f;
    --text: #f2f2f4;
    --text-2: #9d9da5;
    --text-3: #67676f;
    --hair: rgba(255, 255, 255, 0.09);
    --hair-soft: rgba(255, 255, 255, 0.055);
    --hover: rgba(255, 255, 255, 0.05);
    --sel: rgba(27, 124, 245, 0.2);
    --accent-text: #63a9ff;
    --accent-bg: rgba(27, 124, 245, 0.18);
    --accent-2: #ffb340;
    --accent-2-bg: rgba(255, 179, 64, 0.16);
    --ok: #3ccb66;
    --shadow: 0 18px 50px rgba(0, 0, 0, 0.6), 0 1px 2px rgba(0, 0, 0, 0.5);
    --glass: rgba(28, 28, 32, 0.58);
    --glass-strong: rgba(28, 28, 32, 0.76);
    --glass-border: rgba(255, 255, 255, 0.10);
    --glass-edge: rgba(0, 0, 0, 0.5);
    --glass-hi: rgba(255, 255, 255, 0.14);
    --field: #0c0e12;
    --sheet-front: #1e2026;
    --sheet-pick: #2b2e36;
    --sheet-back: rgba(34, 37, 44, 0.42);
    --sheet-mid: rgba(26, 28, 34, 0.9);
    --sheet-rim: rgba(255, 255, 255, 0.07);
    --sheet-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 18px 44px -26px rgba(0, 0, 0, 0.8);
    --sheet-lift: 0 1px 2px rgba(0, 0, 0, 0.5), 0 6px 18px -8px rgba(0, 0, 0, 0.6);
  }
}
:root[data-theme="dark"] {
  --bg: #161618;
  --bg-2: #111113;
  --bg-3: #232326;
  --card: #1c1c1f;
  --text: #f2f2f4;
  --text-2: #9d9da5;
  --text-3: #67676f;
  --hair: rgba(255, 255, 255, 0.09);
  --hair-soft: rgba(255, 255, 255, 0.055);
  --hover: rgba(255, 255, 255, 0.05);
  --sel: rgba(27, 124, 245, 0.2);
  --accent-text: #63a9ff;
  --accent-bg: rgba(27, 124, 245, 0.18);
  --accent-2: #ffb340;
  --accent-2-bg: rgba(255, 179, 64, 0.16);
  --ok: #3ccb66;
  --shadow: 0 18px 50px rgba(0, 0, 0, 0.6), 0 1px 2px rgba(0, 0, 0, 0.5);
  --glass: rgba(28, 28, 32, 0.58);
  --glass-strong: rgba(28, 28, 32, 0.76);
  --glass-border: rgba(255, 255, 255, 0.10);
  --glass-edge: rgba(0, 0, 0, 0.5);
  --glass-hi: rgba(255, 255, 255, 0.14);
  --field: #0c0e12;
  --sheet-front: #1e2026;
  --sheet-pick: #2b2e36;
  --sheet-back: rgba(34, 37, 44, 0.42);
  --sheet-mid: rgba(26, 28, 34, 0.9);
  --sheet-rim: rgba(255, 255, 255, 0.07);
  --sheet-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 18px 44px -26px rgba(0, 0, 0, 0.8);
  --sheet-lift: 0 1px 2px rgba(0, 0, 0, 0.5), 0 6px 18px -8px rgba(0, 0, 0, 0.6);
}

/* Glass needs something to refract. The field: the brand blue rising from the
   top left and the "needs you" amber settling bottom right, the mark's two
   colours, faint enough never to compete with the mail. */
body::before {
  content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background:
    radial-gradient(70vw 70vh at 8% -14%, color-mix(in srgb, var(--accent) 26%, transparent), transparent 70%),
    radial-gradient(55vw 55vh at 106% 112%, color-mix(in srgb, var(--accent-2) 18%, transparent), transparent 70%);
}

/* The glass recipe, shared by every floating surface: translucent fill, blur
   and saturation on what lies behind, a hairline edge, and a specular
   highlight along the top edge that reads as a lit rim. */
.glass, .topbar, .sidebar, .list-head, .thread-toolbar, .thread-panel, .panel-head,
.modal-card, .sheet, .menu, .suggest, .search-hints, .toast, .preview-bar {
  background: var(--glass);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(180%);
  backdrop-filter: blur(var(--glass-blur)) saturate(180%);
}
.modal-card, .sheet, .menu, .suggest, .search-hints, .toast {
  background: var(--glass-solid);
  border: 1px solid var(--glass-border);
  box-shadow: var(--shadow), inset 0 1px 0 var(--glass-hi);
}
/* Inside a glass surface nothing else is glass: stacking two translucent
   layers only lowers contrast further. */
.thread-panel .panel-head, .modal-card .modal-head, .sheet .sheet-head {
  background: transparent; -webkit-backdrop-filter: none; backdrop-filter: none;
}

/* Reduce Transparency: fall back to solid surfaces, same layout. */
@media (prefers-reduced-transparency: reduce) {
  .glass, .topbar, .sidebar, .list-head, .thread-toolbar, .thread-panel, .panel-head,
  .modal-card, .sheet, .menu, .suggest, .search-hints, .toast, .preview-bar {
    background: var(--bg); -webkit-backdrop-filter: none; backdrop-filter: none;
  }
  .modal { background: color-mix(in srgb, var(--bg) 55%, black); backdrop-filter: none; }
  body::before { display: none; }
}

/* ------------------------------------------------------------------ base */

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  /* No automatic text inflation: Safari reads the prefixed property, Chrome and
     Samsung Internet on Android the plain one -- their "auto-fit" font boosting
     otherwise enlarges some blocks of text and breaks the widths (SPEC 78). */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  overflow: hidden;
}
/* A chosen mailbox tints the interface with its provider's colour (SPEC 63):
   the accent, what is selected and the blooms behind the glass. --tint is a
   registered colour, so a change of mailbox is a short cross-fade rather than
   a jump; the theme's own blues come back once no mailbox tints. */
@property --tint { syntax: "<color>"; inherits: true; initial-value: #1b7cf5; }
:root[data-tint] {
  --accent: var(--tint);
  --accent-text: color-mix(in srgb, var(--tint) 84%, black);
  --accent-bg: color-mix(in srgb, var(--tint) 11%, transparent);
  --sel: color-mix(in srgb, var(--tint) 11%, transparent);
  transition: --tint var(--t-slide);
}
@media (prefers-color-scheme: dark) {
  :root[data-tint]:not([data-theme="light"]) {
    --accent-text: color-mix(in srgb, var(--tint) 58%, white);
    --accent-bg: color-mix(in srgb, var(--tint) 20%, transparent);
    --sel: color-mix(in srgb, var(--tint) 20%, transparent);
  }
}
:root[data-theme="dark"][data-tint] {
  --accent-text: color-mix(in srgb, var(--tint) 58%, white);
  --accent-bg: color-mix(in srgb, var(--tint) 20%, transparent);
  --sel: color-mix(in srgb, var(--tint) 20%, transparent);
}

/* The field is the root's colour and body stays clear, so the blooms drawn
   on body::before sit between the two and actually show. With a background
   on body they were painted over, on every page. */
html { background: var(--field); }
body { background: transparent; }

button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; border: 0; background: none; padding: 0; margin: 0; -webkit-tap-highlight-color: transparent; }
a { color: var(--accent-text); text-decoration: none; }
a:hover { text-decoration: underline; }

.hidden { display: none !important; }
.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;
}
.muted { color: var(--text-2); }
.faint { color: var(--text-3); }
.small { font-size: 12px; }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 6px; }
input:focus-visible, textarea:focus-visible, select:focus-visible { outline: none; }

/* Thin scrollbars. Firefox gets the standard property; Chrome and Safari need
   the -webkit- pseudo-elements, and styling the thumb alone leaves the default
   17px-wide track, so the width is set explicitly too. */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--hair) transparent;
}
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--hair);
  border-radius: 999px;
  /* The border is transparent padding: it keeps the visible thumb at 6px while
     leaving a comfortable grab target. */
  border: 1px solid transparent;
  background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover { background: var(--text-3); background-clip: padding-box; }
::-webkit-scrollbar-corner { background: transparent; }

svg.icon {
  width: 18px; height: 18px;
  stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round;
  fill: none; flex: none; display: block;
}
svg.icon.sm { width: 15px; height: 15px; }
svg.icon.xs { width: 12px; height: 12px; }

/* --------------------------------------------------------------- buttons */

.btn {
  display: inline-flex; align-items: center; gap: 6px;
  height: 30px; padding: 0 11px;
  border-radius: 999px;
  background: var(--bg-3); color: var(--text);
  font-size: 13px; font-weight: 500; white-space: nowrap;
  transition: background var(--t-fast), opacity var(--t-fast), transform var(--t-fast), color var(--t-fast), box-shadow var(--t-fast);
  user-select: none;
}
.btn:hover { background: color-mix(in srgb, var(--bg-3) 78%, var(--text) 8%); }
.btn:active { transform: scale(0.98); }
.btn:disabled { opacity: 0.5; cursor: default; transform: none; }
/* Tinted glass: the one control per screen that carries the accent. The
   inset highlight is the specular rim; the coloured shadow is its glow. */
.btn.primary {
  /* The handoff's Compose paint: #4F9DFF -> #1268E0, both on the brand blue. */
  background: linear-gradient(180deg, #4f9dff 0%, #1268e0 100%);
  color: #fff;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.45), 0 4px 12px rgba(11, 91, 211, 0.5);
}
/* the same paint in a chosen mailbox's colour (SPEC 63) */
:root[data-tint] .btn.primary {
  background: linear-gradient(180deg, color-mix(in srgb, var(--tint) 74%, white) 0%, color-mix(in srgb, var(--tint) 86%, black) 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.45), 0 4px 12px color-mix(in srgb, var(--tint) 50%, transparent);
}
.btn.primary:hover { filter: brightness(1.06); }
.btn.primary:active { transform: scale(0.97); filter: brightness(0.96); }
.btn.ghost { background: transparent; color: var(--accent-text); }
.btn.ghost:hover { background: var(--accent-bg); }
.btn.quiet { background: transparent; color: var(--text-2); }
.btn.quiet:hover { background: var(--hover); color: var(--text); }
.btn.danger { color: var(--danger); background: transparent; }
.btn.danger:hover { background: var(--danger-bg); }
.btn.sm { height: 26px; padding: 0 9px; font-size: 12px; }
.btn.busy { position: relative; color: transparent !important; pointer-events: none; }
.btn.busy::after {
  /* centred on both axes whatever the pill's size or label: inset 0 + auto margins */
  content: ""; position: absolute; inset: 0; margin: auto; width: 14px; height: 14px; border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.5); border-top-color: #fff;
  animation: spin 0.8s linear infinite;
}
.btn.busy:not(.primary)::after { border-color: var(--hair); border-top-color: var(--text-2); }

.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border-radius: var(--radius-sm);
  color: var(--text-2);
  transition: background var(--t), color var(--t);
  flex: none;
}
.icon-btn:hover { background: var(--hover); color: var(--text); }
.icon-btn.active { color: var(--accent-text); }
.icon-btn.flagged { color: var(--accent-2); }
.icon-btn:disabled { opacity: 0.35; cursor: default; background: none; }
/* A touch screen has no hover, but iOS keeps :hover on whatever was tapped last
   until the next tap elsewhere, so a button stayed lit in its hover box after
   its work was done (SPEC 94). There the hovers look like the resting state;
   a press still shows through :active. Written here, right after the base
   rules, so a component's own look further down still wins. */
@media (hover: none) {
  .btn:hover { background: var(--bg-3); }
  .btn.quiet:hover { background: transparent; color: var(--text-2); }
  .btn.ghost:hover, .btn.danger:hover { background: transparent; }
  .btn.primary:hover { filter: none; }
  .icon-btn:hover { background: transparent; color: var(--text-2); }
  .icon-btn.active:hover { color: var(--accent-text); }
  .icon-btn.flagged:hover { color: var(--accent-2); }
}

@keyframes spin { to { transform: rotate(360deg); } }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
@keyframes shimmer { 0% { background-position: -400px 0; } 100% { background-position: 400px 0; } }
/* Pop: menus, cards, toasts, the modal. A short lift and a breath of scale. */
@keyframes rise-in { from { opacity: 0; transform: translateY(6px) scale(0.985); } to { opacity: 1; transform: none; } }
/* a list that drops from its button, and folds back into it (SPEC 57) */
@keyframes drop-in { from { opacity: 0; transform: translateY(-6px) scaleY(0.94); } to { opacity: 1; transform: none; } }
@keyframes drop-up { from { opacity: 0; transform: translateY(6px) scaleY(0.94); } to { opacity: 1; transform: none; } }
@keyframes fold-away { from { opacity: 1; transform: none; } to { opacity: 0; transform: translateY(-4px) scale(0.98); } }
/* Fade: backdrops, and the opacity layer of everything that travels. */
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
/* Settle: content arriving into a pane comes up by --travel on the slide curve
   while it fades on the shorter fade -- the same two layers, on the same two
   tokens, as the folds and the thread panel. It is the one entrance keyframe
   left. The panes themselves are transitions, not keyframes: an element that
   stays in the tree and gets a class can travel both ways on its own. */
@keyframes settle { from { transform: translateY(var(--travel)); } to { transform: none; } }
.arrive { animation: settle var(--t-slide) both, fade-in var(--t-fade) both; }

/* ------------------------------------------------------------- app shell */

.app {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  /* the screen's height in the interface's own units: divided by the scale (SPEC 70) */
  height: 100vh; height: calc(100dvh / var(--ui-zoom));
  width: 100%;
  overflow: hidden;
}

.topbar {
  display: flex; align-items: center; gap: 8px;
  height: calc(var(--topbar-h) + var(--safe-top));
  padding: var(--safe-top) 12px 0 calc(12px + var(--safe-left));
  border-bottom: 1px solid var(--hair);
  position: relative; z-index: 30;
  box-shadow: inset 0 1px 0 var(--glass-hi);
}

/* The lockup: the mark, then the wordmark with SECURE INBOX under it, the way
   the brand sheet sets it. The mark is an SVG carrying its own plate, so there
   is nothing behind it on either theme. */
.brand {
  padding: 0 6px; white-space: nowrap; color: var(--text);
  display: flex; align-items: center; gap: 10px;
  min-width: calc(var(--sidebar-w) - 24px);
}
.brand .logo {
  width: 30px; height: 30px; display: block; flex: none;
  border-radius: 8px;                     /* matches the squircle, so the glow sits right */
  box-shadow: 0 4px 12px color-mix(in srgb, var(--accent) 30%, transparent);
}
.brand-text { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; line-height: 1; }
/* The wordmark is a wordmark: Outlook and Gmail both give the product name real
   size next to the icon, and it is the first thing that says which app this is. */
.brand .name { font-weight: 600; font-size: 20px; letter-spacing: -0.5px; }
.brand .tag {
  font-size: 9px; font-weight: 600; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--text-3);
}
/* In the bar the name carries it alone; the strapline belongs on the sign-in
   card, where there is room for a lockup. */
.topbar .brand .tag { display: none; }

.search {
  flex: 1; display: flex; align-items: center; gap: 8px;
  height: 34px; max-width: 620px; margin: 0 auto; padding: 0 10px;
  border-radius: 8px;
  background: var(--bg-3); color: var(--text-2);
  transition: box-shadow var(--t), background var(--t);
  position: relative;
}
.search:focus-within { background: var(--bg); box-shadow: 0 0 0 1.5px var(--accent); }
.search input {
  flex: 1; min-width: 0; height: 100%; border: 0; background: transparent;
  color: var(--text); font-size: 13.5px;
}
.search input::placeholder { color: var(--text-3); }
.search .kbd {
  font-size: 11px; color: var(--text-3);
  border: 1px solid var(--hair); border-radius: 4px; padding: 0 5px; line-height: 17px;
}
.search .clear { width: 22px; height: 22px; }
.search-hints {
  position: absolute; top: calc(100% + 6px); left: 0; right: 0;
  background: var(--card); border: 1px solid var(--hair); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 8px 10px;
  font-size: 12px; color: var(--text-2); z-index: 40;
  display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
}
.search-hints code {
  font-family: var(--mono); font-size: 11px;
  background: var(--bg-3); border-radius: 4px; padding: 1px 5px; color: var(--text); cursor: pointer;
}
.search-hints code:hover { background: var(--accent-bg); color: var(--accent-text); }

.topbar-right { display: flex; align-items: center; gap: 4px; padding-right: var(--safe-right); }

.status-chip {
  display: inline-flex; align-items: center; gap: 6px;
  height: 26px; padding: 0 9px; border-radius: 999px;
  font-size: 12px; color: var(--text-2); white-space: nowrap;
}
.status-chip.off { opacity: 0.55; }
.status-chip .icon { color: var(--text-3); }
.status-chip.alert { color: var(--danger); background: var(--danger-bg); }
.status-chip.alert .icon { color: var(--danger); }

.dot { width: 7px; height: 7px; border-radius: 50%; background: var(--text-3); flex: none; transition: background var(--t); }
.dot.idle { background: var(--ok); }
.dot.syncing { background: var(--accent); animation: pulse 1s ease-in-out infinite; }
.dot.error { background: var(--danger); }
.dot.off { background: var(--text-3); }
#syncBtn .label { display: inline; }
/* Calendar sits beside Refresh (SPEC 58): the same quiet button, lit while it is open */
#calendarBtn { gap: 6px; }
#calendarBtn.active { background: var(--accent-bg); color: var(--accent-text); }
/* Refresh: an icon that turns while it is fetching, so the button reads as
   "pull the mail now" at a glance -- on a phone it was a 7px dot with no label
   at all. The dot stays only for trouble (an error, a stopped worker); green
   for "fine" was noise. */
#syncBtn { position: relative; gap: 6px; }
#syncBtn.busy .icon { animation: spin 0.8s linear infinite; }
#syncBtn .dot { display: none; }
#syncBtn .dot.error, #syncBtn .dot.off { display: block; position: absolute; top: 6px; right: 6px; width: 6px; height: 6px; }

/* ---------------------------------------------------------------- panes */

.panes {
  display: grid;
  grid-template-columns: var(--sidebar-w) var(--list-w) minmax(0, 1fr);
  min-height: 0;
  position: relative;
}
.sidebar, .list-pane, .thread-pane { min-height: 0; min-width: 0; display: flex; flex-direction: column; overflow: hidden; }

/* --------------------------------------------------------------- sidebar */

.sidebar {
  border-right: 1px solid var(--hair);
  padding: 10px 10px calc(12px + var(--safe-bottom)) calc(10px + var(--safe-left));
  overflow-y: auto; overscroll-behavior: contain;
}
.side-section { margin-top: 18px; }
.side-section:first-child { margin-top: 2px; }
/* Section labels in sentence case, not tracked capitals: a label is quiet
   furniture, and shouted small caps are the first thing that makes a tool look
   generated rather than designed. The same rule holds for every label below. */
.side-title {
  font-size: 12px; font-weight: 600;
  color: var(--text-3); padding: 4px 10px 6px;
  display: flex; align-items: center; justify-content: space-between;
}
.side-title button { font-size: 11px; color: var(--text-2); font-weight: 500; text-transform: none; letter-spacing: 0; }
.side-title button:hover { color: var(--accent-text); }
.side-item {
  display: flex; align-items: center; gap: 9px;
  width: 100%; height: 30px; padding: 0 10px;
  border-radius: var(--radius-sm);
  color: var(--text); font-size: 13px; text-align: left;
  transition: background var(--t); overflow: hidden;
}
.side-item:hover { background: var(--hover); }
.side-item.active { background: var(--sel); color: var(--accent-text); font-weight: 500; }
.side-item .icon { color: var(--text-2); }
.side-item.active .icon { color: var(--accent-text); }
.side-item .label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.side-item .count { font-size: 11.5px; color: var(--text-3); font-variant-numeric: tabular-nums; }
.side-item.active .count { color: var(--accent-text); }
.side-item .err { color: var(--danger); }
.side-item .swatch { width: 8px; height: 8px; border-radius: 3px; flex: none; background: var(--accent); }

/* Mailboxes: the built-in shelves drag to reorder (SPEC 43). The grip only
   shows up on hover -- it is a rearranging affordance, not something to look
   at while reading the list -- and the row it belongs to shrinks to make
   room rather than the grip overlapping the label. */
.side-drag { display: flex; align-items: center; }
.side-drag .side-grip {
  display: flex; align-items: center; justify-content: center;
  width: 0; overflow: hidden; flex: none; color: var(--text-3);
  cursor: grab; transition: width var(--t-fast), opacity var(--t-fast);
  opacity: 0;
}
.side-drag:hover .side-grip, .side-drag.dragging .side-grip { width: 16px; opacity: 1; }
.side-drag .side-item { flex: 1; min-width: 0; }
.side-drag.dragging { opacity: 0.5; }
.side-drag.drag-over { box-shadow: inset 0 2px 0 var(--accent); border-radius: var(--radius-sm); }
.side-item.logout { color: var(--text-2); margin-top: 8px; }
.side-item.logout:hover { color: var(--danger); }
.side-item.logout .icon { color: inherit; }
.side-empty { padding: 4px 10px; font-size: 12px; color: var(--text-3); line-height: 1.45; }
.side-foot { margin-top: auto; padding: 16px 10px 0; font-size: 11.5px; color: var(--text-3); line-height: 1.5; }
.side-identity { color: var(--text-2); font-weight: 500; }

.scrim {
  position: fixed; inset: 0; background: rgba(0, 0, 0, 0.3); z-index: 25;
  opacity: 0; pointer-events: none; transition: opacity var(--t);
}
.app.sidebar-open .scrim { opacity: 1; pointer-events: auto; }

/* ------------------------------------------------------------ list pane */

.list-pane { border-right: 1px solid var(--hair); background: var(--bg); position: relative; }
.list-head {
  display: flex; align-items: center; gap: 8px;
  height: 44px; padding: 0 16px;
  border-bottom: 1px solid var(--hair-soft);
  flex: none;
}
.list-head h2 {
  margin: 0; font-size: 15px; font-weight: 600; letter-spacing: -0.2px;
  flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.list-head .count { font-size: 12px; color: var(--text-3); font-variant-numeric: tabular-nums; }
.list-head .filter-chip {
  display: inline-flex; align-items: center; gap: 4px;
  height: 22px; padding: 0 4px 0 8px; border-radius: 999px;
  background: var(--accent-bg); color: var(--accent-text); font-size: 12px; max-width: 160px;
}
.list-head .filter-chip span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.list-head .filter-chip button { display: inline-flex; color: inherit; width: 18px; height: 18px; align-items: center; justify-content: center; border-radius: 50%; }
.list-head .filter-chip button:hover { background: color-mix(in srgb, var(--accent) 20%, transparent); }

.list {
  flex: 1; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
  padding-bottom: var(--safe-bottom);
}

.row {
  display: grid;
  grid-template-columns: 16px minmax(0, 1fr) auto;
  grid-template-rows: auto auto auto;
  column-gap: 8px; row-gap: 2px;
  padding: 11px 16px 11px 10px;
  border-bottom: 1px solid var(--hair-soft);
  cursor: pointer; transition: background var(--t);
  min-height: 44px; position: relative; text-align: left; width: 100%; align-items: start;
}
.row { transition: background var(--t-fast); }
.row:hover { background: var(--hover); }
.row.selected { background: var(--sel); box-shadow: inset 2px 0 0 var(--accent); }
.row .unread-dot { grid-row: 1 / span 3; width: 7px; height: 7px; border-radius: 50%; margin-top: 7px; background: transparent; }
.row.unread .unread-dot { background: var(--accent); }
.row .from {
  font-weight: 500; font-size: 13.5px; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  display: flex; align-items: center; gap: 6px; min-width: 0;
}
.row.unread .from { font-weight: 600; }
.row .from .name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.row .date {
  font-size: 12px; color: var(--text-3); white-space: nowrap; font-variant-numeric: tabular-nums;
  display: flex; align-items: center; gap: 5px;
}
.row.unread .date { color: var(--text-2); }
.row .subject {
  grid-column: 2 / span 2; font-size: 13.5px; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  display: flex; align-items: center; gap: 6px; min-width: 0;
}
.row.unread .subject { font-weight: 500; }
.row .subject .text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.row .snippet {
  grid-column: 2 / span 2; font-size: 12.5px; color: var(--text-2);
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical;
  line-height: 1.4;
}
.row .snippet mark, .row .snippet .hl { background: rgba(255, 214, 10, 0.4); color: inherit; border-radius: 3px; padding: 0 1px; }
.row .meta {
  grid-column: 2 / span 2;
  display: flex; flex-wrap: wrap; align-items: center; gap: 0 10px;
  margin-top: 2px; min-height: 0;
  font-size: 11.5px; color: var(--text-3);
}
.row .meta:empty { display: none; }
.row .meta .mark { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 160px; }
.row .meta .mark.accent { color: var(--accent-2); font-weight: 500; }
.row .meta .mark.warn { color: var(--warn); font-weight: 500; }
/* Settled: nothing was asked of you, or you have answered (SPEC 46). */
.row .meta .mark.ok { color: var(--ok); }
.row .meta button.mark.link { background: none; padding: 0; color: var(--text-3); }
.row .meta button.mark.link:hover { color: var(--accent-text); }
.thread-count {
  font-size: 11px; color: var(--text-3); font-variant-numeric: tabular-nums;
  border: 1px solid var(--hair); border-radius: 4px; padding: 0 4px; line-height: 15px; flex: none;
}
.row .flag-mark { color: var(--accent-2); }
.row .clip { color: var(--text-3); }

/* chips: kept for the places that still use them (related reasons, compose), one neutral look */
.chip {
  display: inline-flex; align-items: center; gap: 4px;
  height: 20px; padding: 0 8px; border-radius: 999px;
  font-size: 11.5px; font-weight: 500;
  background: var(--bg-3); color: var(--text-2);
  white-space: nowrap; max-width: 200px; overflow: hidden; text-overflow: ellipsis; line-height: 20px; flex: none;
}
.chip.cat, .chip.project, .chip.supplier { background: var(--bg-3); color: var(--text-2); }
.chip.tag::before { content: "#"; opacity: 0.6; }
.chip.priority { color: var(--warn); background: var(--warn-bg); }
.chip.reply { color: var(--accent-text); background: var(--accent-bg); }
.chip.md { height: 22px; font-size: 12px; padding: 0 9px; line-height: 22px; }
.chip.clickable { cursor: pointer; }
.chip.clickable:hover { background: var(--hover); color: var(--text); }

.pill {
  display: inline-flex; align-items: center; gap: 6px;
  height: 22px; padding: 0 9px; border-radius: 999px;
  font-size: 12px; font-weight: 500; background: var(--bg-3); color: var(--text-2);
}
.pill::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.pill.waiting_on_us { color: var(--warn); }
.pill.waiting_on_them { color: var(--accent-text); }
.pill.closed { color: var(--ok); }
.pill.info { color: var(--text-2); }

.load-more { display: flex; justify-content: center; padding: 12px; }

/* ------------------------------------------------------------- empty / skeleton */

.empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
  padding: 48px 24px; color: var(--text-3); text-align: center; font-size: 13px;
  height: 100%; min-height: 200px;
}
.empty .icon { width: 34px; height: 34px; stroke-width: 1.2; opacity: 0.5; margin-bottom: 4px; }
.empty strong { color: var(--text-2); font-weight: 500; }

.skeleton {
  background: linear-gradient(90deg, var(--bg-3) 25%, var(--hover) 50%, var(--bg-3) 75%);
  background-size: 800px 100%; animation: shimmer 1.4s linear infinite;
  border-radius: 6px; height: 12px;
}
.skel-row { padding: 12px 16px; border-bottom: 1px solid var(--hair-soft); display: grid; gap: 7px; }
.skel-row .skeleton:nth-child(1) { width: 45%; }
.skel-row .skeleton:nth-child(2) { width: 80%; }
.skel-row .skeleton:nth-child(3) { width: 65%; height: 10px; }
.skel-block { padding: 24px 32px; display: grid; gap: 10px; }
.skel-block .skeleton:nth-child(1) { width: 60%; height: 18px; }
.skel-block .skeleton:nth-child(2) { width: 40%; }
.skel-block .skeleton:nth-child(3) { width: 95%; height: 90px; }
.skel-block .skeleton:nth-child(4) { width: 90%; }
.skel-block .skeleton:nth-child(5) { width: 70%; }

/* ---------------------------------------------------------- thread pane */

.thread-pane { position: relative; background: var(--bg); }

.thread-toolbar {
  display: flex; align-items: center; gap: 2px;
  height: 44px; padding: 0 12px;
  border-bottom: 1px solid var(--hair-soft);
  flex: none;
}
.thread-toolbar .spacer { flex: 1; }
.thread-toolbar .tb-sep { width: 1px; height: 18px; background: var(--hair); margin: 0 8px; }
.thread-toolbar .btn { gap: 6px; }
.thread-toolbar .btn .label { display: inline; }

/* the one prominent control on the right */
/* Blue in both states, matching Compose: this is the one control the toolbar
   is meant to advertise. Open vs closed is carried by the inset ring and the
   pressed shade rather than by turning the button grey. */
.thread-btn {
  background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 88%, white) 0%, var(--accent) 55%, color-mix(in srgb, var(--accent) 88%, black) 100%);
  color: #fff; font-weight: 500;
  border: 1px solid transparent;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.45), 0 4px 14px color-mix(in srgb, var(--accent) 35%, transparent);
}
.thread-btn .count {
  min-width: 18px; height: 18px; padding: 0 5px; border-radius: 999px;
  background: rgba(255, 255, 255, 0.22); color: #fff;
  font-size: 11px; font-weight: 600; font-variant-numeric: tabular-nums;
  display: inline-flex; align-items: center; justify-content: center;
}
.thread-btn:hover { filter: brightness(1.06); }
.thread-btn.active { filter: brightness(0.92); box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.45); }
.thread-btn.active:hover { filter: brightness(0.88); }

/* reader: the message on the left, the thread panel in the right third when open */
/* A custom property has to be registered before a browser will interpolate it;
   without this the column would jump and the panel would slide into a gap that
   was already there. */
@property --panel-size {
  syntax: '<length-percentage>';
  inherits: false;
  initial-value: 0px;
}

.reader {
  flex: 1; min-height: 0;
  --panel-size: 0px;
  display: grid; grid-template-columns: minmax(0, 1fr) var(--panel-size);
  transition: --panel-size var(--t-slide);
  position: relative;
}
.thread-pane.panel-open .reader { --panel-size: var(--panel-w); }

.thread-scroll {
  min-height: 0; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
  padding: 0 0 calc(32px + var(--safe-bottom));
}

.reader-head {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 22px 32px 6px;
}
/* Everything the reader shows -- head, notices, the message -- is one block,
   built fresh for each selection, and it arrives with .arrive. The panel's
   head and body get the same class at the same moment, so a message and its
   thread come in together rather than the reader settling while its column is
   still being squeezed. */
.reader-inner { min-height: 100%; }
.reader-head h1 {
  margin: 0; flex: 1; min-width: 0;
  font-size: 20px; font-weight: 600; letter-spacing: -0.3px; line-height: 1.3;
  overflow-wrap: anywhere;
}
.reader-nav { display: flex; align-items: center; gap: 2px; flex: none; color: var(--text-3); margin-top: 1px; }
.reader-nav .pos { font-size: 12px; font-variant-numeric: tabular-nums; padding: 0 4px; }
.reader-nav .icon-btn { width: 28px; height: 28px; }

/* --------------------------------------------------------- thread panel */

/* The panel is a fold on its side, and it works the way the others do: the
   element stays put, a class moves, and a transition does the rest.
   Two layers, exactly as in SPEC 38.3 -- the track opens and the panel travels
   into it. Animating only the panel was the mistake: the column snapped to full
   width in one frame, and a slide into a gap that is already there is a slide
   nobody sees. */
.thread-panel {
  /* Taken out of the grid and pinned to the right edge at a fixed width. As a
     grid item its width *was* the column, so "translateX(100%)" meant a
     hundred per cent of nothing and the panel unfolded in place instead of
     arriving. Pinned, it keeps its size while the column makes room for it, and
     the two layers read as one movement: the reader gives way, the panel comes
     in over the space. */
  position: absolute; top: 0; right: 0; bottom: 0;
  width: var(--panel-w);
  display: flex;
  min-height: 0; min-width: 0;
  flex-direction: column;
  overflow: hidden;
  background: var(--bg);
  border-left: 1px solid var(--hair);
  transform: translateX(100%);
  opacity: 0;
  visibility: hidden;
  transition: transform var(--t-slide), opacity var(--t-fade), visibility 0s linear var(--d-slide);
}
.thread-pane.panel-open .thread-panel {
  transform: none; opacity: 1; visibility: visible;
  transition: transform var(--t-slide), opacity var(--t-fade), visibility 0s;
}
/* The slide is for a gesture: the Thread button, t, the close cross. When the
   panel is open because a message was selected and the reader is being drawn
   around it, it is simply there -- the class lands under .still, with the
   transitions off for that one frame, and the contents arrive with the
   message instead. Two things moving at once, one of them reflowing the
   other's text, was what made the window feel wrong. */
.thread-pane.still .reader, .thread-pane.still .thread-panel { transition: none; }
/* Clip, so nothing draws outside the reading area on the way in or out. */
.reader { overflow: hidden; }

/* There is no closing case any more. A transition runs both ways on its own,
   which is the whole reason for preferring one over a pair of keyframes: the
   panel leaves by the way it came without a second rule, a class, or a timer to
   take it back down. */
.panel-head {
  display: flex; align-items: center; gap: 8px;
  height: 44px; padding: 0 8px 0 16px;
  border-bottom: 1px solid var(--hair-soft);
  flex: none;
}
.panel-title { flex: 1; min-width: 0; display: flex; align-items: baseline; gap: 8px; }
.panel-title strong { font-size: 13px; font-weight: 600; }
.panel-title .count { font-size: 12px; color: var(--text-3); }
.panel-scroll { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding-bottom: calc(24px + var(--safe-bottom)); }
.panel-section { padding: 6px 0 2px; }
.panel-section h3, .related h3 {
  margin: 12px 16px 6px;
  font-size: 12px; font-weight: 600;
  color: var(--text-3);
  display: flex; align-items: center; gap: 6px;
}

/* The thread, literally: one vertical line the messages hang on, oldest at
   the top. Avatars sit on the line and mask it, so it reads as passing behind
   them; the current message gets the accent ring. */
.timeline { display: flex; flex-direction: column; position: relative; padding: 4px 0; }
.timeline::before {
  content: ""; position: absolute; left: 29px; top: 18px; bottom: 18px; width: 2px;
  background: linear-gradient(180deg, transparent, var(--hair) 10%, var(--hair) 90%, transparent);
  border-radius: 1px;
}
.tl-item {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 10px; align-items: start;
  width: 100%; text-align: left;
  padding: 8px 16px;
  position: relative;
  transition: background var(--t-fast);
}
.tl-item:hover { background: var(--hover); }
.tl-item.current { background: var(--sel); }
.tl-item .avatar { position: relative; z-index: 1; box-shadow: 0 0 0 3px var(--bg); }
.tl-item.current .avatar { box-shadow: 0 0 0 3px var(--bg), 0 0 0 5px var(--accent); }
.tl-item.unread .name { font-weight: 600; }
.tl-item.unread .avatar::after {
  content: ""; position: absolute; right: -2px; top: -2px; width: 8px; height: 8px;
  border-radius: 50%; background: var(--accent); box-shadow: 0 0 0 2px var(--bg);
}
.tl-item .tl-open { opacity: 0; transition: opacity var(--t-fast); }
.tl-item:hover .tl-open, .tl-item.current .tl-open, .tl-item:focus-within .tl-open { opacity: 1; }
.tl-summary {
  grid-column: 2 / span 2; font-size: 12.5px; color: var(--text-2); line-height: 1.5;
  padding: 4px 0 2px; animation: rise-in var(--t);
}
.tl-summary .tl-actions { display: flex; gap: 6px; margin-top: 6px; }
.tl-main { min-width: 0; }
.tl-top { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.tl-top .name { flex: 1; min-width: 0; font-size: 13px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tl-top .date { font-size: 11.5px; color: var(--text-3); white-space: nowrap; font-variant-numeric: tabular-nums; }
.tl-snippet { font-size: 12.5px; color: var(--text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-top: 1px; }
.tl-marks { display: flex; gap: 4px; color: var(--text-3); padding-top: 3px; }
.tl-marks .flag-mark { color: var(--accent-2); }

.card { margin: 12px 16px 6px; border-radius: var(--radius); background: var(--card); border: 1px solid var(--hair); }
.preview-card { padding: 12px 14px; }
/* The head has to survive a 300px drawer. Both labels keep to one line and the
   status pill drops to its own row rather than breaking "Waiting on us" across
   two lines, which is what made the card look crumpled. */
.preview-card .card-head {
  display: flex; align-items: center; gap: 6px 8px; margin-bottom: 6px; flex-wrap: wrap;
}
.preview-card .card-head .title {
  font-size: 12px; font-weight: 600;
  color: var(--text-3); display: flex; align-items: center; gap: 5px; white-space: nowrap;
}
/* Smaller than a standalone pill: it shares a 300px row with the label and the
   refresh button, and at the full size it wrapped "Waiting on us" onto two
   lines and pushed the head to double height. */
.preview-card .card-head .pill {
  white-space: nowrap; height: 19px; padding: 0 8px; font-size: 11px; gap: 5px;
}
.preview-card .card-head .pill::before { width: 5px; height: 5px; }
.preview-card .card-head .spacer { flex: 1; }
.preview-card .card-head .icon-btn { width: 26px; height: 26px; }
.preview-card .summary { font-size: 13px; line-height: 1.5; margin: 4px 0 8px; color: var(--text); }
.preview-card .grid { display: grid; grid-template-columns: 1fr; gap: 10px; margin-top: 6px; }
.preview-card h4 { margin: 0 0 3px; font-size: 12px; font-weight: 600; color: var(--text-3); }
.preview-card ul { margin: 0; padding-left: 16px; font-size: 12.5px; color: var(--text); }
.preview-card li { margin: 2px 0; }
.preview-card .kv { display: flex; gap: 8px; font-size: 12.5px; padding: 2px 0; }
/* flex: none, not just min-width: nowrap text refuses to reflow, so a flex
   item that is still allowed to shrink (the default) shrinks its own box
   under a long amount like "17,000,000.00 EUR" while the text keeps
   painting at full width -- overlapping the label straight through the
   gap, since the gap is sized off the shrunk box, not the overflowing text. */
.preview-card .kv .k { flex: none; color: var(--text-2); font-variant-numeric: tabular-nums; white-space: nowrap; min-width: 84px; }
.preview-card .kv .v { min-width: 0; overflow-wrap: anywhere; }
.preview-card .foot { font-size: 11px; color: var(--text-3); margin-top: 8px; }
.preview-card .skeleton { margin: 6px 0; }

/* ---------------------------------------------------------------- message */

.messages { padding: 0; }
/* The thread's other messages under (and above) the one being read, folded to
   a line (SPEC 47). Quiet on purpose: who, the first words, when -- the open
   message is the only thing on the page that asks to be read. */
.msg-fold {
  display: flex; align-items: center; gap: 10px;
  width: 100%; margin: 0; padding: 11px 32px;
  background: none; border: 0; border-top: 1px solid var(--hair-soft);
  color: var(--text-2); font: inherit; font-size: 13px; text-align: left; cursor: pointer;
  transition: background var(--t);
}
.msg-fold:hover { background: var(--hover); }
.msg-fold:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.msg-fold .fold-name { flex: none; font-weight: 500; color: var(--text); white-space: nowrap; max-width: 36%; overflow: hidden; text-overflow: ellipsis; }
.msg-fold.unread .fold-name { font-weight: 600; }
.msg-fold .fold-snippet { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-3); }
.msg-fold .icon { flex: none; color: var(--text-3); }
.msg-fold .fold-date { flex: none; color: var(--text-3); font-size: 12px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.messages .msg + .msg, .messages .msg-fold + .msg { border-top: 1px solid var(--hair-soft); margin-top: 8px; }
/* Messages newer than the one opened, gathered into a single line above it. */
.msg-newer {
  display: flex; align-items: center; gap: 6px;
  margin: 0; padding: 8px 32px 10px;
  background: none; border: 0; cursor: pointer;
  font: inherit; font-size: 13px; color: var(--accent-text);
}
.msg-newer:hover { text-decoration: underline; }
.msg-newer:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.msg { margin: 0; background: transparent; border: 0; }
.msg-head {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 12px; align-items: start;
  padding: 10px 32px 14px;
  border-bottom: 1px solid var(--hair-soft);
}
.avatar {
  width: 36px; height: 36px; border-radius: 50%;
  background: var(--bg-3); color: var(--text-2);
  display: inline-flex; align-items: center; justify-content: center;
  font-weight: 600; font-size: 13px; flex: none; text-transform: uppercase;
}
.avatar.sm { width: 28px; height: 28px; font-size: 11px; }
.avatar.out { background: var(--accent-bg); color: var(--accent-text); }
.msg.unread .avatar { box-shadow: 0 0 0 2px var(--accent); }
.msg-who { min-width: 0; padding-top: 2px; }
.msg-who .name { font-weight: 600; font-size: 14px; display: flex; gap: 8px; align-items: baseline; min-width: 0; flex-wrap: wrap; }
.msg-who .name .email { font-weight: 400; color: var(--text-3); font-size: 12.5px; overflow: hidden; text-overflow: ellipsis; }
.msg-who .line { font-size: 12.5px; color: var(--text-2); overflow-wrap: anywhere; margin-top: 1px; }
.msg-who .line b { font-weight: 500; color: var(--text-3); }
.msg-right { display: flex; align-items: center; gap: 2px; white-space: nowrap; font-size: 12px; color: var(--text-3); padding-top: 4px; }
.msg-right .date { padding-right: 6px; font-variant-numeric: tabular-nums; }
.msg-right .icon-btn { width: 28px; height: 28px; }

.msg-enrich { padding: 12px 32px 0; font-size: 12.5px; color: var(--text-2); }
/* The summary as a card (SPEC 65): a quiet sheet with its own label, so what the
   AI read is never mistaken for what the sender wrote. */
.msg-enrich.ai-card {
  margin: 14px 32px 2px; padding: 14px 18px 14px; border-radius: 16px;
  background: color-mix(in srgb, var(--accent) 5%, var(--bg-2)); border: 1px solid color-mix(in srgb, var(--accent) 14%, var(--hair-soft));
  display: flex; flex-direction: column; gap: 8px;
}
.ai-card-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
.ai-card-label {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--accent-text);
}
.ai-card-marks { display: inline-flex; gap: 6px; flex-wrap: wrap; }
.ai-pill { display: inline-flex; align-items: center; height: 22px; padding: 0 9px; border-radius: 999px; font-size: 11.5px; font-weight: 600; }
.ai-pill.accent { color: var(--accent-2); background: var(--accent-2-bg); }
.ai-pill.ok { color: var(--ok); background: var(--ok-bg); }
.ai-pill.warn { color: var(--warn); background: color-mix(in srgb, var(--warn) 14%, transparent); }
.ai-card-topic { font-family: var(--font-display); font-size: 15.5px; font-weight: 650; letter-spacing: -0.01em; line-height: 1.3; color: var(--text); overflow-wrap: anywhere; }
.msg-enrich.ai-card p.msg-summary { margin: 0; font-size: 13.5px; line-height: 1.55; color: var(--text-2); }
.ai-card-todo { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 4px 12px; align-items: start; padding-top: 2px; }
.ai-card-sub { font-size: 12px; font-weight: 600; color: var(--text-3); line-height: 20px; }
.msg-enrich.ai-card .msg-todo { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 3px; }
.msg-enrich.ai-card .msg-todo li { display: flex; align-items: baseline; gap: 8px; font-size: 13.5px; line-height: 20px; color: var(--text); }
.todo-dot { flex: none; width: 7px; height: 7px; border-radius: 50%; border: 1.5px solid var(--accent-2); translate: 0 -1px; }
.msg-enrich.ai-card .facts { gap: 6px; padding-top: 2px; }
.msg-enrich.ai-card .fact {
  height: 24px; padding: 0 10px; border-radius: 999px; font-size: 12px; font-weight: 500;
  color: var(--text-2); background: color-mix(in srgb, var(--text) 6%, transparent);
  transition: background var(--t-fast), color var(--t-fast);
}
.msg-enrich.ai-card button.fact:hover { color: var(--accent-text); background: var(--accent-bg); }
.msg-enrich .facts { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.msg-enrich .fact { color: var(--text-2); font-weight: 500; background: none; padding: 0; }
.msg-enrich button.fact:hover { color: var(--accent-text); }
.msg-enrich .fact.strong { color: var(--text); font-weight: 600; }
.msg-enrich .fact.accent { color: var(--accent-2); }
.msg-enrich .fact.warn { color: var(--warn); }
.msg-enrich .fact.ok { color: var(--ok); }
.msg-enrich .sep { color: var(--text-3); }
.msg-enrich .tags { display: flex; flex-wrap: wrap; gap: 0 10px; margin-top: 4px; }
.msg-enrich .tag { color: var(--text-3); font-size: 12px; }
.msg-enrich .tag:hover { color: var(--accent-text); }
.msg-enrich p { margin: 8px 0 0; line-height: 1.5; }
.msg-enrich .msg-summary { color: var(--text-2); }
.msg-enrich .msg-todo { color: var(--text); }
.msg-enrich .msg-todo b { font-weight: 600; color: var(--text-3); margin-right: 6px; }
.msg-enrich .msg-todo span { color: var(--text); }
.msg-enrich.faint { color: var(--text-3); display: flex; align-items: center; gap: 6px; }
.msg-enrich.alert { color: var(--danger); display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.msg-enrich.alert .btn { margin-left: 4px; height: 22px; padding: 0 8px; font-size: 11px; }
.msg-summary { padding: 0; }

.msg-body { padding: 16px 32px 14px; }
.msg-body iframe {
  width: 100%; border: 0; border-radius: var(--radius-lg); background: #fff; display: block;
  min-height: 120px; max-height: 640px;
  box-shadow: var(--shadow);
}
/* The same raised card as the HTML body's iframe, so a plain-text message is
   not the one that sits flat on the panel. Its surface is --card, not the
   iframe's #fff: this half is drawn by the app in the app's own theme, where
   white would leave light text on white in dark mode. */
.msg-body pre.plain {
  margin: 0; font-family: var(--font-read); font-size: 15.5px; line-height: 1.6;
  white-space: pre-wrap; overflow-wrap: anywhere; color: var(--text);
  background: var(--card); border-radius: var(--radius-lg);
  box-shadow: var(--shadow); padding: 14px 18px;
}
.msg-body .quote-toggle { margin-top: 6px; }
.msg-body pre.plain .quoted { color: var(--text-3); }
.body-tools { display: flex; gap: 4px; padding: 0 32px 8px; }
/* Sits above the body now, so the spacing hangs off the message below it
   rather than off the end of the card. */
.attachments { display: flex; flex-wrap: wrap; gap: 6px; padding: 12px 32px 4px; }
.att {
  display: inline-flex; align-items: center; gap: 7px;
  height: 34px; padding: 0 13px 0 11px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--hair); background: var(--card);
  color: var(--text); font-size: 13px; max-width: 280px;
  transition: background var(--t), border-color var(--t);
}
/* The clip/file mark carries the accent: at a glance it is what says "this
   one came with something" before any of the filename is read. */
.att .icon { color: var(--accent); }
.att:hover { background: var(--hover); border-color: var(--hair); text-decoration: none; }
.att .fname { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.att .size { color: var(--text-3); font-size: 11px; }
button.att { font: inherit; cursor: pointer; }
button.att.preview:hover { color: var(--accent-text); }

/* ---------------------------------------------- attachment preview overlay */

.preview-overlay {
  position: fixed; inset: 0; z-index: 60;
  display: flex; flex-direction: column;
  background: color-mix(in srgb, var(--bg) 82%, black);
  backdrop-filter: saturate(140%) blur(12px);
  animation: fade-in var(--t);
}
.preview-bar {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 14px; border-bottom: 1px solid var(--hair); background: var(--card);
  padding-top: max(10px, env(safe-area-inset-top));
}
.preview-name { font-weight: 600; font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.preview-size { color: var(--text-3); font-size: 12px; margin-right: auto; }
.preview-body { flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center; padding: 16px; padding-bottom: max(16px, env(safe-area-inset-bottom)); }
.preview-frame { width: 100%; height: 100%; border: 0; border-radius: 10px; background: #fff; }
.preview-img { max-width: 100%; max-height: 100%; object-fit: contain; border-radius: 10px; background: #fff; }

/* --------------------------------------------------------------- related */

.related { padding: 4px 0 16px; }
.related .item {
  display: block; width: 100%; text-align: left;
  padding: 9px 16px; border: 0; border-top: 1px solid var(--hair-soft);
  background: transparent; transition: background var(--t); cursor: pointer;
}
.related .item:last-child { border-bottom: 1px solid var(--hair-soft); }
.related .item:hover { background: var(--hover); }
.related .item .top { display: flex; gap: 8px; align-items: baseline; }
.related .item .subj { font-weight: 500; font-size: 13px; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.related .item .date { font-size: 11.5px; color: var(--text-3); white-space: nowrap; }
.related .item .who { font-size: 12px; color: var(--text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* One plain line saying why, instead of a row of pills quoting the scorer. */
.related .item .why { font-size: 12px; color: var(--text-3); margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.related .none { font-size: 12.5px; color: var(--text-3); padding: 0 16px; }
.related .skeleton { margin: 4px 16px; }

/* --------------------------------------------------------------- sheet */

.sheet {
  position: absolute; left: 0; right: 0; bottom: 0; height: 100%; max-height: 100%;
  border-radius: var(--radius-xl) var(--radius-xl) 0 0;
  display: flex; flex-direction: column; z-index: 20;
  /* The delay is a bare duration on purpose: --t-slide carries its easing,
     and "visibility 0s linear var(--t-slide)" put a curve where the delay goes,
     which invalidated the whole line and had compose closing with a snap. */
  transform: translateY(102%); transition: transform var(--t-slide), visibility 0s linear var(--d-slide);
  visibility: hidden;
}
.sheet.open { transition: transform var(--t-slide); }
.sheet.open { transform: none; visibility: visible; }
@media (min-width: 1100px) { .sheet { height: 94%; margin: 0 12px; } }

.sheet-head {
  display: flex; align-items: center; gap: 8px;
  height: 46px; padding: 0 10px 0 16px;
  border-bottom: 1px solid var(--hair-soft); flex: none;
}
.sheet-head h2 { margin: 0; font-size: 15px; font-weight: 600; flex: 1; letter-spacing: -0.2px; }
.sheet-body { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; display: flex; flex-direction: column; padding-bottom: var(--safe-bottom); }
.field {
  display: flex; align-items: center; gap: 10px; min-height: 40px; padding: 0 16px;
  border-bottom: 1px solid var(--hair-soft); position: relative;
}
.field label { width: 54px; flex: none; font-size: 12.5px; color: var(--text-3); }
.field input, .field select { flex: 1; min-width: 0; height: 38px; border: 0; background: transparent; font-size: 13.5px; }
.field select { appearance: none; -webkit-appearance: none; padding-right: 20px; cursor: pointer; }
.field .select-wrap { flex: 1; position: relative; display: flex; align-items: center; }
.field .select-wrap .icon { position: absolute; right: 2px; pointer-events: none; color: var(--text-3); }
.field .link { font-size: 12px; color: var(--accent-text); padding: 4px 6px; }
.field input::placeholder { color: var(--text-3); }

.suggest {
  position: absolute; top: calc(100% - 2px); left: 70px; right: 16px; max-width: 460px;
  border-radius: var(--radius-lg);
  z-index: 50; overflow: hidden; padding: 4px; animation: rise-in var(--t);
}
.suggest .s-item { display: flex; flex-direction: column; gap: 1px; width: 100%; text-align: left; padding: 6px 10px; border-radius: var(--radius-sm); min-height: 36px; justify-content: center; }
.suggest .s-item:hover, .suggest .s-item.active { background: var(--sel); }
.suggest .s-item .n { font-size: 13px; font-weight: 500; }
.suggest .s-item .e { font-size: 12px; color: var(--text-2); }

.ai-row {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  padding: 8px 16px; border-bottom: 1px solid var(--hair-soft); position: relative;
}
.ai-row .icon-lead { color: var(--text-3); }
.ai-row .quick {
  display: inline-flex; align-items: center; height: 26px; padding: 0 10px; border-radius: 999px;
  background: var(--bg-3); color: var(--text); font-size: 12px; font-weight: 500;
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; transition: background var(--t);
}
.ai-row .quick:hover { background: var(--accent-bg); color: var(--accent-text); }
.ai-row .sep { width: 1px; height: 18px; background: var(--hair); margin: 0 2px; }
.ai-row .quick.skeleton { width: 120px; height: 26px; border-radius: 999px; }
.ai-row .rationale { width: 100%; font-size: 11.5px; color: var(--text-3); }
.ai-row .ai-ask {
  flex: 1 1 180px; min-width: 0; height: 26px; padding: 0 10px; border-radius: 999px; border: 1px solid var(--hair);
  background: transparent; color: var(--text); font: inherit; font-size: 12px; outline: none;
  transition: border-color var(--t-fast), background var(--t-fast);
}
.ai-row .ai-ask::placeholder { color: var(--text-3); }
.style-box { display: flex; flex-direction: column; gap: 8px; margin: 4px 0 18px; }
.style-text {
  margin: 0; padding: 12px 14px; border-radius: 12px; background: var(--bg-2); color: var(--text-2);
  font: inherit; font-size: 12.5px; line-height: 1.55; white-space: pre-wrap; overflow-wrap: anywhere;
}
.style-actions { display: flex; gap: 8px; }
.ai-row .ai-ask:focus { border-color: var(--accent); background: var(--bg); }

.menu-wrap { position: relative; }
.menu {
  position: absolute; top: calc(100% + 4px); left: 0; min-width: 170px;
  border-radius: var(--radius-lg);
  padding: 4px; z-index: 60; animation: rise-in var(--t);
}
.menu.right { left: auto; right: 0; }
.menu.closing { animation: fold-away var(--t-fast) forwards; pointer-events: none; }

/* ---- the glass select (SPEC 57) ------------------------------------------ */
.gsel { position: relative; display: inline-flex; min-width: 0; }
.gsel-native { position: absolute; inset: 0; opacity: 0; pointer-events: none; width: 100%; height: 100%; }
.gsel-btn {
  display: flex; align-items: center; gap: 8px; width: 100%; min-width: 0;
  color: var(--text); text-align: left; cursor: pointer;
  transition: background var(--t-fast), border-color var(--t-fast), box-shadow var(--t-fast);
}
.gsel-btn:disabled { cursor: default; opacity: 0.6; }
.gsel-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.gsel-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gsel-btn .icon { flex: none; color: var(--text-3); transition: transform var(--t); }
.gsel-btn[aria-expanded="true"] .icon { transform: rotate(180deg); color: var(--text-2); }
.gsel-menu {
  min-width: 100%; max-width: min(420px, 90vw); max-height: 300px; overflow-y: auto; overscroll-behavior: contain;
  transform-origin: top center; animation: drop-in var(--t-slide);
}
.gsel-menu.up { top: auto; bottom: calc(100% + 6px); transform-origin: bottom center; animation-name: drop-up; }
.gsel-menu.up.closing { animation-name: fold-away; }
.gsel-menu button { height: 34px; gap: 10px; font-size: 13.5px; color: var(--text); }
.gsel-menu button.on { font-weight: 600; }
.gsel-menu button.on .icon { color: var(--accent-text); }
.gsel-menu button:focus-visible { outline: none; background: var(--sel); }
.gsel-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gsel-tick { width: 14px; flex: none; }
/* in a compose field: the row is the control, as the input beside it is */
.gsel-field { flex: 1; }
.gsel-field .gsel-btn { height: 38px; padding: 0 2px; background: transparent; border: 0; font-size: 13.5px; }
.gsel-field .gsel-btn:hover .icon { color: var(--text-2); }
.select-wrap:has(.gsel) > span:not(.gsel) { display: none; }
/* the signature pill in the compose footer */
.gsel-pill .gsel-btn {
  height: 30px; padding: 0 10px 0 12px; border-radius: 999px; max-width: 220px;
  background: var(--bg-3); border: 1px solid var(--hair); font-size: 12.5px;
}
.gsel-pill .gsel-btn:hover { background: color-mix(in srgb, var(--bg-3) 78%, var(--text) 8%); }
/* in a settings form: the same box as a text input */
.gsel-input { display: flex; width: 100%; }
.gsel-input .gsel-btn {
  height: 38px; padding: 0 12px; border-radius: 10px; border: 1px solid var(--hair); background: var(--bg);
  font-size: 13.5px;
}
.gsel-input .gsel-btn:hover { border-color: var(--text-3); }
.gsel-input .gsel-btn[aria-expanded="true"] { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-bg); }
.menu button { display: flex; align-items: center; gap: 8px; width: 100%; text-align: left; padding: 0 10px; height: 32px; border-radius: var(--radius-sm); font-size: 13px; }
.menu button:hover { background: var(--sel); }
.menu .menu-sep { height: 1px; background: var(--hair-soft); margin: 4px 0; }

.body-wrap { position: relative; flex: 1; min-height: 220px; display: flex; }
.body-wrap textarea, .body-wrap .ghost {
  font-family: var(--font); font-size: 14px; line-height: 1.5; padding: 12px 16px; margin: 0; border: 0; width: 100%;
  white-space: pre-wrap; overflow-wrap: anywhere; word-break: break-word; letter-spacing: normal; tab-size: 4;
}
.body-wrap textarea { position: relative; z-index: 1; background: transparent; color: var(--text); resize: none; flex: 1; min-height: 220px; outline: none; }
.body-wrap .ghost { position: absolute; inset: 0; color: transparent; pointer-events: none; overflow: hidden; z-index: 0; }
.body-wrap .ghost .typed { color: transparent; }
.body-wrap .ghost .sugg { color: var(--text-3); }
/* A whole suggestion (SPEC 61): what is written steps aside, the grey text stands in its place */
.body-wrap.offering textarea { color: transparent; caret-color: var(--text); }
.body-wrap.offering textarea::placeholder { color: transparent; }
.body-wrap .ghost .kept { color: var(--text); }
.ghost-hint {
  position: absolute; right: 12px; bottom: 8px; z-index: 2;
  font-size: 11px; color: var(--text-3); background: var(--bg-3); border-radius: 5px; padding: 2px 6px;
  border: 1px solid var(--hair); font-family: inherit; cursor: pointer;
}
.ghost-hint:hover, .ghost-hint:focus-visible { background: var(--accent-bg); color: var(--accent-text); }
.body-wrap.working::after { content: ""; position: absolute; inset: 0; z-index: 2; background: color-mix(in srgb, var(--bg) 60%, transparent); pointer-events: none; }
.body-wrap .spinner {
  position: absolute; z-index: 3; left: 50%; top: 40%; width: 22px; height: 22px; border-radius: 50%;
  border: 2px solid var(--hair); border-top-color: var(--accent); animation: spin 0.8s linear infinite; margin-left: -11px;
}

.sheet-foot { display: flex; align-items: center; gap: 8px; padding: 10px 16px calc(10px + var(--safe-bottom)); border-top: 1px solid var(--hair-soft); flex: none; }
.sheet-foot .spacer { flex: 1; }
.sheet-foot .hint { font-size: 11.5px; color: var(--text-3); }

.compose-related { padding: 4px 0 16px; border-top: 1px solid var(--hair-soft); }
.compose-related.related { padding: 4px 0 16px; }

/* --------------------------------------------------------------- toasts */

.toasts {
  position: fixed; left: 50%; bottom: calc(18px + var(--safe-bottom)); transform: translateX(-50%);
  display: flex; flex-direction: column; gap: 6px; z-index: 100; pointer-events: none; max-width: min(92vw, 520px);
}
.toast {
  pointer-events: auto; display: flex; align-items: center; gap: 8px;
  padding: 9px 14px; border-radius: var(--radius-lg); color: var(--text);
  font-size: 13px; animation: rise-in var(--t); overflow-wrap: anywhere;
}
.toast.error { color: var(--danger); }
.toast.ok { color: var(--ok); }
.toast button { color: inherit; opacity: 0.8; display: inline-flex; }

/* --------------------------------------------------------------- login */

/* The sign-in card is the front sheet of the mark: two narrower sheets of
   glass stand behind it, and the field shows through all three. */
.login-page { display: flex; align-items: center; justify-content: center; min-height: 100vh; min-height: calc(100dvh / var(--ui-zoom)); padding: 56px 24px 24px; }
.login-stack { position: relative; width: 100%; max-width: 380px; }
.login-stack::before, .login-stack::after {
  content: ""; position: absolute; border-radius: var(--radius-sheet);
  background: var(--sheet-back); border: 1px solid var(--sheet-rim);
}
.login-stack::before { left: 44px; right: 44px; top: -30px; height: 60px; }
.login-stack::after { left: 20px; right: 20px; top: -16px; height: 60px; background: var(--sheet-mid); }
.login-card {
  position: relative; z-index: 1;
  width: 100%; padding: 32px 30px 26px; border-radius: var(--radius-sheet);
  background: var(--sheet-front); border: 1px solid var(--sheet-rim); box-shadow: var(--sheet-shadow);
  display: flex; flex-direction: column; gap: 14px;
}
.login-card .brand { padding: 0; min-width: 0; gap: 14px; margin-bottom: 4px; }
.login-card .brand .logo { width: 52px; height: 52px; border-radius: 14px; }
.login-card .brand .name { font-family: var(--font-display); font-size: 30px; font-weight: 650; letter-spacing: -0.03em; }
.login-card .brand .tag { font-size: 10px; letter-spacing: 0.2em; }
.login-card p { margin: 0 0 4px; color: var(--text-2); font-size: 14px; }
.login-card input {
  height: 44px; border-radius: 12px; border: 1px solid var(--hair); background: var(--bg-2);
  padding: 0 14px; font-size: 15px; width: 100%; transition: box-shadow var(--t), border-color var(--t), background var(--t);
}
.login-card input:focus { border-color: var(--accent); background: var(--bg); box-shadow: 0 0 0 3px var(--accent-bg); }
.login-card .btn { height: 44px; justify-content: center; font-size: 15px; }
.login-error { color: var(--danger); font-size: 12.5px; min-height: 18px; }

/* ----------------------------------------------------------- responsive */

.menu-btn, .back-btn { display: none; }

/* below 1100px the thread panel floats over the reader instead of taking a column */
/* The thread panel only earns its own column when the reading pane can still
   hold a message beside it. Below this the sidebar, the list and a 300px panel
   left the reader around 270px, where the date header alone squeezed the To:
   line down to one character per row -- so here the panel floats over the
   reader instead of taking space from it. */
@media (max-width: 1279px) {
  /* Too narrow to give the panel room of its own: the column stays shut and it
     floats over the reader, carried by the same transform. */
  .thread-pane.panel-open .reader { --panel-size: 0px; }
  .thread-panel {
    width: min(380px, 88%); z-index: 15; box-shadow: var(--shadow);
    background: var(--glass-solid);
  }
}

@media (max-width: 1099px) {
  .panes { grid-template-columns: var(--list-w) minmax(0, 1fr); }
  .menu-btn { display: inline-flex; }
  .topbar .brand { min-width: 0; }
  .sidebar {
    position: fixed; top: 0; bottom: 0; left: 0; width: min(280px, 85vw);
    padding-top: calc(12px + var(--safe-top)); z-index: 28;
    transform: translateX(-100%); transition: transform var(--t-slide);
    border-right: 1px solid var(--hair);
  }
  .app.sidebar-open .sidebar { transform: none; box-shadow: var(--shadow); }
  .sheet { margin: 0; border-radius: 14px 14px 0 0; }
  /* Reply / Reply all / Forward keep their icons only: the reader is too
     narrow here for the labels and the shelf buttons and the Thread button. */
  .thread-toolbar .btn .label { display: none; }
  .thread-toolbar .btn { width: 34px; padding: 0; justify-content: center; }
  .thread-toolbar .thread-btn { width: auto; padding: 0 10px; }
}

@media (max-width: 900px) {
  .topbar .brand-text { display: none; }
  #syncBtn .label, #calendarBtn .label { display: none; }
  #syncBtn, #calendarBtn { width: 34px; padding: 0; justify-content: center; }
  .status-chip .text-long { display: none; }
}

@media (max-width: 699px) {
  .panes { grid-template-columns: minmax(0, 1fr); }
  .list-pane, .thread-pane { display: none; border-right: 0; }
  .app[data-view="list"] .list-pane { display: flex; }
  .app[data-view="thread"] .thread-pane,
  .app[data-view="compose"] .thread-pane { display: flex; }
  .app[data-view="thread"] .menu-btn,
  .app[data-view="compose"] .menu-btn { display: none; }
  .app[data-view="thread"] .back-btn,
  .app[data-view="compose"] .back-btn { display: inline-flex; }
  .topbar .brand { display: none; }   /* the phone gives the width to search instead */
  .search { max-width: none; margin: 0; }
  .search .kbd { display: none; }
  .status-chip { display: none; }
  .status-chip.alert { display: inline-flex; position: fixed; top: calc(6px + var(--safe-top)); left: 50%; transform: translateX(-50%); z-index: 40; box-shadow: var(--shadow); }
  #composeBtn .label { display: none; }
  #composeBtn { width: 34px; padding: 0; justify-content: center; }
  .topbar { gap: 4px; padding-left: calc(6px + var(--safe-left)); padding-right: calc(6px + var(--safe-right)); }
  .row { padding: 12px 14px 12px 10px; min-height: 60px; }
  .row .snippet { -webkit-line-clamp: 2; }
  .reader-head { padding: 16px 16px 4px; }
  .reader-head h1 { font-size: 17px; }
  .msg-head, .msg-enrich, .body-tools { padding-left: 16px; padding-right: 16px; }
  .msg-enrich.ai-card { margin-left: 16px; margin-right: 16px; padding-left: 14px; padding-right: 14px; }
  .msg-body { padding: 14px 16px 6px; }
  .attachments { padding: 6px 16px 14px; }
  .thread-toolbar .btn .label { display: none; }
  .thread-toolbar .btn { width: 34px; padding: 0; justify-content: center; }
  .thread-toolbar .thread-btn { width: auto; padding: 0 10px; }
  .thread-panel { width: 100%; box-shadow: none; border-left: 0; }
  .sheet { border-radius: 0; height: 100%; }
  .field label { width: 44px; }
  .suggest { left: 12px; right: 12px; }
  .ghost-hint { min-height: 44px; min-width: 44px; padding: 0 14px; display: inline-flex; align-items: center; }
  .list-head .filter-chip { max-width: 120px; }
  .msg-who .name .email { display: none; }
  .preview-body { padding: 8px; }
  .preview-bar .btn span { display: none; }
}

@media (hover: none) {
  .row:hover, .side-item:hover, .tl-item:hover, .related .item:hover { background: inherit; }
  .row.selected { background: var(--sel); }
  .side-item.active { background: var(--sel); }
  .tl-item.current { background: var(--sel); }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

.toast .toast-action {
  font-weight: 600; color: inherit; text-decoration: underline;
  padding: 0 4px; white-space: nowrap;
}

/* ------------------------------------------------------- mailbox settings */

/* A centred dialog rather than the bottom sheet compose uses: this is a
   settings task, not a writing task, and it has to work from any pane. */
.modal {
  position: fixed; inset: 0; z-index: 70;
  display: flex; align-items: center; justify-content: center;
  padding: max(16px, env(safe-area-inset-top)) 16px max(16px, env(safe-area-inset-bottom));
  /* SPEC 150: the dim tint at half its own strength, not full -- mixed to full strength (as this
     was) leaves nothing for the blur behind it to show through, so the screen the dialog sits over
     reads as flat black (or white in the light theme) instead of the frosted glass every other
     floating surface in the app already is. */
  background: color-mix(in srgb, color-mix(in srgb, var(--bg) 55%, black) 50%, transparent);
  -webkit-backdrop-filter: saturate(160%) blur(var(--glass-blur));
  backdrop-filter: saturate(160%) blur(var(--glass-blur));
  animation: fade-in var(--t);
}
.modal-card {
  width: min(620px, 100%); max-height: 100%;
  display: flex; flex-direction: column;
  border-radius: var(--radius-xl); overflow: hidden;
  animation: rise-in var(--t);
}
.modal-head {
  display: flex; align-items: center; gap: 8px;
  padding: 12px 10px 12px 18px; border-bottom: 1px solid var(--hair-soft); flex: none;
}
.modal-head h2 { margin: 0; font-size: 16px; font-weight: 600; letter-spacing: -0.2px; }
.modal-head .spacer { flex: 1; }
.modal-body { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 6px 18px 18px; }
.modal-foot { display: flex; align-items: center; gap: 8px; padding-top: 14px; }
.modal-foot .spacer { flex: 1; }
.modal-note { font-size: 12px; color: var(--text-3); margin: 14px 0 0; line-height: 1.5; }

/* ------------------------------------------------------------ Ask (SPEC 151) */

/* Under the attachment preview (60), so a cited PDF opens over the answer, not behind it. */
.ask-modal { z-index: 59; align-items: flex-start; padding-top: max(9vh, env(safe-area-inset-top)); }
.ask-card { width: min(680px, 100%); max-height: min(84vh, 100%); }
.ask-title { display: flex; align-items: center; gap: 8px; }
.ask-bar {
  display: flex; align-items: flex-end; gap: 8px; margin: 10px 0 8px;
  padding: 6px 6px 6px 14px; border-radius: 16px;
  background: var(--bg-2); border: 1px solid var(--hair);
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
}
.ask-bar:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-bg); }
.ask-input {
  flex: 1; min-width: 0; resize: none; border: 0; outline: 0; background: transparent; color: var(--text);
  font: inherit; font-size: 15px; line-height: 1.45; padding: 7px 0; max-height: 168px;
}
.ask-go { flex: none; width: 36px; height: 36px; padding: 0; border-radius: 12px; display: grid; place-items: center; }
.ask-scope { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; min-height: 22px; margin-bottom: 4px; }
.ask-note { font-size: 12px; color: var(--text-3); }
.ask-chip {
  display: inline-flex; align-items: center; gap: 6px; max-width: 100%;
  padding: 3px 4px 3px 9px; border-radius: 999px; font-size: 12px;
  background: var(--accent-bg); color: var(--accent-text);
}
.ask-chip-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ask-chip-x { display: grid; place-items: center; width: 20px; height: 20px; border-radius: 50%; color: inherit; }
.ask-chip-x:hover { background: color-mix(in srgb, var(--accent) 18%, transparent); }
.ask-body { padding: 6px 0 4px; }
.ask-reading { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--text-2); margin: 10px 0 12px; }
.ask-body .skeleton { margin: 8px 0; }
.ask-answer { font-size: 15px; line-height: 1.6; color: var(--text); overflow-wrap: anywhere; }
.ask-answer p { margin: 0 0 10px; }
.ask-answer ul { margin: 0 0 10px; padding-left: 20px; }
.ask-answer li { margin: 4px 0; }
.cite {
  display: inline-grid; place-items: center; min-width: 18px; height: 18px; margin: 0 1px 0 2px; padding: 0 5px;
  border-radius: 9px; vertical-align: 2px; font-size: 11px; font-weight: 600; font-variant-numeric: tabular-nums;
  background: var(--accent-bg); color: var(--accent-text); transition: background var(--t-fast);
}
.cite:hover, .cite:focus-visible { background: var(--accent); color: #fff; }
.ask-h {
  margin: 16px 0 6px; font-size: 11px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-3);
}
.ask-sources { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.ask-source {
  width: 100%; display: flex; align-items: flex-start; gap: 10px; text-align: left;
  padding: 8px 10px; border-radius: var(--radius-sm); color: var(--text);
  transition: background var(--t-fast);
}
.ask-source:hover, .ask-source:focus-visible { background: var(--hover); }
.ask-source .icon { margin-top: 1px; color: var(--text-2); }
.ask-n {
  flex: none; display: grid; place-items: center; width: 20px; height: 20px; border-radius: 10px;
  font-size: 11px; font-weight: 600; background: var(--bg-3); color: var(--text-2); font-variant-numeric: tabular-nums;
}
.ask-src { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.ask-src-title { font-size: 14px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ask-src-meta { font-size: 12px; color: var(--text-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ask-foot, .ask-empty { font-size: 13px; color: var(--text-3); line-height: 1.5; margin: 14px 0 0; }
.ask-empty { color: var(--text-2); margin-top: 8px; }
.ask-error { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; font-size: 14px; color: var(--danger); margin-top: 8px; }

/* The search box's own row for a question */
.hint-ask {
  display: flex; align-items: center; gap: 8px; width: 100%; text-align: left;
  padding: 8px 10px; margin-bottom: 6px; border-radius: var(--radius-sm);
  background: var(--accent-bg); color: var(--text);
}
.hint-ask:hover { background: color-mix(in srgb, var(--accent) 22%, transparent); }
.hint-ask-label { font-weight: 600; color: var(--accent-text); }
.hint-ask-q { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-2); }

/* Under a conversation's preview */
.thread-ask {
  display: flex; align-items: center; gap: 8px; margin: 2px 16px 10px; padding: 4px 4px 4px 12px;
  border-radius: 999px; background: var(--bg-2); border: 1px solid var(--hair);
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
}
.thread-ask:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-bg); }
.thread-ask-input {
  flex: 1; min-width: 0; border: 0; outline: 0; background: transparent; color: var(--text);
  font: inherit; font-size: 13px; padding: 6px 0;
}
.thread-ask .icon-btn { width: 30px; height: 30px; }

@media (max-width: 720px) {
  .ask-modal { padding-top: 0; align-items: stretch; }
  .ask-card { max-height: 100%; border-radius: 0; }
  .ask-input { font-size: 16px; } /* iOS zooms into anything smaller */
}

/* providers: a bullet in the provider's colour, its name, what it needs */
.pdot { width: 10px; height: 10px; border-radius: 50%; flex: none; display: inline-block; }
.pdot.lg { width: 14px; height: 14px; margin-top: 3px; }

.plist { list-style: none; margin: 0; padding: 6px 0 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 2px 12px; }
.pitem { display: grid; grid-template-columns: minmax(0, 1fr) 32px; align-items: center; gap: 2px; }
.psite {
  width: 32px; height: 32px; border-radius: 8px; display: inline-flex; align-items: center; justify-content: center;
  color: var(--text-3); transition: background var(--t-fast), color var(--t-fast);
}
.psite:hover { background: var(--hover); color: var(--accent-text); }
.psite:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.prow {
  display: grid; grid-template-columns: 10px auto minmax(0, 1fr) 14px; align-items: center; gap: 12px;
  width: 100%; min-height: 44px; padding: 8px 10px; border-radius: 10px;
  background: none; border: 0; text-align: left; color: var(--text);
  transition: background var(--t-fast);
}
.prow:hover { background: var(--hover); }
.prow:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* the name is never cut; the note gives way first, right-aligned so every row's arrow lines up */
.prow .pname { font-size: 14px; font-weight: 500; white-space: nowrap; }
.prow .pnote { font-size: 12px; color: var(--text-3); white-space: nowrap; text-align: right; overflow: hidden; text-overflow: ellipsis; }
/* no website: an empty slot the size of the link, so the columns stay aligned. Not ".empty" --
   that is the empty-state block, whose padding made these rows 200px tall */
.psite-none { pointer-events: none; }
.prow .icon { color: var(--text-3); }
.prow.blocked { opacity: 0.55; }

/* connected mailboxes */
.acct {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 12px 0; border-bottom: 1px solid var(--hair-soft);
}
.acct.off { opacity: 0.6; }
.acct-main { flex: 1; min-width: 0; }
.acct-name { display: flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 600; }
.acct-name .mark { font-size: 11px; font-weight: 500; color: var(--text-3); }
/* Rename in place: a pencil that shows on hover or focus, and a field the size of the name */
.acct-label { display: inline-flex; align-items: center; gap: 4px; min-width: 0; }
.acct-label > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.acct-rename {
  display: inline-grid; place-items: center; width: 24px; height: 24px; padding: 0; border: 0; border-radius: 6px;
  background: none; color: var(--text-3); cursor: pointer; opacity: 0;
  transition: opacity var(--t-fast), background var(--t-fast);
}
.acct:hover .acct-rename, .acct-rename:focus-visible { opacity: 1; }
.acct-rename:hover { background: var(--hover); color: var(--text); }
@media (hover: none) { .acct-rename { opacity: 1; } }
.acct-name-input { height: 28px; margin-block: -5px; padding: 0 8px; font-size: 14px; font-weight: 600; width: min(260px, 100%); }
.acct-sub { font-size: 12.5px; color: var(--text-2); overflow-wrap: anywhere; }
.acct-err { display: flex; align-items: flex-start; gap: 5px; font-size: 12px; color: var(--danger); margin-top: 3px; }
.acct-actions { display: flex; flex-wrap: wrap; gap: 4px; justify-content: flex-end; }

/* the connect form */
.form-head { display: flex; gap: 12px; align-items: flex-start; padding: 12px 0 4px; }
.form-head strong { font-size: 14px; }
.form-head .requirement { margin: 4px 0 6px; font-size: 12.5px; color: var(--text-2); line-height: 1.5; }
.form-head a { font-size: 12.5px; }
.form { display: grid; gap: 12px; padding: 14px 0 4px; border-top: 1px solid var(--hair-soft); }
.form-row { display: grid; gap: 4px; }
.form-label { font-size: 12px; color: var(--text-2); }
.text-input {
  height: 38px; border-radius: 8px; border: 1px solid var(--hair);
  background: var(--bg); color: var(--text); padding: 0 11px; font-size: 14px; width: 100%;
  transition: border-color var(--t), box-shadow var(--t);
}
.text-input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-bg); }
.form-hint { font-size: 11.5px; color: var(--text-3); }
.form-hint.standalone { margin: 0; overflow-wrap: anywhere; }
.form-warn {
  display: flex; gap: 6px; align-items: flex-start; margin: 0;
  font-size: 12.5px; color: var(--warn); line-height: 1.5;
}

/* connection-test result */
.probe { margin-top: 14px; padding: 12px 14px; border-radius: var(--radius); border: 1px solid var(--hair); }
.probe.ok { border-color: color-mix(in srgb, var(--ok) 45%, transparent); background: var(--ok-bg); }
.probe.bad { border-color: color-mix(in srgb, var(--danger) 45%, transparent); background: var(--danger-bg); }
.probe-line { display: flex; gap: 7px; align-items: flex-start; font-size: 13px; line-height: 1.5; }
.probe-line + .probe-line { margin-top: 5px; }
.probe.ok .probe-line .icon { color: var(--ok); }
.probe.bad .probe-line .icon { color: var(--danger); }
.probe-sub { font-size: 12px; color: var(--text-2); margin: 3px 0 0 22px; overflow-wrap: anywhere; }

.link-btn { color: var(--accent-text); font-size: inherit; text-decoration: underline; }

@media (max-width: 699px) {
  .modal { padding: 0; }
  .modal-card { border-radius: 0; height: 100%; max-height: none; border: 0; }
  .acct { flex-wrap: wrap; }
  .acct-actions { width: 100%; justify-content: flex-start; }
}

/* Related items can be pulled into the open thread; the "+" only shows when
   there is a thread to pull them into. */
.related .item { position: relative; }
.related .item .pull {
  position: absolute; right: 10px; top: 8px; opacity: 0; transition: opacity var(--t-fast);
}
.related .item:hover .pull, .related .item:focus-within .pull { opacity: 1; }

/* ------------------------------------------------------------- settings */

.settings-card { width: min(760px, 100%); height: min(640px, 100%); }
.settings-body { display: grid; grid-template-columns: 180px minmax(0, 1fr); flex: 1; min-height: 0; }
.settings-nav {
  display: flex; flex-direction: column; gap: 2px; padding: 10px 8px;
  border-right: 1px solid var(--hair-soft); overflow-y: auto;
}
.settings-nav button {
  display: flex; align-items: center; gap: 9px; height: 32px; padding: 0 10px;
  border-radius: var(--radius); color: var(--text); font-size: 13px; text-align: left;
  transition: background var(--t-fast);
}
.settings-nav button:hover { background: var(--hover); }
.settings-nav button.active { background: var(--sel); color: var(--accent-text); font-weight: 500; }
.settings-nav button .icon { color: var(--text-2); }
.settings-nav button.active .icon { color: var(--accent-text); }
.settings-section h3 { margin: 14px 0 4px; font-size: 15px; font-weight: 600; letter-spacing: -0.2px; }
.settings-section > p { margin: 0 0 10px; font-size: 12.5px; color: var(--text-2); line-height: 1.5; }
.settings-section .form { border-top: 0; padding-top: 6px; }
.settings-section .form-row.inline { grid-template-columns: minmax(0, 1fr) auto; align-items: center; }
.settings-section textarea.text-input { height: auto; min-height: 84px; padding: 9px 11px; resize: vertical; font-family: inherit; line-height: 1.45; }
.settings-section select.text-input { appearance: none; -webkit-appearance: none; padding-right: 28px;
  background-image: linear-gradient(45deg, transparent 50%, var(--text-3) 50%), linear-gradient(135deg, var(--text-3) 50%, transparent 50%);
  background-position: calc(100% - 15px) 16px, calc(100% - 10px) 16px; background-size: 5px 5px; background-repeat: no-repeat; }
.settings-section .switch { display: inline-flex; align-items: center; gap: 10px; cursor: pointer; font-size: 13px; }
.settings-section .switch input { appearance: none; width: 38px; height: 22px; border-radius: 999px; background: var(--bg-3); position: relative; transition: background var(--t); cursor: pointer; }
.settings-section .switch input::after { content: ""; position: absolute; top: 2px; left: 2px; width: 18px; height: 18px; border-radius: 50%; background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,.3); transition: transform var(--t); }
.settings-section .switch input:checked { background: var(--accent); }
.settings-section .switch input:checked::after { transform: translateX(16px); }
.settings-section .status-line { display: flex; align-items: center; gap: 8px; font-size: 13px; margin: 6px 0 10px; }
.settings-section .status-line .dot { width: 8px; height: 8px; }
.qr { width: 180px; height: 180px; border-radius: var(--radius); background: #fff; padding: 8px; display: block; }
.secret { font-family: var(--mono); font-size: 12px; letter-spacing: 0.06em; user-select: all; overflow-wrap: anywhere; }
.recovery { font-family: var(--mono); font-size: 13px; line-height: 1.7; columns: 2; margin: 8px 0; padding: 10px 14px; border-radius: var(--radius); background: var(--bg-3); user-select: all; }
.shortcuts { display: grid; grid-template-columns: auto 1fr; gap: 6px 14px; font-size: 13px; align-items: center; }
.shortcuts kbd { font-family: var(--mono); font-size: 11.5px; border: 1px solid var(--hair); border-radius: 5px; padding: 1px 6px; background: var(--bg-3); }
.side-foot .side-tools { display: flex; gap: 2px; margin-top: 6px; }

/* Compact density: the same layout with the air taken out. */
.app.dense .row { padding: 6px 12px 6px 8px; min-height: 36px; row-gap: 0; }
.app.dense .row .snippet { display: none; }
.app.dense .row .meta { margin-top: 0; }
.app.dense .side-item { height: 26px; }
.app.dense .tl-item { padding: 5px 16px; }
.app.dense .list-head, .app.dense .thread-toolbar { height: 38px; }

@media (max-width: 699px) {
  .settings-body { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr); }
  .settings-nav { flex-direction: row; overflow-x: auto; border-right: 0; border-bottom: 1px solid var(--hair-soft); padding: 6px 8px; }
  .settings-nav button { height: 30px; white-space: nowrap; }
  .recovery { columns: 1; }
}

/* The logo is a button now: no button chrome, a soft press. */
button.brand { background: none; border: 0; cursor: pointer; border-radius: var(--radius); transition: opacity var(--t-fast), transform var(--t-fast); }
button.brand:hover { opacity: 0.85; }
button.brand:active { transform: scale(0.97); }

/* Signatures */
.sig-select {
  height: 30px; padding: 0 28px 0 10px; border-radius: 999px; border: 1px solid var(--hair);
  background: var(--bg-3); color: var(--text); font-size: 12.5px; max-width: 220px;
  appearance: none; -webkit-appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--text-3) 50%), linear-gradient(135deg, var(--text-3) 50%, transparent 50%);
  background-position: calc(100% - 14px) 12px, calc(100% - 9px) 12px; background-size: 5px 5px; background-repeat: no-repeat;
}
.sig-preview { margin: 4px 0 0; font: inherit; font-size: 12.5px; color: var(--text-2); white-space: pre-wrap; overflow-wrap: anywhere; max-height: 84px; overflow: hidden; }
.sig-form { padding: 12px 14px; border: 1px solid var(--hair); border-radius: var(--radius-lg); margin: 8px 0; transition: border-color var(--t-fast), background var(--t-fast); }
/* SPEC 32.5: typeface, size and an image, and a preview of the result */
.sig-form.drop { border-color: var(--accent); background: var(--accent-bg); }
.sig-type-row { display: grid; grid-template-columns: minmax(0, 1fr) 132px; gap: 8px; }
.sig-image-row { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; }
.sig-image-row .form-hint { flex-basis: 100%; }
.sig-image-row .btn { gap: 6px; }
.sig-preview-box { display: flex; flex-direction: column; gap: 6px; padding: 12px 14px; border-radius: var(--radius-lg); background: var(--bg-2); }
/* Mail is read on white: the preview shows the signature the way it lands. */
.sig-rendered { display: flex; flex-direction: column; gap: 8px; padding: 12px 14px; border-radius: 10px; background: #fff; color: #17171a; overflow: hidden; }
.sig-rendered-text { white-space: pre-wrap; overflow-wrap: anywhere; font-family: Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.4; }
.sig-rendered-img { display: block; max-width: 100%; height: auto; }
.sig-rendered.compact { margin-top: 6px; padding: 8px 10px; max-height: 160px; }
.sig-rendered.compact .sig-rendered-text { font-size: 12px; max-height: 84px; overflow: hidden; }
.acct-name .mark.quiet { color: var(--text-3); background: none; }
.compose-sig-image { display: flex; align-items: center; gap: 10px; padding: 6px 16px 10px; font-size: 12px; color: var(--text-3); }
.compose-sig-image img { display: block; max-height: 44px; max-width: min(60%, 360px); border-radius: 4px; box-shadow: 0 0 0 1px var(--hair-soft); background: #fff; }
.rich img { max-width: 100%; height: auto; }
.app.no-snippets .row .snippet { display: none; }

/* ==========================================================================
   Outlook parity (SPEC 33): selection, shelves, drafts, attachments, print
   ========================================================================== */

/* hover checkbox on the left of a row, quick actions on the right */
.row .check { position: absolute; left: 8px; top: 12px; width: 16px; height: 16px; opacity: 0; transition: opacity var(--t-fast); }
.check input {
  appearance: none; -webkit-appearance: none; margin: 0; display: block; position: relative; cursor: pointer;
  width: 15px; height: 15px; border-radius: 4px; border: 1.5px solid var(--text-3); background: var(--bg);
  transition: background var(--t-fast), border-color var(--t-fast);
}
.check input:checked { background: var(--accent); border-color: var(--accent); }
.check input:checked::after {
  content: ''; position: absolute; left: 4px; top: 1px; width: 4px; height: 8px;
  border: solid #fff; border-width: 0 2px 2px 0; transform: rotate(45deg);
}
.check input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.row:hover .check, .row.checked .check, .list.selecting .check, .row .check:focus-within { opacity: 1; }
.row:hover .unread-dot, .row.checked .unread-dot, .list.selecting .unread-dot { opacity: 0; }
.row.checked { background: var(--sel); }
.row .row-actions {
  position: absolute; right: 8px; top: 7px; display: flex; gap: 1px; padding: 1px;
  border-radius: var(--radius-sm); background: var(--glass-solid);
  opacity: 0; pointer-events: none; transition: opacity var(--t-fast);
}
.row:hover .row-actions, .row .row-actions:focus-within { opacity: 1; pointer-events: auto; }
.row:hover .date { visibility: hidden; }
.row .row-actions .icon-btn { width: 26px; height: 26px; }
.icon-btn.danger:hover { color: var(--danger); background: var(--danger-bg); }
.row .mark.draft { color: var(--danger); }
@media (hover: none) {
  .row .row-actions { display: none; }
  .row:hover .date { visibility: visible; }
  .row .check { opacity: 1; }
  .row .unread-dot { opacity: 1; }
}

/* the bar that takes the list head's place while rows are selected */
.bulk-bar {
  position: absolute; top: 0; left: 0; right: 0; height: 44px; z-index: 4;
  display: flex; align-items: center; gap: 2px; padding: 0 10px 0 14px;
  border-bottom: 1px solid var(--hair-soft);
  background: var(--glass-solid);
  -webkit-backdrop-filter: blur(var(--glass-blur)); backdrop-filter: blur(var(--glass-blur));
  animation: rise-in var(--t);   /* --t already carries its easing */
}
.bulk-bar .spacer { flex: 1; }
.bulk-bar .n { font-size: 13px; font-weight: 600; margin-left: 8px; }
.bulk-bar .check { display: inline-flex; }

/* Focused | All above the inbox */
.list-tabs { display: flex; gap: 4px; padding: 6px 12px; border-bottom: 1px solid var(--hair-soft); flex: none; }
.list-tabs .tab {
  height: 26px; padding: 0 12px; border-radius: 999px; font-size: 12.5px; font-weight: 500; color: var(--text-2);
  transition: background var(--t-fast), color var(--t-fast);
}
.list-tabs .tab:hover { background: var(--hover); color: var(--text); }
.list-tabs .tab.active { background: var(--sel); color: var(--accent-text); }

/* an archived or trashed message says so above its body */
.reader-notice {
  display: flex; align-items: center; gap: 10px; margin: 0 32px 10px; padding: 8px 12px;
  border-radius: var(--radius-sm); background: var(--warn-bg); color: var(--text-2); font-size: 12.5px;
}
.reader-notice span { flex: 1; }

/* attachments in the compose sheet */
.compose-atts { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; padding: 8px 16px 0; }
.compose-atts .att.chip { padding-right: 4px; }
.compose-atts .att .rm { display: inline-flex; width: 20px; height: 20px; align-items: center; justify-content: center; border-radius: 50%; color: var(--text-3); }
.compose-atts .att .rm:hover { background: var(--hover); color: var(--text); }
.compose-atts .att.uploading { opacity: 0.6; }
.compose-atts .att.fwd { border-style: dashed; }
.compose-atts .att-total { font-size: 11.5px; color: var(--text-3); margin-left: 4px; }
.compose-atts .att-total.warn { color: var(--accent-2); }
.sheet.dragging { outline: 2px dashed var(--accent); outline-offset: -8px; }
.sheet.dragging::after {
  content: 'Drop files to attach'; position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-weight: 600; color: var(--accent-text); background: color-mix(in srgb, var(--accent) 8%, transparent);
  border-radius: inherit; pointer-events: none;
}

/* print: the open message and nothing else */
@media print {
  .topbar, .sidebar, .scrim, .list-pane, .thread-toolbar, .thread-panel, .sheet, #toasts, .reader-nav, .reader-notice,
  .msg-right .icon-btn, .msg-enrich, .related, .preview-bar { display: none !important; }
  .app, .panes, .thread-pane, .reader, .thread-scroll { display: block !important; height: auto !important; overflow: visible !important; position: static !important; }
  body { background: #fff !important; color: #000 !important; }
  .arrive { animation: none !important; }
}

/* Settings -> Appearance: pick the mark's plate by looking at it (SPEC 34). */
.logo-picker { display: flex; gap: 10px; flex-wrap: wrap; }
.logo-option {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 8px 10px 6px; border-radius: var(--radius);
  border: 1px solid transparent; background: transparent; cursor: pointer;
  font-size: 11.5px; color: var(--text-2);
  transition: background var(--t-fast), border-color var(--t-fast), color var(--t-fast);
}
.logo-option img { display: block; border-radius: 11px; }
.logo-option:hover { background: var(--hover); }
.logo-option.active { border-color: var(--accent); background: var(--sel); color: var(--accent-text); font-weight: 500; }
.logo-option:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ==========================================================================
   Writing tool, urgency, receipts and folders (SPEC 35)
   ========================================================================== */

/* the formatting bar above the body */
.write-bar {
  display: flex; align-items: center; flex-wrap: wrap; gap: 2px;
  padding: 6px 16px 4px;
}
.write-bar .wb {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: var(--radius-sm);
  color: var(--text-2); transition: background var(--t-fast), color var(--t-fast);
}
.write-bar .wb:hover { background: var(--hover); color: var(--text); }
.write-bar .wb.on { background: var(--sel); color: var(--accent-text); }
.write-bar .wb-sep { width: 1px; height: 16px; background: var(--hair); margin: 0 5px; }
.write-bar .wb-select {
  height: 26px; padding: 0 4px; border-radius: var(--radius-sm);
  border: 1px solid var(--hair); background: var(--bg); color: var(--text);
  font-size: 12px; max-width: 96px;
}
.write-bar .wb-select.sm { max-width: 80px; }
.write-bar .wb-colours { display: inline-flex; align-items: center; gap: 3px; }
.write-bar .swatch {
  width: 15px; height: 15px; border-radius: 50%; border: 1px solid var(--hair);
  cursor: pointer; transition: transform var(--t-fast);
}
.write-bar .swatch:hover { transform: scale(1.18); }
.write-bar .swatch.none { background: linear-gradient(135deg, var(--bg) 46%, var(--danger) 46%, var(--danger) 54%, var(--bg) 54%); }

/* the formatted editor sits exactly where the textarea does */
.body-wrap .rich {
  position: relative; z-index: 1; flex: 1; min-height: 220px;
  padding: 12px 16px; outline: none; overflow-y: auto;
  font-size: 14px; line-height: 1.55; color: var(--text);
}
.body-wrap .rich:empty::before { content: attr(data-placeholder); color: var(--text-3); }
.body-wrap .rich p { margin: 0 0 10px; }
.body-wrap .rich ul, .body-wrap .rich ol { margin: 0 0 10px; padding-left: 22px; }
.body-wrap .rich blockquote {
  margin: 0 0 10px; padding-left: 12px; border-left: 3px solid var(--hair); color: var(--text-2);
}
.body-wrap .rich a { color: var(--accent-text); text-decoration: underline; }

/* urgency and receipts */
.icon-btn.urgent { color: var(--danger); }
.icon-btn.quiet-flag { color: var(--text-3); }
.row .urgent-mark { color: var(--danger); display: inline-flex; }
.reader-notice.urgent { background: var(--danger-bg); color: var(--danger); }
.reader-notice.seen { background: var(--accent-bg); color: var(--accent-text); }
.reader-notice.warn { background: var(--warn-bg); color: var(--warn); }

/* the two-line rows in the receipt menu */
.menu.wide { min-width: 268px; }
.menu .menu-note { padding: 6px 10px 4px; font-size: 11.5px; color: var(--text-3); }
.menu .menu-note.faint { border-top: 1px solid var(--hair-soft); margin-top: 4px; padding-top: 6px; }
.menu button.stack {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  height: auto; padding: 7px 10px; line-height: 1.35;
}
.menu button.stack small { color: var(--text-3); font-size: 11px; white-space: normal; }
.menu button.on { background: var(--sel); color: var(--accent-text); }
.menu button.on small { color: inherit; opacity: 0.8; }

/* rename / delete on a folder, on hover only */
.side-item .side-more { display: flex; gap: 1px; margin-left: auto; opacity: 0; transition: opacity var(--t-fast); }
.side-item:hover .side-more, .side-item .side-more:focus-within { opacity: 1; }
.side-item .side-more button {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; border-radius: 5px; color: var(--text-3);
}
.side-item .side-more button:hover { background: var(--hover); color: var(--text); }
.side-item:hover .count { display: none; }
@media (hover: none) { .side-item .side-more { display: none; } }

/* ==========================================================================
   Profile picture and the account menu (SPEC 37)
   ========================================================================== */

.avatar.has-image { background: none; padding: 0; overflow: hidden; }
.avatar.has-image img { width: 100%; height: 100%; object-fit: cover; display: block; }
.avatar.lg { width: 84px; height: 84px; font-size: 28px; }

/* the face in the top bar */
.profile-btn {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0; margin-left: 4px; border-radius: 50%; cursor: pointer;
  border: 1px solid var(--hair); background: none;
  transition: box-shadow var(--t-fast), border-color var(--t-fast);
}
.profile-btn:hover { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-bg); }
.profile-btn[aria-expanded="true"] { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-bg); }
.profile-btn .avatar { width: 30px; height: 30px; font-size: 11.5px; }

.profile-menu { min-width: 244px; }
.profile-menu .profile-head {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 10px 12px; border-bottom: 1px solid var(--hair-soft); margin-bottom: 4px;
}
.profile-menu .profile-head .who { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.profile-menu .profile-head strong { font-size: 13.5px; }
.profile-menu .profile-head span { font-size: 11.5px; color: var(--text-3); }
.profile-menu .menu-note div { line-height: 1.6; }
.profile-menu button.danger { color: var(--danger); }
.profile-menu button.danger:hover { background: var(--danger-bg); }

/* the picture row in Settings → Account */
.avatar-row .avatar-edit { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.avatar-row .avatar-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.avatar-row .avatar-actions .form-hint { flex-basis: 100%; margin: 0; }
.btn.quiet.danger { color: var(--danger); }
.btn.quiet.danger:hover { background: var(--danger-bg); }

/* the cropper */
.crop-card { width: min(440px, 94vw); }
.crop-hint { margin: 0 0 12px; font-size: 12.5px; color: var(--text-2); }
.crop-stage {
  position: relative; width: 360px; max-width: 100%; aspect-ratio: 1;
  margin: 0 auto; border-radius: var(--radius-lg); overflow: hidden;
  background: var(--bg-3); cursor: grab; touch-action: none;
}
.crop-stage.dragging { cursor: grabbing; }
.crop-stage canvas { display: block; width: 100%; height: 100%; }
/* the circle is a mask drawn over the square, so what you see is what is kept */
.crop-stage::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  border-radius: var(--radius-lg);
  box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.45);
  -webkit-mask: radial-gradient(circle at 50% 50%, transparent 49.5%, #000 50%);
  mask: radial-gradient(circle at 50% 50%, transparent 49.5%, #000 50%);
}
.crop-zoom { display: flex; align-items: center; gap: 12px; margin: 14px 2px 0; font-size: 12.5px; color: var(--text-2); }
.crop-zoom input { flex: 1; }

/* ==========================================================================
   Folding: sidebar sections and the list's day bands (SPEC 38)
   ========================================================================== */

.side-title .side-fold {
  display: flex; align-items: center; gap: 5px; flex: 1; min-width: 0;
  font: inherit; color: inherit; text-transform: inherit; letter-spacing: inherit;
  padding: 0; cursor: pointer;
}
.side-title .side-fold:hover { color: var(--text-2); }
.side-title .side-fold .icon { transition: transform var(--t-fast); flex: none; }
.side-section.collapsed .side-fold .icon { transform: rotate(-90deg); }
/* Same fold as the list's day bands, so the two read as one gesture. */
.side-body {
  display: grid; grid-template-rows: 1fr;
  transition: grid-template-rows var(--t-slide);
}
.side-section.collapsed .side-body { grid-template-rows: 0fr; }
.side-body > .side-body-inner {
  overflow: hidden; min-height: 0; display: flex; flex-direction: column;
  transition: opacity var(--t-fade), transform var(--t-slide);
}
.side-section.collapsed .side-body-inner { opacity: 0; transform: translateY(calc(-1 * var(--travel))); }

/* The day band above a run of messages. It has to read as a divider at a
   glance, so it is a filled strip in the raised tone rather than a tinted line:
   --bg-3 is lighter than the list on dark and darker on light, which is the
   contrast a heading needs on both. Opaque, too -- it is sticky, and rows
   scrolling under a translucent heading was the thing that made it unreadable. */
.day-head {
  position: sticky; top: 0; z-index: 2;
  display: flex; align-items: center; gap: 7px;
  /* the same 30px as a sidebar item, so the two rhythms agree */
  width: 100%; height: 30px; padding: 0 14px 0 9px;
  margin-top: 8px;
  background: var(--bg-3);
  border-bottom: 1px solid var(--hair-soft);
  color: var(--text); font-size: 12px; font-weight: 600; letter-spacing: -0.05px;
  text-align: left; cursor: pointer;
  transition: background var(--t-fast);
}
/* the first band sits straight under the tabs, with nothing above to separate */
.list > .day-head:first-child { margin-top: 0; }
.day-head:hover { background: color-mix(in srgb, var(--accent) 9%, var(--bg-3)); }
.day-head .icon { color: var(--text-3); transition: transform var(--t-fast); flex: none; }
.day-head:hover .icon { color: var(--text-2); }
.day-head.collapsed .icon { transform: rotate(-90deg); }
.day-head .label { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.day-head .when { color: var(--text-3); font-weight: 400; font-size: 11px; white-space: nowrap; }
.day-head .spacer { flex: 1; }
.day-head .count {
  color: var(--text-3); font-weight: 500; font-size: 10.5px; font-variant-numeric: tabular-nums;
}
/* a folded band keeps a hint that something is behind it */
.day-head.collapsed { color: var(--text-2); }
.day-head.collapsed .count {
  background: var(--accent-bg); color: var(--accent-text); font-weight: 600;
  border-radius: 999px; padding: 1px 7px;
}
/* The fold itself. A run of rows has no height anyone can name in advance, so
   the wrapper is a one-row grid and the row goes 1fr -> 0fr: the browser
   interpolates it, nothing has to be measured, and it works the same whether a
   band holds two messages or two hundred. */
.day-rows {
  display: grid; grid-template-rows: 1fr;
  /* --t-slide, the same expo-out the thread panel comes in on. Long enough
     to be seen as a movement rather than registered as a jump, and it already
     carries its easing -- adding another lands it where the delay goes and the
     browser drops the whole line. */
  transition: grid-template-rows var(--t-slide);
}
.day-group.collapsed .day-rows { grid-template-rows: 0fr; }
/* The overflow has to live on an inner box: a grid row of 0fr still shows what
   overflows it. */
.day-rows-inner { overflow: hidden; min-height: 0; }
/* The rows travel with the fold rather than only being clipped by it: they lift
   a few pixels on the way up and settle back on the way down, which is what
   makes the direction readable instead of the run simply ceasing to exist. */
.day-rows-inner {
  transition: opacity var(--t-fade), transform var(--t-slide);
}
.day-group.collapsed .day-rows-inner { opacity: 0; transform: translateY(calc(-1 * var(--travel))); }
.app.dense .day-head { height: 26px; margin-top: 6px; }

/* The end of the archive, said out loud (SPEC 39.6). A list that simply stops
   looks like a list that has not finished loading; this line says which it is,
   and only once the server has agreed there is nothing older. */
.list-end {
  padding: 18px 20px calc(24px + var(--safe-bottom));
  text-align: center; font-size: 12px; line-height: 1.5; color: var(--text-3);
}

/* which folders an account pulls, on its card in Mailboxes (SPEC 39.4) */
.acct .acct-folders { margin-top: 8px; font-size: 12.5px; color: var(--text-2); }

/* the chime pickers in Settings → Notifications (SPEC 40) */
.sound-row { display: flex; align-items: center; gap: 10px; }
.sound-row select { flex: 1; min-width: 0; }
.sound-row input[type="range"] { flex: 1; }
.sound-row .btn { flex: none; gap: 6px; }
.sound-vol { font-size: 12px; color: var(--text-3); font-variant-numeric: tabular-nums; min-width: 38px; text-align: right; }


/* ==========================================================================
   The glass stack (SPEC 53)
   --------------------------------------------------------------------------
   The mark is three sheets of glass, mail arriving already sorted, and only
   the front one asks for you. Past a phone's width the app is drawn the same
   way, so the logo and the screen tell one story:

   - the ground is a cool field, the brand blue and the amber faint in it;
   - the mailboxes sit on the field as the back sheet, the list is the middle
     sheet, and the message is the front one: solid, lifted, in reach;
   - a chosen row, a chosen mailbox, is pulled forward as a small front sheet
     of its own, instead of being tinted and underlined;
   - separators give way to space, and titles take the display face.

   Layout, behaviour and motion are untouched: this block only paints. The
   phone keeps its own Liquid Glass layer below, which already floats its
   controls the same way.
   ========================================================================== */

.list-head h2, .reader-head h1, .brand .name, .sheet-head h2, .modal-head h2 {
  font-family: var(--font-display);
}
.reader-head h1 { font-weight: 650; letter-spacing: -0.02em; }

/* "Waiting on you" counts in the amber that means it, as a small pill: the
   one number in the sidebar that is a request rather than a total. */
.side-item.awaiting .count {
  min-width: 20px; height: 18px; padding: 0 6px; border-radius: 999px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--accent-2-bg); color: var(--accent-2); font-weight: 600;
}

@media (min-width: 700px) {
  .app { background: transparent; }

  /* ---- the bar: on the field, with only the search as glass ------------- */
  .topbar {
    background: transparent; border-bottom: 0; box-shadow: none;
    -webkit-backdrop-filter: none; backdrop-filter: none;
    padding-left: calc(var(--gap-sheet) + 6px + var(--safe-left));
    padding-right: calc(var(--gap-sheet) + var(--safe-right));
  }
  .brand .name { font-weight: 650; letter-spacing: -0.03em; }
  .brand .logo { box-shadow: 0 6px 16px -4px color-mix(in srgb, var(--accent) 45%, transparent); }
  .search {
    height: 36px; border-radius: 999px; padding: 0 14px;
    background: var(--sheet-back); border: 1px solid var(--sheet-rim);
    -webkit-backdrop-filter: blur(18px) saturate(160%); backdrop-filter: blur(18px) saturate(160%);
  }
  .search:focus-within { background: var(--sheet-front); box-shadow: 0 0 0 1.5px var(--accent), var(--sheet-lift); }
  .search .kbd { border-radius: 6px; }

  /* ---- three sheets ---------------------------------------------------- */
  .panes {
    column-gap: var(--gap-sheet);
    padding: 0 calc(var(--gap-sheet) + var(--safe-right)) calc(var(--gap-sheet) + var(--safe-bottom)) calc(var(--gap-sheet) + var(--safe-left));
  }
  .sidebar {
    background: var(--sheet-back); border: 1px solid var(--sheet-rim); border-radius: var(--radius-sheet);
    -webkit-backdrop-filter: none; backdrop-filter: none;
    padding: 12px 10px 14px;
  }
  .list-pane {
    background: var(--sheet-mid); border: 1px solid var(--sheet-rim); border-radius: var(--radius-sheet);
    box-shadow: var(--sheet-shadow);
  }
  .thread-pane {
    background: var(--sheet-front); border: 1px solid var(--sheet-rim); border-radius: var(--radius-sheet);
    box-shadow: var(--sheet-shadow);
  }
  .list-head, .thread-toolbar {
    background: transparent; border-bottom: 0;
    -webkit-backdrop-filter: none; backdrop-filter: none;
  }
  .list-head { height: 52px; padding: 0 18px; }
  .list-head h2 { font-size: 21px; font-weight: 650; letter-spacing: -0.025em; }
  .thread-toolbar { height: 50px; padding: 0 14px; }
  .list-tabs { border-bottom: 0; padding: 0 14px 8px; }

  /* ---- the sidebar: a chosen mailbox comes forward ---------------------- */
  .side-item { height: 32px; border-radius: 10px; }
  .side-item:hover { background: color-mix(in srgb, var(--sheet-front) 55%, transparent); }
  .side-item.active {
    background: var(--sheet-pick); color: var(--text); box-shadow: var(--sheet-lift);
  }
  .side-item.active .icon { color: var(--accent); }
  .side-item.active .count { color: var(--text-2); }
  .side-item.awaiting.active .count { color: var(--accent-2); }

  /* ---- the list: rows on space, the chosen one lifted ------------------- */
  .list { padding: 0 8px var(--safe-bottom); }
  .row {
    border-bottom: 0; border-radius: 14px;
    padding: 11px 14px 11px 8px; margin: 1px 0;
  }
  .row:hover { background: color-mix(in srgb, var(--text) 4%, transparent); }
  .row.selected {
    background: var(--sheet-pick); box-shadow: var(--sheet-lift);
  }
  .row .check { left: 6px; }
  /* A day is a quiet label over its run of mail, not a filled strip across
     the sheet. No backdrop blur: it is sticky, and a blur there is
     recomputed on every frame of every scroll. */
  .day-head {
    height: 30px; margin-top: 10px; padding: 0 10px 0 8px; border-radius: 10px;
    background: var(--sheet-mid);
    border-bottom: 0; color: var(--text-2); font-weight: 600;
  }
  /* A long inbox: the browser skips laying out and painting days that are
     off screen, and remembers each one's height once it has been seen. */
  .day-group { content-visibility: auto; contain-intrinsic-size: auto 480px; }
  .day-head:hover { background: color-mix(in srgb, var(--accent) 7%, var(--sheet-mid)); }
  .day-head .when { color: var(--text-3); }
  .skel-row { border-bottom: 0; padding: 12px 14px; }

  /* ---- the front sheet: the message ------------------------------------ */
  .reader-head { padding: 26px 34px 8px; }
  .reader-head h1 { font-size: 25px; line-height: 1.22; }
  .msg-head { border-bottom: 0; padding-left: 34px; padding-right: 34px; }
  .msg-enrich, .body-tools, .attachments { padding-left: 34px; padding-right: 34px; }
  .msg-fold { border-top: 0; padding-left: 34px; padding-right: 34px; border-radius: 0; }
  .msg-newer { padding-left: 34px; padding-right: 34px; }
  .messages .msg + .msg, .messages .msg-fold + .msg { border-top: 1px solid var(--hair-soft); }
  .msg-body { padding: 16px 34px 14px; }
  /* Already on the front sheet: the body no longer needs a card of its own,
     only an edge where the sender's white page meets it. */
  .msg-body iframe { box-shadow: none; border: 1px solid var(--hair-soft); border-radius: 16px; }
  .msg-body pre.plain { box-shadow: none; background: var(--bg-2); border-radius: 16px; padding: 16px 20px; }
  .att { border-radius: 12px; background: var(--bg-2); border-color: transparent; }
  .att:hover { background: var(--bg-3); border-color: transparent; }
}

/* The bar keeps the sheets' own columns, so nothing in it floats at an
   arbitrary spot: the wordmark stands over the mailboxes, the search over
   the list it filters, Compose on the left edge of the reader, where a new
   message opens -- on the sheet's own edge, the way the search pill sits on
   the list's -- and the status and account controls on the reader's right. */
@media (min-width: 1100px) {
  .topbar {
    display: grid; align-items: center;
    /* Compose has a column of its own, so a narrow reader can never put the status
       and account controls on top of it: they take what is left and stay to its right. */
    grid-template-columns: var(--sidebar-w) var(--list-w) auto minmax(min-content, 1fr);
    column-gap: var(--gap-sheet);
    padding-left: calc(var(--gap-sheet) + var(--safe-left));
    padding-right: calc(var(--gap-sheet) + var(--safe-right));
  }
  .topbar .brand { grid-column: 1; grid-row: 1; justify-self: start; min-width: 0; padding: 0 0 0 10px; }
  .topbar .search { grid-column: 2; grid-row: 1; max-width: none; margin: 0; }
  .topbar #composeBtn { grid-column: 3; grid-row: 1; justify-self: start; margin-left: 0; }
  .topbar .topbar-right { grid-column: 4; grid-row: 1; justify-self: end; padding-right: 6px; }
}

/* Until the reader is wide enough for the words, Calendar and Refresh keep their
   icons only, as they already do below 900px (their tooltips still say what they are). */
@media (min-width: 1100px) and (max-width: 1379px) {
  #syncBtn .label, #calendarBtn .label { display: none; }
  #syncBtn, #calendarBtn { width: 34px; padding: 0; justify-content: center; }
  .status-chip .text-long { display: none; }
}

/* The gaps between sheets cost the reader 40px, which is where Reply, Reply
   all and Forward kept their labels; until the reader has room again they
   keep their icons, as they already did below 1100px. */
@media (min-width: 1100px) and (max-width: 1279px) {
  .thread-toolbar .btn .label { display: none; }
  .thread-toolbar .btn { width: 34px; padding: 0; justify-content: center; }
  .thread-toolbar .thread-btn { width: auto; padding: 0 10px; }
}

/* Too narrow for three columns: the mailboxes become a drawer, and a drawer
   is a sheet pulled over the others, so it is solid and it keeps its edge. */
@media (min-width: 700px) and (max-width: 1099px) {
  /* It opens under the bar, which is clear now: the bar's controls stay
     over the field and the drawer never slides beneath them. */
  .sidebar {
    top: calc(var(--topbar-h) + var(--safe-top)); bottom: var(--gap-sheet); left: var(--gap-sheet);
    padding-top: 12px;
    background: var(--glass-solid); border-radius: var(--radius-sheet);
    -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(180%);
    backdrop-filter: blur(var(--glass-blur)) saturate(180%);
    transform: translateX(calc(-100% - 2 * var(--gap-sheet)));
  }
}

@media (prefers-reduced-transparency: reduce) {
  .sidebar, .search { -webkit-backdrop-filter: none; backdrop-filter: none; }
  :root { --sheet-back: var(--bg-2); --sheet-mid: var(--bg); }
}


/* ==========================================================================
   iPhone: Liquid Glass (SPEC 50)
   --------------------------------------------------------------------------
   The phone layout used to be the desktop one, squeezed: a crowded top bar,
   filled day bands with counts, a checkbox on every row. This is the phone
   drawn the way iOS 26 draws it, for an iPhone 15 Pro (393 x 852, Dynamic
   Island, home indicator) and everything around it:

   - controls float as glass -- translucent, blurred, a hairline edge and a
     light catch along the top -- and the mail scrolls underneath them;
   - search and Compose sit at the bottom, where the thumb already is;
   - a large title names the mailbox; rows read like Mail's;
   - in a message, one glass bar of actions floats above the home indicator.

   Everything is in this one block and inside this one query, so the desktop
   and tablet layouts are untouched by it.
   ========================================================================== */

@media (max-width: 699px) {
  .app {
    --float-gap: 10px;
    --float-h: 50px;
    /* room the floating bar takes over the bottom of a scrolling pane */
    --float-room: calc(var(--float-h) + var(--float-gap) * 2 + var(--safe-bottom));
  }

  /* ---- the glass itself ------------------------------------------------ */
  .topbar .menu-btn,
  .topbar .back-btn,
  .topbar #syncBtn,
  .topbar #calendarBtn,
  .app[data-view="list"] #searchBox,
  .app[data-view="list"] #composeBtn,
  .app[data-view="thread"] .thread-toolbar {
    background: var(--glass);
    -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(180%);
    backdrop-filter: blur(var(--glass-blur)) saturate(180%);
    border: 0.5px solid var(--glass-border);
    box-shadow: 0 8px 28px rgba(0, 0, 0, 0.16), inset 0 1px 0 var(--glass-hi);
    transition: transform var(--t-fast), background var(--t-fast);
  }
  .topbar .menu-btn:active,
  .topbar .back-btn:active,
  .topbar #syncBtn:active,
  .topbar #calendarBtn:active,
  .app[data-view="list"] #composeBtn:active { transform: scale(0.92); }

  /* ---- top: only round glass buttons over the page ---------------------- */
  .topbar {
    height: calc(56px + var(--safe-top));
    padding: var(--safe-top) calc(16px + var(--safe-right)) 0 calc(16px + var(--safe-left));
    gap: 10px;
    background: var(--bg);
    border-bottom: 0; box-shadow: none;
    /* Not glass itself: a backdrop-filter makes the bar the containing block
       for its position:fixed children, and search and Compose -- which live in
       it -- would float at the bottom of the bar instead of the screen. */
    -webkit-backdrop-filter: none; backdrop-filter: none;
  }
  .topbar .menu-btn, .topbar .back-btn { width: 40px; height: 40px; border-radius: 50%; color: var(--text); }
  .topbar-right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
  .topbar #syncBtn, .topbar #calendarBtn { width: 40px; height: 40px; padding: 0; border-radius: 50%; color: var(--text); }
  .topbar #calendarBtn.active { color: var(--accent-text); }
  .topbar #syncBtn .dot.error, .topbar #syncBtn .dot.off { top: 4px; right: 4px; }
  .profile-btn { width: 40px; height: 40px; }
  .profile-btn .avatar { width: 36px; height: 36px; }
  /* reading or writing: the way back and nothing else competes for the top */
  .app[data-view="thread"] .topbar-right,
  .app[data-view="compose"] .topbar-right { display: none; }

  /* ---- bottom: search and Compose, floating over the list --------------- */
  .app[data-view="list"] #searchBox {
    position: fixed; z-index: 31;
    left: calc(16px + var(--safe-left));
    right: calc(16px + var(--float-h) + 10px + var(--safe-right));
    bottom: calc(var(--float-gap) + var(--safe-bottom));
    height: var(--float-h); max-width: none; margin: 0; padding: 0 16px;
    border-radius: calc(var(--float-h) / 2);
    color: var(--text-2);
  }
  .app[data-view="list"] #searchBox:focus-within { box-shadow: 0 8px 28px rgba(0, 0, 0, 0.2), 0 0 0 1.5px var(--accent); }
  .app[data-view="list"] #searchBox input { font-size: 17px; }   /* 17px also keeps iOS from zooming in on focus */
  .search-hints { top: auto; bottom: calc(100% + 8px); border-radius: var(--radius-lg); }
  .app[data-view="list"] #composeBtn {
    position: fixed; z-index: 31;
    right: calc(16px + var(--safe-right));
    bottom: calc(var(--float-gap) + var(--safe-bottom));
    width: var(--float-h); height: var(--float-h); padding: 0;
    border-radius: 50%; justify-content: center;
    /* tinted glass: the one coloured control on the screen */
    background: color-mix(in srgb, var(--accent) 86%, transparent);
    color: #fff;
  }
  .app[data-view="list"] #composeBtn .icon { width: 22px; height: 22px; }
  .app:not([data-view="list"]) #searchBox,
  .app:not([data-view="list"]) #composeBtn { display: none; }
  .app.sidebar-open #searchBox, .app.sidebar-open #composeBtn { visibility: hidden; }
  .toasts { bottom: calc(var(--float-room) + 6px); }

  /* ---- the list ---------------------------------------------------------- */
  .list-head { height: auto; padding: 2px 20px 10px; border-bottom: 0; align-items: baseline; }
  .list-head h2 { font-size: 32px; font-weight: 700; letter-spacing: -0.6px; line-height: 1.15; }
  .list-head .count { font-size: 15px; }
  .list-tabs { border-bottom: 0; padding: 0 20px 8px; gap: 6px; }
  .list-tabs .tab { height: 32px; padding: 0 14px; border-radius: 16px; font-size: 14px; }
  .list { padding-bottom: var(--float-room); }

  .day-head {
    height: 32px; margin-top: 10px; padding: 0 20px;
    background: var(--bg); border-bottom: 0;
    font-size: 13px; color: var(--text-2);
  }
  .day-head:hover { background: var(--bg); }
  .day-head .count { display: none; }

  .row {
    grid-template-columns: 12px minmax(0, 1fr) auto;
    column-gap: 8px; row-gap: 2px;
    padding: 12px 20px 12px 8px;
    border-bottom: 0; min-height: 76px;
  }
  /* inset separator, starting under the text as in Mail */
  .row::after {
    content: ""; position: absolute; left: 28px; right: 0; bottom: 0;
    height: 1px; background: var(--hair-soft);
  }
  .row.selected { box-shadow: none; }
  .row .unread-dot { width: 10px; height: 10px; margin-top: 6px; }
  .row .from { font-size: 16.5px; }
  .row .date { font-size: 14px; }
  .row .subject { font-size: 15px; }
  .row .snippet { font-size: 15px; line-height: 1.35; -webkit-line-clamp: 2; }
  .row .meta { font-size: 13px; margin-top: 2px; }
  /* no checkbox on every row: selecting is a desktop gesture */
  .row .check { display: none; }
  .list.selecting .row .check { display: block; }

  /* ---- a message ----------------------------------------------------------- */
  .reader-head { padding: 8px 20px 4px; }
  .reader-head h1 { font-size: 24px; font-weight: 700; letter-spacing: -0.4px; line-height: 1.2; }
  .msg-head, .msg-enrich, .body-tools, .attachments, .msg-fold, .msg-newer { padding-left: 20px; padding-right: 20px; }
  .msg-body { padding: 12px 12px 6px; }
  .thread-scroll { padding-bottom: var(--float-room); }
  /* Sender, recipients, then the date under them, as Mail sets it. The row of
     reply/flag/read buttons beside the name is the floating bar's job here --
     side by side, the name was left a column one word wide. */
  .msg-head { grid-template-columns: auto minmax(0, 1fr); column-gap: 12px; row-gap: 2px; }
  .msg-right { grid-column: 2; padding-top: 0; }
  .msg-right .icon-btn { display: none; }
  .msg-right .date { font-size: 13px; padding-right: 0; }
  .msg-who .name { font-size: 16px; }

  .app[data-view="thread"] .thread-toolbar {
    position: fixed; z-index: 31;
    left: calc(16px + var(--safe-left)); right: calc(16px + var(--safe-right));
    bottom: calc(var(--float-gap) + var(--safe-bottom));
    height: var(--float-h); padding: 0 6px; gap: 0;
    border-radius: calc(var(--float-h) / 2);
    justify-content: space-between;
  }
  .app[data-view="thread"] .thread-toolbar .spacer,
  .app[data-view="thread"] .thread-toolbar .tb-sep,
  .app[data-view="thread"] .thread-toolbar [title^="Reply all"],
  .app[data-view="thread"] .thread-toolbar [aria-label="Print"],
  .app[data-view="thread"] .thread-toolbar [aria-label="Toggle read"] { display: none; }
  .app[data-view="thread"] .thread-toolbar .btn,
  .app[data-view="thread"] .thread-toolbar .icon-btn {
    width: 42px; height: 42px; padding: 0; border-radius: 50%;
    justify-content: center; background: transparent; box-shadow: none; color: var(--text);
  }
  .app[data-view="thread"] .thread-toolbar .icon-btn.danger { color: var(--danger); }
  .app[data-view="thread"] .thread-toolbar .thread-btn .label,
  .app[data-view="thread"] .thread-toolbar .thread-btn .count { display: none; }
  .app[data-view="thread"] .thread-toolbar .thread-btn.active { color: var(--accent-text); }

  /* ---- sheets: rounded, with the page showing above them ------------------ */
  .sheet { height: calc(100% - 8px); border-radius: 22px 22px 0 0; }
  .modal { padding: calc(var(--safe-top) + 10px) 0 0; }
  .modal-card { border-radius: 22px 22px 0 0; }

  /* ---- the mailboxes drawer, at finger size ------------------------------- */
  /* it opens under the floating top buttons, so it starts below them */
  .sidebar { padding-top: calc(56px + var(--safe-top) + 6px); }
  .side-item { height: 44px; padding: 0 12px; border-radius: 12px; font-size: 16px; gap: 12px; }
  .side-title { font-size: 13px; padding: 10px 12px 6px; }
}


/* ==========================================================================
   Welcome: the first screen, and a guided setup (SPEC 51, drawn per SPEC 53)
   --------------------------------------------------------------------------
   The page tells the mark's story: a letter used to be something you open,
   and by 2030 it is glass. So the page is a bento of glass sheets on the
   field, the inbox in the hero is drawn as the mark's stack -- settled mail
   behind, the one message that needs you in front -- and the setup card is
   itself a front sheet with two sheets standing behind it. Colour is spent
   where the app spends it: blue for the one action and the count, amber
   only for what needs you, green for what is settled.
   ========================================================================== */

/* The app pins html and body to the viewport and scrolls inside its panes. A
   page that scrolls as a whole has to release both: releasing body alone left
   html clipping it, and the welcome page could not be scrolled at all. */
html.page-scroll, html.page-scroll body { height: auto; min-height: 100%; overflow-y: visible; }
/* Only the root trims sideways overflow, and with clip where it exists: hidden on
   body as well made body a second scroll container, and a phone's scroll could
   catch on it and stop (SPEC 72). */
html.page-scroll { overflow-x: hidden; }
@supports (overflow-x: clip) { html.page-scroll { overflow-x: clip; } }
html.page-scroll body { overflow-x: visible; }
/* the sticky nav must never cover what keyboard focus or an anchor lands on */
html.page-scroll { scroll-padding-top: calc(88px + var(--safe-top)); }
body[data-page="welcome"] { color: var(--text); -webkit-font-smoothing: antialiased; }
.login-more { font-size: 12.5px; color: var(--text-2); text-align: center; }
.login-more:hover { color: var(--accent-text); }

/* ---- navigation: a glass bar floating over the page ----------------------- */
.wn {
  position: sticky; top: calc(12px + var(--safe-top)); z-index: 10;
  display: flex; align-items: center; justify-content: space-between;
  max-width: calc(clamp(1200px, 80vw, 1480px) - 40px); margin: calc(12px + var(--safe-top)) auto 0;
  width: calc(100% - 2 * (20px + var(--safe-left)));
  padding: 8px 8px 8px 12px; border-radius: 999px;
  background: var(--sheet-back); border: 1px solid var(--sheet-rim);
  box-shadow: var(--sheet-shadow);
  -webkit-backdrop-filter: saturate(170%) blur(20px); backdrop-filter: saturate(170%) blur(20px);
}
.wn-brand {
  display: inline-flex; align-items: center; gap: 10px; color: var(--text); text-decoration: none;
  font-family: var(--font-display); font-weight: 650; font-size: 19px; letter-spacing: -0.03em;
}
.wn-brand img { border-radius: 8px; }
.wn-links { display: flex; align-items: center; gap: 6px; font-size: 14px; }
.wn-links a { display: inline-flex; align-items: center; height: 36px; padding: 0 14px; border-radius: 999px; color: var(--text-2); text-decoration: none; transition: background var(--t-fast), color var(--t-fast); }
.wn-links a:hover { color: var(--text); background: color-mix(in srgb, var(--sheet-front) 60%, transparent); }
.wn-links .wn-cta { background: var(--accent); color: #fff; font-weight: 500; }
.wn-links .wn-cta:hover { background: color-mix(in srgb, var(--accent) 88%, black); color: #fff; }

/* ---- shared ------------------------------------------------------------- */
.skip-link {
  position: absolute; left: 16px; top: -60px; z-index: 20;
  padding: 10px 16px; border-radius: 999px; background: var(--accent); color: #fff; font-size: 14px;
}
.skip-link:focus-visible { top: calc(12px + var(--safe-top)); }
.welcome a, .welcome button, .wn a, .welcome input { touch-action: manipulation; }
.welcome a:focus-visible, .welcome button:focus-visible, .wn a:focus-visible,
.welcome .switch input:focus-visible, .welcome .text-input:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 3px;
}
.welcome h1, .welcome h2 { text-wrap: balance; font-family: var(--font-display); }
.welcome p { text-wrap: pretty; }
.welcome {
  /* grows with a wide screen up to a comfortable measure, then the scale takes over (SPEC 70) */
  max-width: clamp(1200px, 80vw, 1480px); margin: 0 auto;
  padding: 20px calc(20px + var(--safe-right)) calc(40px + var(--safe-bottom)) calc(20px + var(--safe-left));
  display: flex; flex-direction: column; gap: 12px;
}
.welcome h1, .welcome h2 { color: var(--text); font-weight: 650; margin: 0; }

/* A tile is a sheet of glass on the field. The field behind it is a soft
   gradient with nothing to blur, so the glass is its fill and rim alone:
   a backdrop blur on every tile cost a repaint of each on every scroll. */
.welcome .tile {
  border-radius: 28px; padding: 32px;
  background: var(--sheet-back); border: 1px solid var(--sheet-rim);
  min-width: 0;
}
.wt-copy p, .wt-hero p { color: var(--text-2); }

.w-cta {
  display: inline-flex; align-items: center; justify-content: center;
  height: 48px; padding: 0 26px; border-radius: 999px;
  background: var(--accent); color: #fff; font-size: 16px; font-weight: 500; text-decoration: none;
  box-shadow: 0 10px 24px -10px color-mix(in srgb, var(--accent) 70%, transparent);
  transition: background var(--t-fast), transform var(--t-fast);
}
.w-cta:hover { background: color-mix(in srgb, var(--accent) 88%, black); }
.w-cta:active { transform: scale(0.98); }
.w-link { font-size: 16px; color: var(--accent-text); text-decoration: none; }
.w-link:hover { text-decoration: underline; }

/* ---- hero --------------------------------------------------------------- */
.wh {
  display: grid; gap: 12px;
  grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
  grid-template-areas: "hero stack" "hero count";
}
.wt-hero {
  grid-area: hero; display: flex; flex-direction: column; justify-content: flex-end;
  min-height: 520px; padding: 44px;
  background: var(--sheet-mid);
}
.wh h1 { font-size: clamp(42px, 5.4vw, 72px); line-height: 1.0; letter-spacing: -0.04em; max-width: 14ch; }
/* "20" and its reel are one word: the line may never break between them. */
.yr-year { white-space: nowrap; }
/* The year's reel: a four-sided glass cube turning about its horizontal axis.
   Each face stands a quarter turn below the last, pushed out by half the
   cube's height, and the cube is pulled back by the same half so its front
   face sits exactly on the line of type. */
.yr {
  --yr-h: 0.96em;
  display: inline-block; position: relative; vertical-align: -0.1em;
  width: 1.22em; height: var(--yr-h); margin-left: 0.02em;
  perspective: 7em;
}
.yr-cube {
  position: absolute; inset: 0; transform-style: preserve-3d;
  transform: translateZ(calc(var(--yr-h) / -2)) rotateX(var(--yr-turn, 0deg));
  will-change: transform;   /* turned frame by frame from app.js: no transition to lag behind it */
}
.yr-face {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  border-radius: 0.14em; line-height: 1;
  background: color-mix(in srgb, var(--sheet-front) 80%, transparent);
  border: 1px solid var(--sheet-rim);
  box-shadow: inset 0 1px 0 var(--glass-hi), var(--sheet-lift);
  color: var(--accent-text); font-variant-numeric: tabular-nums;
  -webkit-backface-visibility: hidden; backface-visibility: hidden;
  /* a faint smear at speed, none at rest */
  filter: blur(calc(var(--yr-blur, 0) * 0.03em));
}
.yr-face:nth-child(1) { transform: rotateX(0deg) translateZ(calc(var(--yr-h) / 2)); }
.yr-face:nth-child(2) { transform: rotateX(-90deg) translateZ(calc(var(--yr-h) / 2)); }
.yr-face:nth-child(3) { transform: rotateX(-180deg) translateZ(calc(var(--yr-h) / 2)); }
.yr-face:nth-child(4) { transform: rotateX(-270deg) translateZ(calc(var(--yr-h) / 2)); }
.wh-lede { margin: 24px 0 0; max-width: 34em; font-size: clamp(17px, 1.5vw, 19px); line-height: 1.55; }
.wh-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 24px; margin-top: 32px; }

/* the inbox as the mark: three sheets, the front one needs you */
.wt-stack { grid-area: stack; display: flex; align-items: flex-end; justify-content: center; padding: 28px 28px 32px; margin: 0; }
.gs { position: relative; width: min(100%, 420px); display: grid; grid-template-columns: minmax(0, 1fr); cursor: pointer; outline: none; -webkit-tap-highlight-color: transparent; }
.gs:focus-visible { outline: 2px solid var(--accent); outline-offset: 8px; border-radius: 24px; }
/* A deck of glass (SPEC 66). Every card carries a whole message; where it sits
   decides how much of it shows. The cards behind only peek out above the front
   one, so they show one line -- who, and the mark that says whether it is
   settled -- in the strip that stays uncovered. A tap sends the front card to
   the back: its layer drops through the others while it rises and shrinks, and
   the next card grows forward into its place. */
.gs-sheet {
  grid-area: 1 / 1; align-self: start;
  display: flex; flex-direction: column; padding: 0 18px 8px;
  border-radius: 20px; border: 1px solid var(--sheet-rim); font-size: 13px;
  transition: margin var(--t-slide), padding var(--t-slide), background var(--t-slide), box-shadow var(--t-slide),
    transform var(--t-slide), opacity var(--t-fade), color var(--t-slide), z-index var(--t-slide);
}
.gs-from { display: flex; align-items: center; gap: 10px; min-height: 42px; font-size: 13px; }
.gs-from b { flex: 1; min-width: 0; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.gs-from time { display: none; font-size: 13px; color: var(--text-2); font-variant-numeric: tabular-nums; }
.gs-sheet .m { font-size: 12px; font-weight: 500; white-space: nowrap; }
.gs .ok { color: var(--ok); }
.gs .warn { color: var(--accent-2); }
.gs-dot { display: none; width: 12px; height: 12px; border-radius: 50%; flex: none; }
.gs-dot.warn { background: var(--accent-2); box-shadow: 0 0 0 4px var(--accent-2-bg); }
.gs-dot.ok { background: var(--ok); box-shadow: 0 0 0 4px var(--ok-bg); }
.gs-more { display: grid; grid-template-rows: 0fr; opacity: 0.4; transition: grid-template-rows var(--t-slide), opacity var(--t-fade); }
.gs-more-in { min-height: 0; overflow: hidden; display: flex; flex-direction: column; gap: 6px; }
.gs-subject { font-family: var(--font-display); font-size: 19px; font-weight: 650; letter-spacing: -0.02em; line-height: 1.2; }
.gs-sum { margin: 0; font-size: 13.5px; line-height: 1.5; color: var(--text-2); }
.gs-more-in .m { margin-top: 4px; font-size: 13px; }

.gs-sheet[data-pos="0"] {
  z-index: 4; margin: 72px 0 0; padding: 8px 20px 20px;
  background: var(--sheet-front); box-shadow: var(--sheet-shadow); transform: translateZ(40px);
}
.gs-sheet[data-pos="0"] .gs-more { grid-template-rows: 1fr; opacity: 1; }
.gs-sheet[data-pos="0"] .gs-from { font-size: 14px; }
.gs-sheet[data-pos="0"] .gs-dot, .gs-sheet[data-pos="0"] .gs-from time { display: block; }
.gs-sheet[data-pos="0"] .gs-peek { display: none; }
.gs-sheet[data-pos="1"] { z-index: 3; margin: 36px 24px 0; background: color-mix(in srgb, var(--sheet-front) 66%, transparent); transform: translateZ(-40px); }
.gs-sheet[data-pos="2"] { z-index: 2; margin: 0 48px; background: color-mix(in srgb, var(--sheet-front) 40%, transparent); color: var(--text-2); transform: translateZ(-80px); }
.gs-sheet[data-pos="3"] { z-index: 1; margin: 0 72px; background: color-mix(in srgb, var(--sheet-front) 30%, transparent); opacity: 0; transform: translateZ(-120px); }
.gs:active .gs-sheet[data-pos="0"] { scale: 0.985; }

/* the one number: solid brand blue, as the plate is */
.welcome .wt-count {
  grid-area: count;
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: end; column-gap: 16px;
  background: linear-gradient(180deg, #63a9ff 0%, var(--accent) 46%, #0b5bd3 100%);
  border-color: transparent; color: #fff;
}
.wc-label { grid-column: 1; font-size: 17px; font-weight: 600; }
.wc-note { grid-column: 1; font-size: 14px; color: rgba(255, 255, 255, 0.82); }
.wc-num {
  grid-column: 2; grid-row: 1 / span 2;
  font-family: var(--font-display); font-size: 88px; line-height: 0.85; font-weight: 650; letter-spacing: -0.05em;
  font-variant-numeric: tabular-nums;
}

/* ---- the bento ------------------------------------------------------------ */
.wb {
  display: grid; gap: 12px;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-template-areas: "note time privacy";
}
.wt-thread { grid-area: thread; }
.wt-note { grid-area: note; }
.wt-time { grid-area: time; }
.wt-privacy { grid-area: privacy; }
.wt-thread, .wt-privacy { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 32px; align-items: center; }
/* in a third of the row the privacy tile stacks its two halves */
.wb .wt-privacy { grid-template-columns: minmax(0, 1fr); gap: 24px; align-content: space-between; }
.wt-note, .wt-time { display: flex; flex-direction: column; justify-content: space-between; gap: 28px; }
.wb h2 { font-size: clamp(26px, 2.5vw, 34px); line-height: 1.08; letter-spacing: -0.03em; }
.wt-copy p { margin: 14px 0 0; font-size: 16px; line-height: 1.55; }

.mini-thread { overflow: hidden; border-radius: 18px; background: var(--sheet-front); border: 1px solid var(--sheet-rim); box-shadow: var(--sheet-shadow); }
.mt-open { padding: 16px 18px; }
.mt-open b, .mt-fold b { font-size: 14px; font-weight: 600; }
.mt-open small, .mt-fold small { float: right; font-size: 12px; color: var(--text-3); }
.mt-open p { margin: 8px 0 0; font-size: 14px; line-height: 1.5; color: var(--text-2); }
.mt-fold { display: flex; align-items: center; gap: 10px; padding: 12px 18px; border-top: 1px solid var(--hair-soft); font-size: 13px; }
.mt-fold span { flex: 1; min-width: 0; color: var(--text-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mt-fold small { float: none; }
.mt-related { display: flex; flex-direction: column; gap: 2px; padding: 12px 18px; border-top: 1px solid var(--hair-soft); background: var(--bg-2); }
.mt-related b { font-size: 12.5px; font-weight: 600; color: var(--text-2); }
.mt-related span { font-size: 13px; color: var(--text); }

/* the one visual that borrows its platform's material: an iOS notification */
.mini-note {
  display: flex; align-items: center; gap: 12px; padding: 14px 16px; border-radius: 22px;
  background: color-mix(in srgb, var(--sheet-front) 78%, transparent);
  border: 1px solid var(--sheet-rim); box-shadow: var(--sheet-lift);
}
.mini-note img { border-radius: 9px; flex: none; }
.mini-note div { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.mini-note b { font-size: 14px; }
.mini-note span { font-size: 13.5px; color: var(--text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mini-note small { align-self: flex-start; font-size: 12px; color: var(--text-3); }

/* the story, as a timeline whose last entry is now */
.timeline { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.timeline li { display: grid; grid-template-columns: 52px minmax(0, 1fr); gap: 12px; font-size: 14.5px; line-height: 1.45; color: var(--text-2); }
.timeline em { font-style: normal; font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; }
.timeline li.now { color: var(--text); font-weight: 500; }
.timeline li.now em { color: var(--accent-text); }

/* no frame at all: two lines of type and two bars are the whole argument */
.mini-store { display: flex; flex-direction: column; gap: 28px; }
.st { display: grid; grid-template-columns: minmax(0, 1fr); gap: 4px; }
.st-label { font-size: 14px; font-weight: 600; }
.st-items { font-size: 13px; color: var(--text-2); }
.st-bar { height: 10px; border-radius: 5px; margin-top: 6px; background: color-mix(in srgb, var(--text) 8%, transparent); }
.st-bar.full { background: color-mix(in srgb, var(--accent) 30%, transparent); }
.st-bar.thin { width: 12%; background: var(--accent); }

/* ---- setup: the front sheet ----------------------------------------------- */
.ws {
  scroll-margin-top: calc(88px + var(--safe-top));
  margin-top: 60px; padding: 0 12px;
  display: grid; grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr); column-gap: 72px; align-items: start;
}
.ws-head { position: static; padding-top: 40px; }
.ws-head h2 { font-size: clamp(32px, 3.6vw, 48px); line-height: 1.05; letter-spacing: -0.035em; }
.ws-head p { margin: 14px 0 0; max-width: 34em; font-size: 17px; line-height: 1.55; color: var(--text-2); }
.ws-steps { margin: 24px 0 0; padding: 0; list-style: none; counter-reset: ws; display: flex; flex-direction: column; gap: 14px; max-width: 34em; }
.ws-steps li { counter-increment: ws; display: grid; grid-template-columns: 28px minmax(0, 1fr); gap: 12px; font-size: 15px; line-height: 1.5; color: var(--text-2); }
.ws-steps li::before {
  content: counter(ws); width: 28px; height: 28px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center;
  background: var(--sheet-front); border: 1px solid var(--sheet-rim); box-shadow: var(--sheet-lift);
  font-size: 13px; font-weight: 600; color: var(--accent-text); font-variant-numeric: tabular-nums;
}
.ws-steps b { color: var(--text); font-weight: 600; }
.ws-body { min-width: 0; max-width: 640px; }

.w-progress { list-style: none; display: flex; gap: 6px; margin: 0 0 44px; padding: 0; }
.w-progress li {
  flex: 1; min-width: 0; padding-top: 10px; border-top: 3px solid color-mix(in srgb, var(--text) 10%, transparent);
  font-size: 13px; color: var(--text-2);
}
.w-progress li.done { border-top-color: color-mix(in srgb, var(--accent) 45%, transparent); color: var(--text-2); }
.w-progress li.current { border-top-color: var(--accent); color: var(--text); font-weight: 600; }
.w-step-label { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: block; }

/* Two narrower sheets stand behind the card, as they do behind the front
   sheet in the mark. They sit on a wrapper: on the card itself they would
   paint over its own background. */
.w-stack { position: relative; }
.w-stack::before, .w-stack::after {
  content: ""; position: absolute; height: 60px; border-radius: 28px;
  border: 1px solid var(--sheet-rim);
}
.w-stack::before { left: 56px; right: 56px; top: -30px; background: var(--sheet-back); }
.w-stack::after { left: 26px; right: 26px; top: -16px; background: var(--sheet-mid); }
.w-card {
  position: relative; z-index: 1;
  padding: 34px; border-radius: 28px;
  background: var(--sheet-front); border: 1px solid var(--sheet-rim); box-shadow: var(--sheet-shadow);
  display: flex; flex-direction: column; gap: 20px;
}
.w-step-head h2 { font-size: 24px; letter-spacing: -0.02em; }
.w-step-head p { margin: 6px 0 0; font-size: 15px; color: var(--text-2); line-height: 1.5; }
.w-form, .w-options { display: flex; flex-direction: column; gap: 16px; }
.w-form .text-input, .w-options .text-input { height: 46px; font-size: 15px; border-radius: 12px; background: var(--bg-2); }
.w-form .text-input:focus, .w-options .text-input:focus { background: var(--bg); }
.w-card .form-label { font-size: 13px; font-weight: 500; color: var(--text); }
.w-card .form-hint { font-size: 12.5px; line-height: 1.45; color: var(--text-2); }
.w-buttons { display: flex; flex-wrap: wrap; align-items: center; gap: 16px; margin-top: 4px; }
.w-card .btn { height: 46px; padding: 0 24px; border-radius: 999px; font-size: 15px; text-decoration: none; box-shadow: none; }
.w-card .btn.primary { background: var(--accent); color: #fff; }
.w-card .btn.primary:hover { background: color-mix(in srgb, var(--accent) 88%, black); filter: none; }
.w-card .link-btn { text-decoration: none; color: var(--accent-text); font-size: 15px; }
.w-note { margin: 0; font-size: 15px; line-height: 1.55; color: var(--text-2); }
.w-invite { margin: 0; display: inline-flex; align-items: center; gap: 6px; font-size: 14px; color: var(--ok); }
/* SPEC 56: the field only a bot fills in, and the code box */
.w-trap { position: absolute !important; left: -10000px; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.welcome .w-code { font-family: var(--mono); font-size: 26px; letter-spacing: 0.35em; text-align: center; height: 56px; max-width: 260px; font-variant-numeric: tabular-nums; }
.w-requirement {
  display: flex; gap: 14px; align-items: flex-start; padding: 16px;
  border-radius: 16px; background: var(--bg-2);
}
.w-requirement strong { font-size: 14px; }
.w-requirement p { margin: 4px 0 6px; font-size: 14px; line-height: 1.5; color: var(--text-2); }
.w-requirement a { font-size: 14px; color: var(--accent-text); text-decoration: none; }
.w-advanced summary { cursor: pointer; font-size: 14px; font-weight: 500; margin-bottom: 8px; }
.w-advanced { display: flex; flex-direction: column; gap: 10px; }
.w-two { display: grid; grid-template-columns: minmax(0, 1fr) 96px; gap: 10px; margin-top: 10px; }
.w-card .plist { grid-template-columns: minmax(0, 1fr); gap: 2px; }
.w-card .prow { min-height: 48px; }
.w-card .prow .pname { font-size: 15px; }
.w-option { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
.w-option strong { font-size: 14px; }
.w-option .form-hint { margin: 0; }
.welcome .switch { display: inline-flex; align-items: center; gap: 10px; cursor: pointer; font-size: 15px; }
.welcome .switch input { appearance: none; width: 44px; height: 26px; border-radius: 999px; background: var(--bg-3); position: relative; transition: background var(--t); cursor: pointer; flex: none; }
.welcome .switch input::after { content: ""; position: absolute; top: 2px; left: 2px; width: 22px; height: 22px; border-radius: 50%; background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,.3); transition: transform var(--t); }
.welcome .switch input:checked { background: var(--ok); }
.welcome .switch input:checked::after { transform: translateX(18px); }
/* SPEC 120: the last step is what is left to do, each with its own button */
.w-check { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.w-check li {
  display: grid; grid-template-columns: 26px minmax(0, 1fr) auto; align-items: center; column-gap: 14px;
  padding: 14px 0; border-top: 1px solid var(--hair-soft);
}
.w-check li:first-child { border-top: 0; padding-top: 4px; }
.w-check-mark { width: 24px; height: 24px; border-radius: 50%; box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--text) 28%, transparent); position: relative; align-self: start; margin-top: 1px; }
.w-check li.done .w-check-mark { background: var(--ok); box-shadow: none; }
.w-check li.done .w-check-mark::after {
  content: ""; position: absolute; left: 8px; top: 4px; width: 6px; height: 11px;
  border: solid #fff; border-width: 0 2.2px 2.2px 0; rotate: 45deg;
}
.w-check-copy strong { display: block; font-size: 15px; font-weight: 600; color: var(--text); }
.w-check li.done .w-check-copy strong { color: var(--text-2); }
.w-check-copy p { margin: 3px 0 0; font-size: 14px; line-height: 1.45; color: var(--text-2); }
.w-card .w-check .btn.sm { height: 36px; padding: 0 16px; font-size: 14px; background: var(--bg-2); color: var(--text); border: 1px solid var(--sheet-rim); }
.w-card .w-check .btn.sm.primary { background: var(--accent); color: #fff; border-color: transparent; }
.w-check .link-btn { font-size: 14px; font-weight: 600; white-space: nowrap; }
@media (max-width: 480px) {
  .w-check li { grid-template-columns: 26px minmax(0, 1fr); row-gap: 10px; }
  .w-check li > .btn, .w-check li > .link-btn { grid-column: 2; justify-self: start; }
}
.w-foot { display: flex; align-items: flex-start; gap: 16px; margin-top: 64px; padding: 28px 12px 0; border-top: 1px solid color-mix(in srgb, var(--text) 8%, transparent); }
.w-foot img { border-radius: 8px; flex: none; }
.w-foot p { margin: 0; font-size: 13px; line-height: 1.6; color: var(--text-2); max-width: 680px; }

@media (prefers-reduced-transparency: reduce) {
  .wn { -webkit-backdrop-filter: none; backdrop-filter: none; }
}

/* ---- smaller screens ---------------------------------------------------- */
@media (max-width: 999px) {
  .wh { grid-template-columns: minmax(0, 1fr); grid-template-areas: "hero" "stack" "count"; }
  .wt-hero { min-height: 0; padding: 36px 32px; }
  .wb { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); grid-template-areas: "note time" "privacy privacy"; }
  .wb .wt-privacy { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .welcome .wth { grid-template-columns: minmax(0, 1fr); gap: 32px; }
  .ws { grid-template-columns: minmax(0, 1fr); row-gap: 48px; }
  .ws-head { position: static; padding-top: 0; }
}
@media (max-width: 699px) {
  .wn { width: calc(100% - 2 * (12px + var(--safe-left))); }
  .wn-links a:not(.wn-cta) { padding: 0 10px; }
  .welcome { padding-left: calc(12px + var(--safe-left)); padding-right: calc(12px + var(--safe-right)); gap: 10px; }
  .welcome .tile { padding: 24px 22px; border-radius: 24px; }
  .wt-hero { padding: 32px 22px 28px; }
  .wb { grid-template-columns: minmax(0, 1fr); grid-template-areas: "note" "time" "privacy"; }
  .wb .wt-privacy { grid-template-columns: minmax(0, 1fr); }
  .wt-thread, .wt-privacy { grid-template-columns: minmax(0, 1fr); gap: 24px; }
  .wc-num { font-size: 72px; }
  .gs-sheet[data-pos="1"] { margin: 36px 16px 0; }
  .gs-sheet[data-pos="2"] { margin: 0 32px; }
  .gs-sheet[data-pos="3"] { margin: 0 48px; }
  .ws { padding: 0; margin-top: 44px; }
  .w-card { padding: 24px 20px; border-radius: 24px; }
  .w-progress li { font-size: 12px; }
  .w-form .text-input, .w-options .text-input { font-size: 16px; }   /* no zoom on focus in iOS Safari */
  .w-foot { padding: 24px 4px 0; }
}

/* A meeting (SPEC 54): an invitation or its answer, drawn as a calendar would. */
.meeting-card {
  display: grid; grid-template-columns: 40px minmax(0, 1fr); gap: 14px;
  margin: 14px 32px 4px; padding: 18px 20px; border-radius: 18px;
  background: var(--bg-2); border: 1px solid var(--hair-soft);
}
.mc-mark {
  width: 40px; height: 40px; border-radius: 12px; display: flex; align-items: center; justify-content: center;
  background: var(--accent-bg); color: var(--accent-text);
}
.meeting-card.state-ok .mc-mark { background: var(--ok-bg); color: var(--ok); }
.meeting-card.state-danger .mc-mark { background: var(--danger-bg); color: var(--danger); }
.meeting-card.state-warn .mc-mark { background: var(--accent-2-bg); color: var(--accent-2); }
.mc-main { min-width: 0; display: flex; flex-direction: column; gap: 6px; }
/* SPEC 54.1: the place on a map, to the right of the facts, with a way there */
/* The facts are one invisible column the height of the card's row, with
   Navigate centred at its foot; the map is centred on the row, so the space
   above it and below it inside the card is the same. */
.meeting-card.has-map { grid-template-columns: 40px minmax(0, 1fr) minmax(220px, 300px); align-items: stretch; }
.meeting-card.has-map .mc-mark { align-self: start; }
.mc-map { display: flex; flex-direction: column; justify-content: center; align-self: center; min-width: 0; }
.mc-map-frame {
  display: block; width: 100%; aspect-ratio: 4 / 3; border: 0; border-radius: 14px;
  background: var(--bg-3); box-shadow: 0 0 0 1px var(--hair-soft);
}
.mc-map-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px; margin-top: auto; padding-top: 14px; }
.mc-map-actions .btn { gap: 6px; text-decoration: none; }
@media (max-width: 1279px) {
  .meeting-card.has-map { grid-template-columns: 40px minmax(0, 1fr); }
  .meeting-card.has-map .mc-map { grid-column: 1 / -1; }
}
.mc-status { font-size: 12.5px; font-weight: 600; color: var(--accent-text); }
.meeting-card.state-ok .mc-status { color: var(--ok); }
.meeting-card.state-danger .mc-status { color: var(--danger); }
.meeting-card.state-warn .mc-status { color: var(--accent-2); }
.meeting-card.state-info .mc-status { color: var(--text-2); }
.mc-title { font-family: var(--font-display); font-size: 19px; font-weight: 650; letter-spacing: -0.015em; line-height: 1.25; overflow-wrap: anywhere; }
.mc-facts { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 4px 14px; margin: 4px 0 0; font-size: 14px; }
.mc-facts dt { color: var(--text-3); }
.mc-facts dd { margin: 0; color: var(--text); overflow-wrap: anywhere; font-variant-numeric: tabular-nums; }
.mc-line { margin: 4px 0 0; font-size: 13.5px; color: var(--text-2); }
.mc-desc { margin: 6px 0 0; font-size: 13.5px; line-height: 1.5; color: var(--text-2); white-space: pre-wrap; overflow-wrap: anywhere; max-height: 12em; overflow: auto; }
.meeting-card a, .msg-enrich a { color: var(--accent-text); }
@media (max-width: 699px) { .meeting-card { margin: 12px 16px 4px; padding: 16px; } }

/* ==========================================================================
   Calendar (SPEC 58)
   ========================================================================== */
.app.calendar-mode .list-pane, .app.calendar-mode .thread-pane { display: none; }
.calendar-pane { grid-column: 2 / -1; min-width: 0; min-height: 0; display: flex; flex-direction: column; overflow: hidden; background: var(--bg); }
@media (max-width: 1099px) { .calendar-pane { grid-column: 1 / -1; } }
@media (min-width: 700px) {
  .calendar-pane { background: var(--sheet-front); border: 1px solid var(--sheet-rim); border-radius: var(--radius-sheet); box-shadow: var(--sheet-shadow); }
}
.cal-head { display: flex; align-items: center; gap: 10px; padding: 14px 18px 10px; flex: none; }
.cal-head h2 { margin: 0; font-family: var(--font-display); font-size: 22px; font-weight: 650; letter-spacing: -0.02em; min-width: 190px; }
.cal-nav { display: flex; align-items: center; gap: 2px; }
.cal-head .spacer { flex: 1; }
.cal-head .btn.primary { gap: 6px; }
.cal-body { flex: 1; min-height: 0; display: grid; grid-template-columns: minmax(0, 1fr) minmax(300px, 380px); gap: 14px; padding: 0 18px 18px; overflow: hidden; }
.cal-month { min-height: 0; display: flex; flex-direction: column; gap: 10px; }
.cal-grid { flex: 1; min-height: 0; display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); grid-template-rows: auto repeat(6, minmax(0, 1fr)); gap: 4px; }
.cal-dow { font-size: 11.5px; font-weight: 600; color: var(--text-3); padding: 0 8px 4px; }
.cal-day {
  display: flex; flex-direction: column; align-items: stretch; gap: 3px; min-width: 0; min-height: 64px;
  padding: 6px 6px 4px; border-radius: 12px; background: var(--bg-2); border: 1px solid transparent;
  text-align: left; color: var(--text); overflow: hidden; transition: background var(--t-fast), border-color var(--t-fast);
}
.cal-day:hover { border-color: var(--hair); }
.cal-day.out { background: transparent; color: var(--text-3); }
.cal-day.weekend:not(.out) { background: color-mix(in srgb, var(--bg-2) 60%, transparent); }
.cal-day.selected { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-bg); }
.cal-num { font-size: 12.5px; font-weight: 600; font-variant-numeric: tabular-nums; width: 24px; height: 24px; display: inline-flex; align-items: center; justify-content: center; border-radius: 50%; }
.cal-day.today .cal-num { background: var(--accent); color: #fff; }
.cal-chips { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.cal-chip { font-size: 11px; line-height: 16px; padding: 0 5px; border-radius: 5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; background: var(--accent-bg); color: var(--accent-text); }
/* Dates found in mail are background: grey, so meetings and your own events are what the eye finds. */
.cal-chip.kind-date { background: color-mix(in srgb, var(--text) 6%, transparent); color: var(--text-3); }
.cal-chip.kind-event { background: var(--ok-bg); color: var(--ok); }
.cal-more { font-size: 10.5px; color: var(--text-3); padding: 0 5px; }
.cal-legend { display: flex; flex-wrap: wrap; gap: 6px 16px; font-size: 12px; color: var(--text-3); }
.cal-legend span::before { content: ""; display: inline-block; width: 8px; height: 8px; border-radius: 3px; margin-right: 6px; background: var(--accent); vertical-align: 0; }
.cal-legend .kind-date::before { background: var(--text-3); }
.cal-legend .kind-event::before { background: var(--ok); }
.cal-agenda, .cal-editor { min-height: 0; overflow-y: auto; overscroll-behavior: contain; display: flex; flex-direction: column; gap: 10px; padding: 2px 2px 8px; }
.cal-agenda-day, .cal-agenda-soon, .cal-editor h3 { margin: 4px 0 0; font-family: var(--font-display); font-size: 17px; font-weight: 650; letter-spacing: -0.01em; }
.cal-agenda-soon { margin-top: 12px; font-size: 14px; color: var(--text-2); }
.cal-empty { margin: 0; font-size: 13.5px; color: var(--text-3); }
.cal-event { display: flex; flex-direction: column; gap: 6px; padding: 14px 16px; border-radius: 16px; background: var(--bg-2); border-left: 3px solid var(--accent); }
.cal-event.kind-date { border-left-color: var(--hair); background: transparent; box-shadow: inset 0 0 0 1px var(--hair-soft); }
.cal-event.kind-date .cal-event-title { font-size: 14px; font-weight: 500; color: var(--text-2); }
.cal-event.kind-event { border-left-color: var(--ok); }
.cal-event.cancelled .cal-event-title { text-decoration: line-through; color: var(--text-3); }
.cal-event-top { display: flex; justify-content: space-between; gap: 8px; font-size: 12.5px; color: var(--text-2); font-variant-numeric: tabular-nums; }
.cal-event-kind { color: var(--text-3); }
.cal-event.cancelled .cal-event-kind { color: var(--danger); }
.cal-event-title { font-size: 15.5px; font-weight: 600; overflow-wrap: anywhere; }
.cal-event-where, .cal-event-notes { margin: 0; font-size: 13px; color: var(--text-2); overflow-wrap: anywhere; white-space: pre-wrap; }
.cal-event a { color: var(--accent-text); }
.cal-people { list-style: none; margin: 2px 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 4px 6px; }
.cal-people li { display: inline-flex; align-items: center; gap: 5px; height: 22px; padding: 0 8px; border-radius: 999px; background: var(--bg); font-size: 12px; color: var(--text-2); }
.cal-person-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--text-3); }
.cal-people .ps-accepted .cal-person-dot { background: var(--ok); }
.cal-people .ps-declined .cal-person-dot { background: var(--danger); }
.cal-people .ps-tentative .cal-person-dot { background: var(--accent-2); }
.cal-event-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: 4px; }
.cal-event-actions .btn, .cal-event-actions .mc-map-actions { margin: 0; padding-top: 0; gap: 6px; }
.cal-soon { display: grid; grid-template-columns: 78px minmax(0, 1fr) auto; gap: 10px; align-items: center; min-height: 36px; padding: 6px 10px; border-radius: 10px; background: none; border: 0; text-align: left; color: var(--text); font-size: 13px; }
.cal-soon:hover { background: var(--hover); }
.cal-soon-date { color: var(--text-2); font-variant-numeric: tabular-nums; }
.cal-soon-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; }
.cal-soon.kind-date .cal-soon-title, .cal-soon.kind-date .cal-soon-date { color: var(--text-3); font-weight: 400; }
.cal-soon-time { color: var(--text-3); font-size: 12px; font-variant-numeric: tabular-nums; }
.cal-soon::before { content: none; }
.cal-editor-when { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: end; gap: 12px; }
.cal-editor-when .switch { height: 38px; display: inline-flex; align-items: center; gap: 8px; }
.cal-editor-times { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.cal-editor .text-input { height: 38px; }
.cal-editor textarea.text-input { height: auto; }
@media (max-width: 1099px) {
  /* one column that scrolls: the month keeps its own height instead of being squeezed to fit */
  .cal-body { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto auto; align-content: start; overflow-y: auto; }
  .cal-month { min-height: auto; }
  .cal-grid { flex: none; grid-template-rows: auto repeat(6, minmax(70px, auto)); }
  .cal-agenda, .cal-editor { overflow: visible; }
}
@media (max-width: 699px) {
  .cal-head { padding: 8px 16px; flex-wrap: wrap; }
  .cal-head h2 { font-size: 26px; min-width: 0; flex-basis: 100%; }
  .cal-body { padding: 0 12px calc(90px + var(--safe-bottom)); }
  .cal-day { min-height: 50px; padding: 4px 3px; border-radius: 10px; }
  .cal-chip { font-size: 0; height: 5px; padding: 0; border-radius: 3px; }
  .cal-grid { grid-template-rows: auto repeat(6, minmax(50px, auto)); gap: 3px; }
  .cal-dow { padding: 0 0 4px; text-align: center; }
  .cal-num { width: 26px; height: 26px; }
}

/* Invitations and the owner's panel (SPEC 59) */
.invite-hero { display: flex; flex-direction: column; gap: 6px; padding: 14px 16px; border-radius: 14px; background: var(--accent-bg); }
.invite-link { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; }
.invite-link .text-input { height: 38px; font-family: var(--mono); font-size: 12.5px; background: var(--bg); }
.invite-link .btn { height: 38px; gap: 6px; }
.invite-list { display: flex; flex-direction: column; gap: 2px; margin-bottom: 6px; }
.invite-row { display: grid; grid-template-columns: minmax(0, 1fr) auto auto auto; align-items: center; gap: 8px; padding: 8px 10px; border-radius: 10px; }
.invite-row:hover { background: var(--hover); }
.invite-row.off { opacity: 0.55; }
.invite-row-main { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.invite-row-main b { font-size: 13.5px; font-weight: 600; }
.invite-row-main code, .admin-table small { font-family: var(--mono); font-size: 11.5px; color: var(--text-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.invite-uses { font-size: 12px; color: var(--text-2); font-variant-numeric: tabular-nums; white-space: nowrap; }
.invite-new { padding: 12px 14px; border: 1px solid var(--hair); border-radius: var(--radius-lg); }
.invite-ending { display: flex; align-items: center; border: 1px solid var(--hair); border-radius: 10px; background: var(--bg); overflow: hidden; }
.invite-ending span { padding: 0 2px 0 12px; font-size: 12.5px; color: var(--text-3); white-space: nowrap; font-family: var(--mono); }
.invite-ending .text-input { border: 0; background: transparent; padding-left: 0; font-family: var(--mono); font-size: 12.5px; min-width: 0; }
.invite-joined { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.invite-joined li { display: flex; justify-content: space-between; gap: 12px; font-size: 13.5px; }
.invite-joined span { color: var(--text-3); font-size: 12.5px; }
.admin-head { display: flex; align-items: center; justify-content: space-between; }
.admin-head .btn { gap: 6px; }
.admin-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 8px; }
.admin-stat { display: flex; flex-direction: column; gap: 2px; padding: 12px 14px; border-radius: 14px; background: var(--bg-2); font-size: 12px; color: var(--text-2); }
.admin-stat-num { font-family: var(--font-display); font-size: 26px; font-weight: 650; color: var(--text); font-variant-numeric: tabular-nums; }
.admin-tree { list-style: none; margin: 0; padding: 0 0 0 16px; border-left: 1px solid var(--hair); display: flex; flex-direction: column; gap: 6px; }
.settings-section > .admin-tree { padding-left: 0; border-left: 0; }
.admin-tree .admin-tree { margin-top: 6px; }
.admin-node { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px; font-size: 13.5px; }
.admin-node-meta { font-size: 12px; color: var(--text-3); }
.admin-table-wrap { overflow-x: auto; }
.admin-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.admin-table th { text-align: left; font-size: 11.5px; font-weight: 600; color: var(--text-3); padding: 6px 8px; border-bottom: 1px solid var(--hair); white-space: nowrap; }
.admin-table td { padding: 8px; border-bottom: 1px solid var(--hair-soft); vertical-align: top; }
.admin-table td b { display: block; font-weight: 600; }
.admin-table td small { display: block; }
.admin-table td.num { font-variant-numeric: tabular-nums; }
.admin-table tr.off td { opacity: 0.55; }

/* Mail kept with the provider (SPEC 52): the moment it is read from the mailbox. */
.msg-body.provider-state { padding-left: 32px; padding-right: 32px; }
.msg-body.provider-loading { display: flex; flex-direction: column; gap: 10px; padding-top: 22px; padding-bottom: 22px; }
@media (max-width: 699px) { .msg-body.provider-state { padding-left: 20px; padding-right: 20px; } }
.provider-error { margin: 0 0 8px; font-size: 13.5px; color: var(--text-2); }
.provider-excerpt { margin: 0 0 12px; font-size: 14px; color: var(--text-3); }
.mc-calendar { display: inline-flex; align-items: center; gap: 6px; align-self: flex-start; margin-top: 2px; font-size: 13px; }

/* ==========================================================================
   The welcome page, in motion (SPEC 62). Everything here is decoration over a
   page that reads the same without it: with reduced motion none of it runs,
   and before app.js has run nothing is hidden that the first screen needs.
   ========================================================================== */
@keyframes wi-curtain { to { clip-path: inset(0 0 100% 0); visibility: hidden; } }
@keyframes wi-fill { from { scale: 0 1; } to { scale: 1 1; } }
@keyframes w-rise { from { opacity: 0; translate: 0 28px; } to { opacity: 1; translate: 0 0; } }
@keyframes w-word { from { translate: 0 112%; rotate: 5deg; } to { translate: 0 0; rotate: 0deg; } }
@keyframes gs-float { 0%, 100% { translate: 0 0; } 50% { translate: 0 -10px; } }
@keyframes wm-run { to { transform: translateX(-50%); } }
@keyframes note-land {
  0%, 6% { translate: 0 -150%; opacity: 0; }
  16% { translate: 0 8%; opacity: 1; }
  22%, 76% { translate: 0 0; opacity: 1; }
  88%, 100% { translate: 0 -150%; opacity: 0; }
}

/* the curtain: the mark, a line that fills, and the page wiped up from under it */
.w-intro {
  position: fixed; inset: 0; z-index: 100; pointer-events: none;
  display: grid; place-content: center; justify-items: center; gap: 22px;
  background: var(--field);
  animation: wi-curtain var(--t-stage) var(--d-intro) both;
}
.wi-mark {
  display: flex; align-items: center; gap: 14px;
  font-family: var(--font-display); font-weight: 650; font-size: 34px; letter-spacing: -0.04em; color: var(--text);
  animation: w-rise var(--t-stage) both;
}
.wi-mark img { border-radius: 16px; }
.wi-bar { width: 180px; height: 3px; border-radius: 2px; overflow: hidden; background: color-mix(in srgb, var(--text) 10%, transparent); }
.wi-bar i { display: block; height: 100%; background: var(--accent); transform-origin: left; animation: wi-fill var(--d-intro) linear both; }
.intro-seen .w-intro { display: none; }
.intro-seen { --d-intro: 0s; }

/* the headline: each word rises out of its own mask, then the rest of the hero */
.wr { display: inline-block; overflow: hidden; vertical-align: top; padding: 0.04em 0.02em 0.12em; margin: -0.04em -0.02em -0.12em; }
.wr > span { display: inline-block; animation: w-word var(--t-stage) calc(var(--d-intro) + var(--i, 0) * var(--d)) both; }
.wr-accent > span { color: var(--accent-text); }
.w-rise { animation: w-rise var(--t-stage) calc(var(--d-intro) + var(--i, 0) * var(--d)) both; }

/* a light that follows the pointer across the hero */
.wt-hero {
  background:
    radial-gradient(520px circle at var(--mx, 78%) var(--my, 18%), color-mix(in srgb, var(--accent) 16%, transparent), transparent 62%),
    var(--sheet-mid);
}

/* the stack is a real stack: sheets at depth, tilting towards the pointer, floating when left alone */
.wt-stack { perspective: 1100px; }
.gs {
  transform-style: preserve-3d;
  transform: rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
  animation: gs-float var(--t-loop) infinite;
}
/* backwards, not both: once in, a card's opacity is its place in the deck's again */
.gs-sheet { animation: w-rise var(--t-stage) calc(var(--d-intro) + var(--i, 0) * var(--d)) backwards; }

/* the band: huge type running sideways, a solid row and an outlined row the other way */
.wm {
  margin: 36px calc(50% - 50vw); padding: 8px 0; overflow: hidden;
  display: flex; flex-direction: column; gap: 2px;
}
.wm-row { display: flex; transform: skewX(var(--wm-skew, 0deg)); }
.wm-track {
  display: flex; flex: none; align-items: center; gap: 0.42em; padding-right: 0.42em;
  font-family: var(--font-display); font-weight: 650; font-size: clamp(54px, 9vw, 132px);
  line-height: 1.02; letter-spacing: -0.05em; white-space: nowrap; color: var(--text);
  animation: wm-run var(--d-marquee) linear infinite;
}
.wm-alt .wm-track {
  color: transparent; -webkit-text-stroke: 1.5px color-mix(in srgb, var(--text) 42%, transparent);
  animation-direction: reverse;
}
.wm-dot { flex: none; width: 0.3em; height: 0.3em; border-radius: 50%; background: var(--accent); box-shadow: 0 0 0 0.1em var(--accent-bg); }
.wm-alt .wm-dot { background: var(--accent-2); box-shadow: 0 0 0 0.1em var(--accent-2-bg); }

/* sections arrive as they scroll in (only once app.js has said motion is on) */
.motion .reveal { transition: opacity var(--t-stage), translate var(--t-stage), scale var(--t-stage); transition-delay: calc(var(--i, 0) * var(--d)); }
.motion .reveal:not(.in) { opacity: 0; translate: 0 56px; scale: 0.97; }

/* the notification keeps landing, the bars fill, the timeline lights up year by year */
.mini-notes { display: flex; flex-direction: column; gap: 8px; }
.mini-note-2 { opacity: 0.72; scale: 0.96; }
.motion .wt-note.in .mini-note { animation: note-land var(--t-loop) infinite both; }
/* the second lands a beat after the first, like a phone's stack */
.motion .wt-note.in .mini-note-2 { animation: note-land var(--t-loop) var(--d-stage) infinite both; }
.st-bar { transform-origin: left; transition: scale var(--t-stage); }
.motion .wt-privacy:not(.in) .st-bar { scale: 0 1; }
.wt-time .timeline li { transition: color var(--t-stage), translate var(--t-stage), opacity var(--t-stage); }
.motion .wt-time .timeline li:not(.lit) { opacity: 0.35; translate: -10px 0; }

/* buttons that lean towards the pointer */
.w-cta, .wn-links .wn-cta { transition: background var(--t-fast), transform var(--t-fast), translate var(--t); }

/* the ring: a mouse only, never a finger; it swells over anything you can press */
.w-cursor { display: none; }
.has-cursor .w-cursor {
  display: block; position: fixed; left: 0; top: 0; z-index: 95; pointer-events: none;
  translate: var(--cx, -100px) var(--cy, -100px);
}
.w-cursor i {
  display: block; width: 34px; height: 34px; margin: -17px 0 0 -17px; border-radius: 50%;
  border: 1.5px solid color-mix(in srgb, var(--accent) 70%, transparent);
  transition: scale var(--t), background var(--t), border-color var(--t);
}
.w-cursor.press i { scale: 1.9; background: var(--accent-bg); border-color: transparent; }
.w-cursor.over i { scale: 1.35; }

@media (prefers-reduced-motion: reduce) {
  .w-intro, .has-cursor .w-cursor { display: none; }
  .wr > span, .w-rise, .gs, .gs-sheet, .wi-mark, .wi-bar i { animation: none; }
  .wm-track { animation: none; }
}

/* ==========================================================================
   Try it (SPEC 67): one message, played through -- it arrives with the chime,
   the AI reads it, a reply is offered in grey, taken, and sent with a ping.
   ========================================================================== */
@keyframes wd-drop { from { opacity: 0; translate: 0 -110%; scale: 0.96; } to { opacity: 1; translate: 0 0; scale: 1; } }
@keyframes wd-lift { to { opacity: 0; translate: 0 -40px; scale: 0.94; } }
@keyframes wd-press { 50% { scale: 0.92; } }

/* SPEC 69: is the username free, and every account's number */
.name-check { display: block; min-height: 18px; margin-top: 4px; font-size: 12.5px; color: var(--text-3); }
.name-check.ok { color: var(--ok); }
.name-check.bad { color: var(--danger); }
.admin-no { font-variant-numeric: tabular-nums; font-size: 12px; color: var(--text-3); min-width: 2.2em; }
/* SPEC 68: what a password needs, ticking itself off while it is typed */
.pw-rules { list-style: none; margin: 6px 0 0; padding: 0; display: flex; flex-direction: column; gap: 3px; }
.pw-rules li { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--text-3); transition: color var(--t-fast); }
.pw-tick { width: 14px; height: 14px; border-radius: 50%; flex: none; border: 1.5px solid var(--hair); position: relative; transition: background var(--t-fast), border-color var(--t-fast); }
.pw-rules li.ok { color: var(--text-2); }
.pw-rules li.ok .pw-tick { background: var(--ok); border-color: var(--ok); }
.pw-rules li.ok .pw-tick::after {
  content: ""; position: absolute; left: 3.5px; top: 1px; width: 3.5px; height: 7px;
  border: solid #fff; border-width: 0 1.5px 1.5px 0; rotate: 45deg;
}
.ws-steps li { cursor: pointer; border-radius: 14px; margin: -6px -8px; padding: 6px 8px; transition: background var(--t-fast); }
.ws-steps li:hover, .ws-steps li:focus-visible { background: color-mix(in srgb, var(--sheet-front) 60%, transparent); outline: none; }
.w-card.flash { box-shadow: 0 0 0 3px var(--accent-bg), var(--sheet-shadow); transition: box-shadow var(--t-slide); }

.wd { margin-top: 30px; max-width: 34em; display: flex; flex-direction: column; gap: 12px; }
.wd-intro { margin: 0; font-size: 14px; color: var(--text-2); }
.wd-buttons { display: flex; flex-wrap: wrap; gap: 8px; }
.wd-btn {
  display: inline-flex; align-items: center; gap: 8px; height: 40px; padding: 0 16px; border-radius: 999px;
  background: var(--sheet-front); border: 1px solid var(--sheet-rim); box-shadow: var(--sheet-lift);
  color: var(--text); font-size: 14px; font-weight: 500;
  transition: background var(--t-fast), color var(--t-fast), translate var(--t), opacity var(--t-fast);
}
.wd-btn .icon { width: 16px; height: 16px; color: var(--accent-text); }
.wd-btn:hover { background: var(--accent-bg); color: var(--accent-text); }
.wd-btn.next { background: var(--accent); color: #fff; border-color: transparent; }
.wd-btn.next .icon { color: #fff; }
.wd-btn:disabled { opacity: 0.5; cursor: default; }
.wd-btn.pressed { animation: wd-press var(--t) both; }

.wd-stage {
  position: relative; min-height: 132px; padding: 14px; border-radius: 22px; overflow: hidden;
  background: var(--sheet-back); border: 1px solid var(--sheet-rim);
  display: flex; flex-direction: column; gap: 10px;
}
.wd-empty { margin: auto; font-size: 13.5px; color: var(--text-3); text-align: center; }
.wd-note {
  display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: 18px;
  background: color-mix(in srgb, var(--sheet-front) 90%, transparent); border: 1px solid var(--sheet-rim); box-shadow: var(--sheet-lift);
  animation: wd-drop var(--t-stage) both;
}
.wd-note img { border-radius: 8px; flex: none; }
.wd-note div, .wd-row-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.wd-note b, .wd-row b { font-size: 14px; font-weight: 600; }
.wd-note span, .wd-row-main span { font-size: 13px; color: var(--text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wd-note small { align-self: flex-start; font-size: 12px; color: var(--text-3); }
.wd-note.gone { animation: wd-lift var(--t-slide) both; }
.wd-row {
  display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: 16px;
  background: var(--sheet-front); border: 1px solid var(--sheet-rim);
  animation: wd-drop var(--t-slide) both;
}
.wd-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--accent); flex: none; transition: opacity var(--t-slide); }
.wd-row.read .wd-dot { opacity: 0; }
.wd-pill { flex: none; height: 22px; padding: 0 9px; border-radius: 999px; font-size: 11.5px; font-weight: 600; display: inline-flex; align-items: center; transition: background var(--t-slide), color var(--t-slide); }
.wd-pill.warn { color: var(--accent-2); background: var(--accent-2-bg); }
.wd-pill.ok { color: var(--ok); background: var(--ok-bg); }

.wd-card {
  display: flex; flex-direction: column; gap: 6px; padding: 12px 14px; border-radius: 16px;
  background: color-mix(in srgb, var(--accent) 6%, var(--sheet-front)); border: 1px solid color-mix(in srgb, var(--accent) 16%, var(--sheet-rim));
  animation: wd-drop var(--t-slide) both;
}
.wd-label { display: inline-flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--accent-text); }
.wd-label .icon { width: 13px; height: 13px; }
.wd-topic { font-family: var(--font-display); font-size: 15px; font-weight: 650; color: var(--text); min-height: 1.3em; }
.wd-text { margin: 0; font-size: 13.5px; line-height: 1.5; color: var(--text-2); min-height: 1.5em; }
.wd-todo { font-size: 13px; color: var(--text); }
.wd-todo b { color: var(--text-3); font-weight: 600; margin-right: 6px; }

.wd-compose {
  display: flex; flex-direction: column; gap: 8px; padding: 12px 14px; border-radius: 16px;
  background: var(--sheet-front); border: 1px solid var(--sheet-rim); box-shadow: var(--sheet-lift);
  animation: wd-drop var(--t-slide) both;
}
.wd-compose.gone { animation: wd-lift var(--t-slide) both; }
.wd-compose-head { display: flex; align-items: center; justify-content: space-between; font-size: 12.5px; color: var(--text-3); }
.wd-body { font-size: 14px; line-height: 1.5; color: var(--text-3); transition: color var(--t-slide); }
.wd-body.taken { color: var(--text); }
.wd-compose-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.wd-hint { font-size: 11px; color: var(--text-3); padding: 2px 6px; border-radius: 5px; border: 1px solid var(--hair); transition: opacity var(--t-fade); }
.wd-hint.gone { opacity: 0; }
.wd-send { display: inline-flex; align-items: center; gap: 6px; height: 30px; padding: 0 14px; border-radius: 999px; background: var(--accent); color: #fff; font-size: 13px; font-weight: 500; }
.wd-send.pressed { animation: wd-press var(--t) both; }
.wd-sent { align-self: center; display: inline-flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 500; color: var(--ok); animation: wd-drop var(--t-slide) both; }
.wd-again { align-self: flex-end; font-size: 12.5px; color: var(--accent-text); background: none; padding: 0; }
@media (prefers-reduced-motion: reduce) {
  .wd-note, .wd-row, .wd-card, .wd-compose, .wd-sent, .wd-note.gone, .wd-compose.gone, .wd-btn.pressed, .wd-send.pressed { animation: none; }
}

/* ==========================================================================
   Every screen (SPEC 70). The interface is drawn in CSS pixels for a phone, a
   tablet and a laptop; on a big monitor at 100% -- an ultrawide, a 4K screen --
   those pixels are tiny, so the whole interface scales up in steps with the
   screen, width and height both, and the app's height is divided back by the
   same factor so it still fills exactly one screen. Phones and tablets are
   never scaled: their browsers already do it.
   ========================================================================== */
:root { --ui-zoom: 1; }
@media (min-width: 2200px) and (min-height: 1200px) { :root { --ui-zoom: 1.15; } }
@media (min-width: 2800px) and (min-height: 1400px) { :root { --ui-zoom: 1.3; } }
@media (min-width: 3400px) and (min-height: 1900px) { :root { --ui-zoom: 1.6; } }
html { zoom: var(--ui-zoom); }

/* A touch screen scrolls with its finger on the glass: nothing on the page may make
   that heavy. The bar stops blurring what runs under it (SPEC 72). */
@media (hover: none) {
  .wn { -webkit-backdrop-filter: none; backdrop-filter: none; background: color-mix(in srgb, var(--field) 90%, transparent); }
}

/* the narrowest phones and a folded phone's cover screen (280-359px) */
@media (max-width: 359px) {
  .wn { padding: 6px 6px 6px 10px; }
  .wn-brand { font-size: 17px; gap: 8px; white-space: nowrap; }
  .wn-brand img { width: 26px; height: 26px; }
  .wn-links a:not(.wn-cta) { display: none; }
  .wn-links .wn-cta { padding: 0 12px; white-space: nowrap; }
  .welcome .tile { padding: 20px 16px; border-radius: 22px; }
  .wt-stack { padding: 20px 12px 24px; }
  .gs-sheet[data-pos="1"] { margin: 36px 10px 0; }
  .gs-sheet[data-pos="2"] { margin: 0 20px; }
  .gs-sheet[data-pos="3"] { margin: 0 30px; }
  .wc-num { font-size: 60px; }
  .wd-btn { height: auto; min-height: 36px; padding: 7px 12px; font-size: 13px; text-align: left; }
  .welcome .wth { padding: 24px 14px; }
}
/* the stack's depth is drawn in perspective, which pushes the front card past a narrow screen's edge */
@media (max-width: 480px) {
  .gs-sheet[data-pos="0"] { transform: translateZ(0); }
}

/* ==========================================================================
   The thread (SPEC 71): what the word means, and V Mail doing all three. A
   strand is drawn down through the conversation as it scrolls in; each message
   is a knot on it; the older ones open with a tap; the whole thing summarises.
   ========================================================================== */
.welcome .wth {
  display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); gap: 48px; align-items: start;
  padding: 44px;
}
.wth-word { margin: 0; font-size: 15px; color: var(--text-2); }
.wth-word b { font-family: var(--font-display); font-size: 22px; font-weight: 650; color: var(--text); letter-spacing: -0.02em; }
.wth-ipa { margin: 0 6px; color: var(--text-3); }
.wth-word i { color: var(--text-3); }
.wth-senses { margin: 12px 0 0; padding: 0 0 0 22px; display: flex; flex-direction: column; gap: 4px; font-size: 15px; line-height: 1.5; color: var(--text-2); }
.wth-senses li::marker { color: var(--accent-text); font-weight: 600; }
.wth h2 { margin-top: 26px; font-size: clamp(34px, 3.8vw, 56px); line-height: 1.02; letter-spacing: -0.04em; }
.wth-lede { margin: 14px 0 0; max-width: 34em; font-size: 17px; line-height: 1.55; color: var(--text-2); }
.wth-points { list-style: none; margin: 26px 0 0; padding: 0; display: flex; flex-direction: column; gap: 16px; max-width: 36em; }
.wth-points li { display: grid; grid-template-columns: 28px minmax(0, 1fr); gap: 12px; font-size: 15px; line-height: 1.5; color: var(--text-2); }
.wth-points b { color: var(--text); font-weight: 600; }
.wth-n {
  width: 28px; height: 28px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center;
  background: var(--sheet-front); border: 1px solid var(--sheet-rim); box-shadow: var(--sheet-lift);
  font-size: 13px; font-weight: 600; color: var(--accent-text);
}

/* The thread is sewn through the conversation (SPEC 71): it goes into each card
   through an eyelet at its top edge, runs behind it, comes out of an eyelet at
   its foot and crosses the gap to the next one, a little to the other side, the
   way a running stitch does. Only the stretches between cards are drawn, so the
   cards themselves are what it passes through. app.js measures the layout. */
.wth-demo { position: relative; display: flex; flex-direction: column; gap: 18px; min-width: 0; padding-top: 18px; }
.wth-thread { display: flex; flex-direction: column; gap: 18px; }
.wth-strand { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; z-index: 2; }
.wth-strand path {
  fill: none; stroke: var(--accent); stroke-width: 2; stroke-linecap: round;
  stroke-dasharray: 1; stroke-dashoffset: 0; transition: stroke-dashoffset var(--t-draw);
}
.wth-eyelets circle { fill: var(--sheet-back); stroke: color-mix(in srgb, var(--accent) 70%, var(--sheet-rim)); stroke-width: 1.5; transition: opacity var(--t-fade); }
.wth-eyelets circle.wth-end { fill: var(--accent); stroke: none; }
.motion .wth:not(.in) .wth-strand path { stroke-dashoffset: 1; }
.motion .wth:not(.in) .wth-eyelets circle { opacity: 0; }
.wth-msg {
  position: relative; display: flex; flex-direction: column; gap: 6px; width: 100%; text-align: left;
  padding: 14px 16px; border-radius: 18px; color: var(--text);
  background: var(--sheet-front); border: 1px solid var(--sheet-rim); box-shadow: var(--sheet-lift);
  transition: background var(--t-fast), box-shadow var(--t-fast);
}
button.wth-msg:hover { background: color-mix(in srgb, var(--accent) 5%, var(--sheet-front)); }
.wth-msg-head { display: flex; align-items: baseline; gap: 10px; font-size: 14px; min-width: 0; }
.wth-msg-head b { font-weight: 600; white-space: nowrap; min-width: 0; overflow: hidden; text-overflow: ellipsis; flex: 0 1 auto; }
.wth-subject { flex: 1; min-width: 0; font-size: 13px; color: var(--text-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wth-msg-head small { margin-left: auto; font-size: 12px; color: var(--text-3); white-space: nowrap; }
.wth-msg-text { margin: 0; font-size: 14px; line-height: 1.5; color: var(--text-2); }
.wth-fold { display: grid; grid-template-rows: 0fr; transition: grid-template-rows var(--t-slide), opacity var(--t-fade); opacity: 0; }
.wth-fold-in { min-height: 0; overflow: hidden; font-size: 14px; line-height: 1.5; color: var(--text-2); }
.wth-msg[aria-expanded="true"] .wth-fold { grid-template-rows: 1fr; opacity: 1; }
.wth-related {
  display: flex; flex-direction: column; gap: 2px; padding: 12px 16px; border-radius: 16px;
  background: var(--sheet-back); border: 1px dashed color-mix(in srgb, var(--accent) 35%, var(--sheet-rim));
}
.wth-related-label { font-size: 11px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--accent-text); }
.wth-rel { display: flex; flex-direction: column; gap: 1px; padding-top: 8px; }
.wth-rel + .wth-rel { border-top: 1px solid var(--hair-soft); margin-top: 8px; }
.wth-rel b { font-size: 13.5px; font-weight: 600; }
.wth-rel span { font-size: 13.5px; color: var(--text-2); }
.wth-actions { display: flex; margin-top: 10px; }
.wth-summary { display: flex; flex-direction: column; }
.wth-summary:empty { display: none; }
.wth-status { display: flex; flex-wrap: wrap; gap: 6px; }

@media (max-width: 699px) {
  .welcome .wth { padding: 28px 20px; gap: 28px; }
  .wth h2 { font-size: clamp(30px, 9vw, 40px); }
  .wth-subject { display: none; }
}
/* after the thread's own rules, so they win: one column below the two-column width */
@media (max-width: 999px) { .welcome .wth { grid-template-columns: minmax(0, 1fr); gap: 32px; } }
@media (max-width: 359px) { .welcome .wth { padding: 24px 14px; } }

/* ==========================================================================
   Mark all (SPEC 73): every mailbox has Select in its head; the bar then offers
   the whole mailbox and says its four everyday actions in words.
   ========================================================================== */
.select-btn { gap: 5px; margin-left: 4px; flex: none; }
.bulk-bar { gap: 4px; }
.bulk-bar .bulk-act { gap: 5px; padding: 0 9px; }
.bulk-bar .bulk-act.danger { color: var(--danger); }
.bulk-bar .select-all-link { margin-left: 10px; font-size: 12.5px; color: var(--accent-text); white-space: nowrap; }
.bulk-bar .n { white-space: nowrap; }
/* the words fit when the list column is wide, whatever the screen: measured on the column itself */
.list-pane { container-type: inline-size; container-name: list; }
@container list (max-width: 560px) {
  .bulk-bar .bulk-act .label { display: none; }
  .bulk-bar .bulk-act { width: 30px; padding: 0; justify-content: center; }
}
@media (max-width: 699px) {
  .select-btn .label { display: none; }
  .select-btn { width: 30px; padding: 0; justify-content: center; }
}

/* ==========================================================================
   Read and unread, told apart at a glance (SPEC 74). The dot alone was too
   quiet. Unread mail carries a bar in the accent down its left edge, a bold
   sender, its subject and time in the accent and bold, and a faint tint; read
   mail steps back to regular weight in the secondary colours. Last in the
   file so it holds in every layout (glass, phone, dense).
   ========================================================================== */
.list .row.unread { background: color-mix(in srgb, var(--accent) 5%, transparent); }
.list .row.unread:hover { background: color-mix(in srgb, var(--accent) 9%, transparent); }
.list .row.unread::before {
  content: ""; position: absolute; left: 0; top: 7px; bottom: 7px; width: 3px;
  border-radius: 0 3px 3px 0; background: var(--accent);
}
.list .row.unread .from { font-weight: 700; color: var(--text); }
.list .row.unread .subject { font-weight: 600; color: var(--accent-text); }
.list .row.unread .date { font-weight: 600; color: var(--accent-text); }
.list .row.unread .snippet { color: var(--text-2); }
.list .row:not(.unread) .from { font-weight: 400; color: var(--text-2); }
.list .row:not(.unread) .subject { font-weight: 400; color: var(--text-2); }
.list .row:not(.unread) .snippet { color: var(--text-3); }
.list .row:not(.unread) .date { font-weight: 400; color: var(--text-3); }
/* the one being read is picked out by its sheet, and keeps its words legible */
.list .row.selected.unread, .list .row.checked.unread { background: var(--sel); }
.list .row.selected:not(.unread) .from, .list .row.selected:not(.unread) .subject { color: var(--text); }

/* SPEC 75: an unread count reads as one -- the accent, bold -- and the shelf's name with it */
.side-item .count.unread { color: var(--accent-text); font-weight: 700; }
.side-item.has-unread .label { font-weight: 600; color: var(--text); }
.side-item.active .count.unread { color: var(--accent-text); }

/* ==========================================================================
   A day, set apart by type and space (SPEC 76). A tinted band with a stroke
   and a pill competed with the mail under it. The break is typographic: the
   day in semibold, its date quiet beside it, the count as plain grey figures
   at the right, a hairline beneath and room above. The fold chevron stays out
   of sight until it is useful -- on hover, on keyboard focus, or while the day
   is folded. The band keeps the list's own ground, so it can stay sticky.
   ========================================================================== */
.list .day-head {
  /* the day lines up with the senders under it, the count with their times */
  height: 34px; margin-top: 14px; padding: 0 var(--day-pad-right, 14px) 0 var(--day-pad-left, 32px); gap: 8px; border-radius: 0;
  background: var(--sheet-mid); box-shadow: none; border: 0; border-bottom: 1px solid var(--hair-soft);
  color: var(--text); font-size: 13px; font-weight: 650; letter-spacing: -0.01em;
}
.list .day-head:hover { background: var(--sheet-mid); }
.list .day-head .label { color: var(--text); }
.list .day-head .when { font-size: 12px; font-weight: 400; color: var(--text-3); }
.list .day-head .spacer { flex: 1; height: auto; margin: 0; background: none; }
.list .day-head .count {
  display: inline; min-width: 0; height: auto; padding: 0; border-radius: 0; background: none;
  color: var(--text-3); font-size: 12px; font-weight: 500; font-variant-numeric: tabular-nums;
}
/* the chevron lives in the gutter where the unread dots are, so it takes no room from the line */
.list .day-head .icon {
  position: absolute; left: 11px; top: 50%; translate: 0 -50%;
  color: var(--text-3); opacity: 0; transition: opacity var(--t-fast), transform var(--t-fast);
}
.list .day-head:hover .icon, .list .day-head:focus-visible .icon, .list .day-head.collapsed .icon { opacity: 1; }
.list .day-head.collapsed .count { background: none; color: var(--accent-text); font-weight: 600; }
@media (hover: none) { .list .day-head .icon { opacity: 1; } }
.list > .day-group:first-child > .day-head, .list > .day-head:first-child { margin-top: 4px; }
/* the phone list pads its rows differently; the day follows them there too */
@media (max-width: 699px) { .list .day-head { --day-pad-left: 28px; --day-pad-right: 20px; } }

/* ==========================================================================
   Installed on a desktop (SPEC 77). The manifest asks for the window-controls
   overlay, so the app draws where a title bar would be and the window's own
   buttons float over its top right. The top bar leaves them their room (the
   titlebar-area environment variables say where they are), and the bar itself
   drags the window, except where there is something to press or type in.
   ========================================================================== */
@media (display-mode: window-controls-overlay) {
  .topbar {
    padding-left: calc(env(titlebar-area-x, 0px) + 12px);
    padding-right: calc(100vw - env(titlebar-area-x, 0px) - env(titlebar-area-width, 100vw) + 12px);
    min-height: max(50px, env(titlebar-area-height, 0px));
    -webkit-app-region: drag; app-region: drag;
  }
  .topbar button, .topbar a, .topbar input, .topbar select, .topbar label, .topbar .search, .topbar [role="button"] {
    -webkit-app-region: no-drag; app-region: no-drag;
  }
}

/* ==========================================================================
   On a phone the page itself scrolls (SPEC 78). The shell used to be pinned to
   the screen with every pane scrolling inside it, and a browser only folds its
   own bars away -- Safari's address bar sinking to a sliver, Chrome's and
   Samsung Internet's sliding off -- when the document scrolls. So below 700px
   the document is the scroller: the top bar sticks, the day labels stick under
   it, and everything that has to stay on screen (search and Compose, the
   message's actions, the thread panel, compose, the selection bar) is fixed to
   the screen, so it rides down with the browser's bars as they go.
   ========================================================================== */
@media (max-width: 699px) {
  html.doc-scroll, html.doc-scroll body { height: auto; min-height: 100%; overflow-y: visible; overflow-x: hidden; }
  @supports (overflow-x: clip) { html.doc-scroll, html.doc-scroll body { overflow-x: clip; } }
  html.doc-scroll .app { height: auto; min-height: 100vh; min-height: 100dvh; overflow: visible; grid-template-rows: auto auto; }
  html.doc-scroll .topbar { position: sticky; top: 0; }
  html.doc-scroll .panes, html.doc-scroll .list-pane, html.doc-scroll .thread-pane,
  html.doc-scroll .calendar-pane, html.doc-scroll .cal-body { overflow: visible; min-height: 0; }
  html.doc-scroll .list, html.doc-scroll .thread-scroll { flex: none; overflow: visible; }
  html.doc-scroll .reader { display: block; overflow: visible; }
  html.doc-scroll .list .day-head { top: calc(56px + var(--safe-top)); }
  html.doc-scroll .list-pane, html.doc-scroll .thread-pane { min-height: calc(100dvh - 56px - var(--safe-top)); }

  html.doc-scroll .thread-panel {
    position: fixed; top: calc(56px + var(--safe-top)); bottom: 0; left: 0; right: 0;
    width: auto; z-index: 29; overscroll-behavior: contain;
  }
  html.doc-scroll .sheet {
    position: fixed; top: calc(64px + var(--safe-top)); bottom: 0; left: 0; right: 0;
    height: auto; max-height: none; z-index: 29;
  }
  /* writing: the sheet is the page, so nothing scrolls behind it */
  html.doc-scroll .app[data-view="compose"] .reader,
  html.doc-scroll .app[data-view="compose"] .thread-toolbar { display: none; }
  html.doc-scroll .bulk-bar {
    position: fixed; top: calc(56px + var(--safe-top)); left: 0; right: 0; z-index: 29;
    padding-left: calc(14px + var(--safe-left)); padding-right: calc(10px + var(--safe-right));
  }
}

/* The message's iframe scrolls inside a wrapper, the way iOS Safari needs it
   (SPEC 78): the wrapper holds the size and the touch scrolling, and carries
   the card's rounding and shadow so its clipping does not cut them off. */
.msg-body .frame-scroll {
  overflow-y: auto; -webkit-overflow-scrolling: touch;
  max-height: 640px; border-radius: var(--radius-lg); box-shadow: var(--shadow);
}
.msg-body .frame-scroll.expanded { max-height: none; }
.msg-body .frame-scroll iframe { box-shadow: none; }
@media (min-width: 700px) { .msg-body .frame-scroll { box-shadow: none; border-radius: 16px; } }

/* ==========================================================================
   One gutter on a phone (SPEC 79). Every edge on the screen keeps the same
   16px from the side: the round buttons, the large title, the Focused and All
   pills, the unread dots, the chevrons of the days, the times, the selection
   button, search and Compose, the message and compose. The text of a row and
   of a day starts one dot further in, and its separator starts with that text.
   The head is the page's own ground, so no band shows between it and the bar.
   ========================================================================== */
@media (max-width: 699px) {
  .app { --gutter: 16px; --gutter-l: calc(var(--gutter) + var(--safe-left)); --gutter-r: calc(var(--gutter) + var(--safe-right)); --text-in: 18px; }
  .topbar { padding-left: var(--gutter-l); padding-right: var(--gutter-r); }

  .list-head {
    min-height: 0; padding: 4px var(--gutter-r) 18px var(--gutter-l); gap: 8px; align-items: center;
    background: transparent; box-shadow: none; -webkit-backdrop-filter: none; backdrop-filter: none;
  }
  .list-head .select-btn { width: 40px; height: 40px; margin: 0; border-radius: 50%; }
  .list-tabs { padding: 0 var(--gutter-r) 12px var(--gutter-l); gap: 8px; }
  .list-tabs .tab { height: 34px; padding: 0 16px; border-radius: 17px; }
  .list-tabs .tab:not(.active) { background: color-mix(in srgb, var(--text) 7%, transparent); }
  html.doc-scroll .bulk-bar { padding-left: var(--gutter-l); padding-right: var(--gutter-r); }

  .row {
    grid-template-columns: 10px minmax(0, 1fr) auto; column-gap: calc(var(--text-in) - 10px);
    padding: 12px var(--gutter-r) 12px var(--gutter-l);
  }
  .row::after { left: calc(var(--gutter-l) + var(--text-in)); }
  .row .check { left: calc(var(--gutter-l) - 3px); }
  .list .day-head { --day-pad-left: calc(var(--gutter-l) + var(--text-in)); --day-pad-right: var(--gutter-r); }
  .list .day-head .icon { left: calc(var(--gutter-l) - 1px); }

  .reader-head { padding: 12px var(--gutter-r) 4px var(--gutter-l); }
  .msg-head, .msg-enrich, .body-tools, .attachments, .msg-fold, .msg-newer { padding-left: var(--gutter-l); padding-right: var(--gutter-r); }
  .msg-enrich.ai-card { margin-left: var(--gutter-l); margin-right: var(--gutter-r); }
  .msg-body { padding: 12px var(--gutter-r) 6px var(--gutter-l); }
  .sheet-head { padding: 0 var(--gutter-r) 0 var(--gutter-l); }
  .field { padding-left: var(--gutter-l); padding-right: var(--gutter-r); }
}

/* ==========================================================================
   Search folds into a pill (SPEC 80). Scrolling down a phone's list, the
   search field draws in from the left like a funnel until it is a small pill
   at the right holding the search glass and, inside it, Compose; scrolling
   back up or reaching the top opens it out again, and a tap on the pill opens
   it and puts the cursor in it. app.js sets .bar-min from the scroll.
   ========================================================================== */
@media (max-width: 699px) {
  .app { --pill-w: calc(var(--float-h) * 2 + 12px); }
  .app[data-view="list"] #searchBox {
    transition: left var(--t-slide), right var(--t-slide), padding var(--t-slide), box-shadow var(--t-fast), background var(--t-fast);
  }
  .app[data-view="list"] #composeBtn {
    transition: right var(--t-slide), bottom var(--t-slide), width var(--t-slide), height var(--t-slide), transform var(--t-fast), background var(--t-fast);
  }
  .app[data-view="list"] #searchBox input { transition: opacity var(--t-fade); }

  .app[data-view="list"].bar-min #searchBox {
    left: calc(100% - var(--gutter-r) - var(--pill-w));
    right: var(--gutter-r);
    padding: 0 14px; cursor: pointer;
  }
  .app[data-view="list"].bar-min #searchBox input { opacity: 0; pointer-events: none; }
  .app[data-view="list"].bar-min #searchBox .clear,
  .app[data-view="list"].bar-min #searchBox .search-hints { display: none; }
  .app[data-view="list"].bar-min #composeBtn {
    z-index: 32;
    right: calc(var(--gutter-r) + 5px);
    bottom: calc(var(--float-gap) + var(--safe-bottom) + 5px);
    width: calc(var(--float-h) - 10px); height: calc(var(--float-h) - 10px);
    box-shadow: none;
  }
  .app[data-view="list"].bar-min #composeBtn .icon { width: 19px; height: 19px; }
}

/* A phone scrolls a long inbox as smoothly as it can (SPEC 80): the browser
   skips days that are off screen, taps land at once, and no row flashes the
   system's grey tap highlight. */
@media (max-width: 699px) {
  html.doc-scroll .day-group { content-visibility: auto; contain-intrinsic-size: auto 480px; }
  .row, .day-head, .list-tabs .tab, #searchBox, #composeBtn { touch-action: manipulation; -webkit-tap-highlight-color: transparent; }
}

/* ==========================================================================
   A phone's top and its gestures (SPEC 81). The top bar has no ground of its
   own: only the round glass buttons float over the mail, so nothing blurred
   sits under the browser's own edge and the days no longer stick beneath it.
   Refresh is a pull from the top of the list (the page's own pull-to-reload is
   held back), the mailboxes come in from the left edge, and a message swipes
   right to left to delete and left to right to mark it unread or read.
   ========================================================================== */
@media (max-width: 699px) {
  html.doc-scroll { overscroll-behavior-y: contain; }
  html.doc-scroll .app { background: var(--bg); }
  html.doc-scroll .topbar { background: transparent; pointer-events: none; }
  html.doc-scroll .topbar > :not(.topbar-right), html.doc-scroll .topbar-right > * { pointer-events: auto; }
  html.doc-scroll .list .day-head { position: relative; top: auto; }
  .topbar #syncBtn { display: none; }

  .ptr {
    position: fixed; z-index: 33; left: 50%; top: calc(var(--safe-top) + 4px);
    width: 36px; height: 36px; border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    background: var(--glass-solid); color: var(--text-2);
    border: 0.5px solid var(--glass-border); box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
    transform: translate(-50%, -60px); opacity: 0; pointer-events: none;
    transition: transform var(--t-slide), opacity var(--t-fade), color var(--t-fast);
  }
  .ptr.pulling { transition: color var(--t-fast); }
  .ptr.armed { color: var(--accent-text); }
  .ptr.busy .icon { animation: spin 0.8s linear infinite; }

  html.doc-scroll .list { position: relative; }
  .list .row { touch-action: pan-y; }
  .list .row.swiping { z-index: 1; background: var(--bg); }
  .list .row.swiping.unread { background: color-mix(in srgb, var(--accent) 5%, var(--bg)); }
  .list .row.swiping::after { display: none; }
  .list .row.settle { transition: transform var(--t-slide); }
  .swipe-under {
    --p: 0; --act: var(--danger);
    position: absolute; left: 0; right: 0; z-index: 0; overflow: hidden;
    display: flex; align-items: center; padding: 0 calc(var(--gutter-r) + 6px) 0 calc(var(--gutter-l) + 6px);
    color: #fff; font-size: 13px; font-weight: 600;
    background: color-mix(in srgb, var(--text) 16%, var(--bg));
  }
  /* SPEC 82: the action's colour fills in with the distance swiped, over a quiet ground */
  .swipe-under::before { content: ""; position: absolute; inset: 0; background: var(--act); opacity: calc(0.25 + var(--p) * 0.75); }
  .swipe-under.delete { justify-content: flex-end; }
  .swipe-under.flag { --act: var(--accent-2); justify-content: flex-start; }
  .swipe-act {
    position: relative; display: inline-flex; flex-direction: column; align-items: center; gap: 4px;
    opacity: calc(0.4 + var(--p) * 0.6); transform: scale(calc(0.72 + var(--p) * 0.28));
    transition: transform var(--t-fast);
  }
  .swipe-act .icon { width: 22px; height: 22px; }
  .swipe-under.armed .swipe-act { transform: scale(1.14); }
}

/* A flagged message is flagged at a glance, in every layout (SPEC 81): the whole
   row takes the flag's orange, with a bar of it down the left edge in place of
   the unread one. Last in the file, so it holds over read, unread and glass. */
.list .row.flagged { background: color-mix(in srgb, var(--accent-2) 16%, transparent); }
.list .row.flagged:hover { background: color-mix(in srgb, var(--accent-2) 22%, transparent); }
.list .row.flagged::before {
  content: ""; position: absolute; left: 0; top: 7px; bottom: 7px; width: 3px;
  border-radius: 0 3px 3px 0; background: var(--accent-2);
}
.list .row.flagged.selected, .list .row.flagged.checked { background: color-mix(in srgb, var(--accent-2) 26%, transparent); }
@media (max-width: 699px) {
  .list .row.swiping.flagged { background: color-mix(in srgb, var(--accent-2) 16%, var(--bg)); }
}

/* ==========================================================================
   The phone's glass, lifted (SPEC 82). The round buttons over the mail -- the
   menu, the way back, the calendar, the profile, compose's close -- and the
   message's action bar sit higher: a heavier blur and saturation of what runs
   under them, a deeper two-part shadow and a brighter rim, so they read as
   floating above the page rather than printed on it. Their icons, the search
   glass and the action bar's icons are drawn at the pencil's size.
   ========================================================================== */
@media (max-width: 699px) {
  .topbar .menu-btn, .topbar .back-btn, .topbar #calendarBtn, .topbar .profile-btn,
  .sheet-head #composeClose,
  .app[data-view="list"] #searchBox, .app[data-view="thread"] .thread-toolbar {
    background: var(--glass);
    -webkit-backdrop-filter: blur(calc(var(--glass-blur) * 1.8)) saturate(210%);
    backdrop-filter: blur(calc(var(--glass-blur) * 1.8)) saturate(210%);
    border: 0.5px solid var(--glass-border);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.26), 0 2px 8px rgba(0, 0, 0, 0.16), inset 0 1px 0 var(--glass-hi);
  }
  .topbar .profile-btn { width: 44px; height: 44px; }
  .topbar .profile-btn .avatar { width: 38px; height: 38px; }
  .topbar .menu-btn, .topbar .back-btn, .topbar #calendarBtn { width: 44px; height: 44px; }
  .topbar .menu-btn .icon, .topbar .back-btn .icon, .topbar #calendarBtn .icon { width: 21px; height: 21px; }
  .sheet-head #composeClose { width: 36px; height: 36px; border-radius: 50%; color: var(--text); }

  .app[data-view="list"] #searchIcon .icon { width: 22px; height: 22px; }

  .app[data-view="thread"] .thread-toolbar { height: 58px; border-radius: 29px; padding: 0 8px; }
  .app[data-view="thread"] .thread-toolbar .btn,
  .app[data-view="thread"] .thread-toolbar .icon-btn { width: 46px; height: 46px; }
  .app[data-view="thread"] .thread-toolbar .icon { width: 22px; height: 22px; }
  html.doc-scroll .thread-scroll { padding-bottom: calc(58px + var(--float-gap) * 2 + var(--safe-bottom) + 12px); }
}

/* ==========================================================================
   Like a native iOS app (SPEC 83). On a phone the type follows the system's
   default text sizes -- a 34px large title, 17px senders, body and fields,
   15px subjects, previews and times, 13px footnotes -- and the motion follows
   its curve: a message pushes in from the right over the list, Back brings the
   list in from the left, compose rises and the mailboxes slide on the same
   long, soft landing, a row greys while it is held, and every field is at
   least 16px so Safari never zooms into it.
   ========================================================================== */
@keyframes ios-push { from { transform: translateX(100%); } to { transform: none; } }
@keyframes ios-pop { from { transform: translateX(-28%); opacity: 0.6; } to { transform: none; opacity: 1; } }
@media (max-width: 699px) {
  .list-head h2 { font-size: 34px; letter-spacing: -0.4px; line-height: 1.12; }
  .list-head .count { font-size: 17px; }
  .list-tabs .tab { font-size: 15px; font-weight: 500; }
  .list .day-head { font-size: 13px; }
  .list .day-head .when, .list .day-head .count { font-size: 13px; }
  .row .from { font-size: 17px; }
  .row .date { font-size: 15px; }
  .row .subject { font-size: 15px; }
  .row .snippet { font-size: 15px; line-height: 1.33; }
  .row .meta { font-size: 13px; }

  .reader-head h1 { font-size: 26px; line-height: 1.18; }
  .msg-who .name { font-size: 17px; }
  .msg-right .date, .msg-who .to { font-size: 15px; }
  .msg-body pre.plain { font-size: 17px; line-height: 1.5; padding: 14px 16px; }

  .side-item { font-size: 17px; }
  .side-title { font-size: 13px; }
  .field input, .field select, .body-wrap textarea, .text-input, .modal input, .modal select, .modal textarea { font-size: 17px; }
  .field label { font-size: 15px; }
  .sheet-head h2 { font-size: 17px; font-weight: 600; }

  /* the reader and the bar move, not the pane: a transform on the pane would pull its fixed bar and panel along */
  .app[data-nav="push"] .thread-pane > .reader, .app[data-nav="push"] .thread-toolbar { animation: ios-push var(--t-push) both; }
  .app[data-nav="pop"] .list-pane { animation: ios-pop var(--t-push) both; }
  .sheet, .sheet.open { transition-duration: var(--d-push); transition-timing-function: var(--ease-ios); }
  .sidebar { transition: transform var(--t-push); }
  .app[data-view="list"] #searchBox {
    transition: left var(--t-push), right var(--t-push), padding var(--t-push), box-shadow var(--t-fast), background var(--t-fast);
  }
  .app[data-view="list"] #composeBtn {
    transition: right var(--t-push), bottom var(--t-push), width var(--t-push), height var(--t-push), transform var(--t-fast), background var(--t-fast);
  }
  .list .row:active:not(.swiping) { background: color-mix(in srgb, var(--text) 9%, transparent); }
}

/* ==========================================================================
   The phone's controls float (SPEC 84). The glass is drawn on a layer of its
   own behind each control (::before, z-index -1 inside an isolated control),
   never on the control itself: Safari could composite a backdrop blur over
   the control's own content, and the icons vanished under their glass. So the
   icon always paints above the blur, and the control stands a level higher in
   depth over the page: a long soft shadow under a short close one, a lit top
   rim and a shaded lower rim, a touch more fill than the page behind.
   ========================================================================== */
@media (max-width: 699px) {
  .topbar .menu-btn, .topbar .back-btn, .topbar #calendarBtn, .topbar .profile-btn, .sheet-head #composeClose {
    position: relative;
  }
  .topbar .menu-btn, .topbar .back-btn, .topbar #calendarBtn, .topbar .profile-btn, .sheet-head #composeClose,
  .app[data-view="list"] #searchBox, .app[data-view="list"] #composeBtn, .app[data-view="thread"] .thread-toolbar {
    isolation: isolate;
    background: transparent;
    -webkit-backdrop-filter: none; backdrop-filter: none;
    box-shadow:
      0 22px 44px -6px rgba(0, 0, 0, 0.34),
      0 8px 16px -4px rgba(0, 0, 0, 0.22),
      0 1px 3px rgba(0, 0, 0, 0.18),
      inset 0 1px 0 color-mix(in srgb, white 34%, transparent),
      inset 0 -1px 0 rgba(0, 0, 0, 0.14);
  }
  .topbar .menu-btn::before, .topbar .back-btn::before, .topbar #calendarBtn::before, .topbar .profile-btn::before,
  .sheet-head #composeClose::before,
  .app[data-view="list"] #searchBox::before, .app[data-view="list"] #composeBtn::before, .app[data-view="thread"] .thread-toolbar::before {
    content: ""; position: absolute; inset: 0; z-index: -1; border-radius: inherit; pointer-events: none;
    background: color-mix(in srgb, var(--glass) 82%, color-mix(in srgb, var(--text) 14%, transparent));
    -webkit-backdrop-filter: blur(40px) saturate(210%);
    backdrop-filter: blur(40px) saturate(210%);
  }
  .app[data-view="list"] #composeBtn { color: #fff; }
  .app[data-view="list"] #composeBtn::before { background: color-mix(in srgb, var(--accent) 88%, transparent); }
  .app[data-view="list"] #composeBtn {
    box-shadow:
      0 22px 44px -6px color-mix(in srgb, var(--accent) 45%, rgba(0, 0, 0, 0.3)),
      0 8px 16px -4px rgba(0, 0, 0, 0.24),
      inset 0 1px 0 color-mix(in srgb, white 40%, transparent);
  }
  .app[data-view="list"] #searchBox:focus-within {
    box-shadow: 0 22px 44px -6px rgba(0, 0, 0, 0.34), 0 0 0 1.5px var(--accent);
  }
  .topbar .profile-btn .avatar { box-shadow: 0 1px 3px rgba(0, 0, 0, 0.28); }
}

/* ==========================================================================
   Bigger type on a phone, and the profile as a sheet (SPEC 85). Every text on
   a phone steps up a size from the system defaults of SPEC 83 -- the drawer's
   mailboxes and folders most of all -- and the drawer is wider to hold them.
   The profile opens as a sheet that takes the screen under the top buttons:
   a large avatar and name, then Your profile, Settings, Mailboxes and Sign
   out as full-width rows at finger size.
   ========================================================================== */
@media (max-width: 699px) {
  .sidebar { width: min(330px, 88vw); }
  .side-item { height: 50px; font-size: 18px; gap: 14px; }
  .side-item .icon { width: 22px; height: 22px; }
  .side-item .count { font-size: 15px; }
  .side-title, .side-title .side-fold, .side-title button { font-size: 15px; }
  .side-empty, .side-foot { font-size: 15px; }

  .list-head h2 { font-size: 36px; }
  .list-tabs .tab { font-size: 16px; height: 36px; border-radius: 18px; }
  .list .day-head, .list .day-head .when, .list .day-head .count { font-size: 14px; }
  .row .from { font-size: 18px; }
  .row .date { font-size: 15px; }
  .row .subject { font-size: 16px; }
  .row .snippet { font-size: 16px; }
  .row .meta { font-size: 14px; }
  .app[data-view="list"] #searchBox input { font-size: 18px; }

  .reader-head h1 { font-size: 28px; }
  .msg-who .name { font-size: 18px; }
  .msg-right .date, .msg-who .to { font-size: 16px; }
  .msg-body pre.plain { font-size: 18px; }
  .field input, .field select, .body-wrap textarea, .text-input, .modal input, .modal select, .modal textarea { font-size: 18px; }
  .field label { font-size: 16px; }
  .sheet-head h2 { font-size: 18px; }
  .menu button { height: 48px; font-size: 17px; gap: 12px; }
  .menu button .icon { width: 20px; height: 20px; }
  .toast { font-size: 16px; }
  .settings-nav button { height: 38px; font-size: 16px; }
  .settings-section h3 { font-size: 20px; }
  .settings-section > p { font-size: 15px; }
  .modal-head h2 { font-size: 20px; }

  .menu.profile-menu {
    position: fixed; left: 0; right: 0; bottom: 0; top: calc(64px + var(--safe-top));
    min-width: 0; margin: 0; z-index: 60; overflow-y: auto; overscroll-behavior: contain;
    padding: 12px calc(16px + var(--safe-right)) calc(28px + var(--safe-bottom)) calc(16px + var(--safe-left));
    border-radius: 28px 28px 0 0; border-bottom: 0;
    /* solid, not glass: text on a sheet this size stays sharp, and Safari cannot blur over it */
    background: color-mix(in srgb, var(--bg) 94%, var(--text) 6%); -webkit-backdrop-filter: none; backdrop-filter: none;
    box-shadow: 0 -12px 40px rgba(0, 0, 0, 0.3);
    display: flex; flex-direction: column; gap: 4px;
    animation: ios-sheet var(--t-push) both;
  }
  .profile-menu.closing { animation: fold-away var(--t-fast) forwards; }
  .profile-menu .profile-head {
    flex-direction: column; align-items: center; text-align: center; gap: 12px;
    padding: 18px 8px 22px; margin-bottom: 8px;
  }
  .profile-menu .profile-head .avatar { width: 84px; height: 84px; font-size: 30px; }
  .profile-menu .profile-head .who { align-items: center; gap: 4px; }
  .profile-menu .profile-head strong { font-size: 24px; font-weight: 700; letter-spacing: -0.3px; }
  .profile-menu .profile-head span { font-size: 16px; }
  .profile-menu button { height: 56px; padding: 0 16px; border-radius: 16px; font-size: 18px; gap: 14px; }
  .profile-menu button .icon { width: 22px; height: 22px; }
  .profile-menu .menu-note { padding: 10px 16px; font-size: 15px; }
  .profile-menu .menu-sep { margin: 8px 4px; }
}
@keyframes ios-sheet { from { transform: translateY(100%); } to { transform: none; } }

/* The picture floats bare, and nothing glass is ever over an icon (SPEC 85). The
   profile button carries no glass at all: the photo (or the initials) fills the
   whole circle and floats on its shadow alone, so no blur can sit over the face.
   In every other glass control the content is lifted onto its own layer above
   the glass behind it, so Safari cannot composite the blur on top of it. */
@media (max-width: 699px) {
  .topbar .profile-btn { border: 0; background: transparent; }
  .topbar .profile-btn::before { display: none; }
  .topbar .profile-btn .avatar { width: 44px; height: 44px; font-size: 15px; box-shadow: none; }
  .topbar .menu-btn > *, .topbar .back-btn > *, .topbar #calendarBtn > *, .topbar .profile-btn > *,
  .sheet-head #composeClose > *,
  .app[data-view="list"] #searchBox > :not(.search-hints), .app[data-view="list"] #composeBtn > *,
  .app[data-view="thread"] .thread-toolbar > * {
    position: relative; z-index: 1;
  }
}

/* The top of a phone has no blur at all (SPEC 86). The round buttons up there
   -- the menu, the way back, the calendar, the profile, compose's close -- are
   solid discs a shade lighter than the page, with a short crisp shadow and a
   lit rim, and their icons at full contrast. A backdrop blur there, under the
   status bar and Safari's own edge, only ever read as haze over the buttons.
   The glass stays below, on search, Compose and the message's bar. */
@media (max-width: 699px) {
  .topbar .menu-btn::before, .topbar .back-btn::before, .topbar #calendarBtn::before, .sheet-head #composeClose::before {
    background: color-mix(in srgb, var(--bg) 84%, var(--text) 16%);
    -webkit-backdrop-filter: none; backdrop-filter: none;
  }
  .topbar .menu-btn, .topbar .back-btn, .topbar #calendarBtn, .topbar .profile-btn, .sheet-head #composeClose {
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.28), 0 1px 3px rgba(0, 0, 0, 0.2), inset 0 1px 0 color-mix(in srgb, white 22%, transparent);
    color: var(--text);
  }
  .topbar .profile-btn { box-shadow: 0 6px 16px rgba(0, 0, 0, 0.28), 0 1px 3px rgba(0, 0, 0, 0.2); }
}

/* ==========================================================================
   iPad: the iPhone's look in two columns (SPEC 87).
   ========================================================================== */

/* The columns breathe with what you are doing: with no message open the list
   is wide; open one and the message takes the room while the list draws in,
   and back again when it closes. */
@media (min-width: 700px) {
  .app { --list-w: clamp(320px, 44vw, 460px); }
  .app.reading { --list-w: clamp(270px, 32vw, 352px); }
  .panes { transition: grid-template-columns var(--t-push); }
}

/* A message sized to its column, not to the screen: where the reader is narrow
   (a tablet in portrait, a small window) the sender, the recipients and the
   date stack as they do on a phone, the head's own buttons leave it to the bar
   above, and the bar keeps only what fits. */
@media (min-width: 700px) { .thread-pane { container: reader / inline-size; } }
@container reader (max-width: 640px) {
  .reader-head { padding-left: 22px; padding-right: 22px; }
  .msg-head, .msg-enrich, .body-tools, .attachments, .msg-fold, .msg-newer { padding-left: 22px; padding-right: 22px; }
  .msg-body { padding-left: 22px; padding-right: 22px; }
  .msg-enrich.ai-card { margin-left: 22px; margin-right: 22px; }
  .msg-head { grid-template-columns: auto minmax(0, 1fr); column-gap: 12px; row-gap: 2px; }
  .msg-right { grid-column: 2; padding-top: 0; }
  .msg-right .icon-btn { display: none; }
  .thread-toolbar { justify-content: space-between; gap: 0; }
  .thread-toolbar .spacer, .thread-toolbar .tb-sep,
  .thread-toolbar [title^="Reply all"], .thread-toolbar [aria-label="Print"] { display: none; }
}

/* A touch tablet: the iPhone's sizes, controls and gestures. */
@media (hover: none) and (pointer: coarse) and (min-width: 700px) {
  :root { --topbar-h: 64px; }
  .app { --gutter: 16px; --gutter-l: 16px; --gutter-r: 16px; --text-in: 18px; }

  /* no checkbox on every row: Select opens them, as on the phone */
  .row .check { display: none; }
  .list.selecting .row .check { display: block; }

  .list-head { height: auto; min-height: 60px; padding: 10px 18px 6px; }
  .list-head h2 { font-size: 30px; font-weight: 700; letter-spacing: -0.4px; }
  .list-tabs { padding: 2px 18px 12px; gap: 8px; }
  .list-tabs .tab { height: 36px; padding: 0 16px; border-radius: 18px; font-size: 16px; }
  .list-tabs .tab:not(.active) { background: color-mix(in srgb, var(--text) 7%, transparent); }
  .list .day-head, .list .day-head .when, .list .day-head .count { font-size: 14px; }
  .row .from { font-size: 18px; }
  .row .date { font-size: 15px; }
  .row .subject { font-size: 16px; }
  .row .snippet { font-size: 16px; line-height: 1.33; }
  .row .meta { font-size: 14px; }
  .list .row:active:not(.swiping) { background: color-mix(in srgb, var(--text) 9%, transparent); }

  .side-item { height: 48px; font-size: 17px; gap: 14px; }
  .side-item .icon { width: 22px; height: 22px; }
  .side-item .count, .side-title, .side-title .side-fold, .side-title button, .side-empty, .side-foot { font-size: 15px; }

  .reader-head h1 { font-size: 30px; line-height: 1.16; }
  .msg-who .name { font-size: 18px; }
  .msg-who .line, .msg-right .date { font-size: 15px; }
  .msg-body pre.plain { font-size: 18px; line-height: 1.5; }
  .thread-toolbar { height: 60px; }
  .thread-toolbar .btn, .thread-toolbar .icon-btn { width: 44px; height: 44px; padding: 0; justify-content: center; border-radius: 50%; }
  .thread-toolbar .btn .label { display: none; }
  .thread-toolbar .icon { width: 22px; height: 22px; }
  .thread-toolbar .thread-btn { width: auto; padding: 0 12px; border-radius: 22px; }

  .field input, .field select, .body-wrap textarea, .text-input, .modal input, .modal select, .modal textarea { font-size: 17px; }
  .menu button { height: 46px; font-size: 17px; gap: 12px; }
  .menu button .icon { width: 20px; height: 20px; }
  .toast { font-size: 16px; }

  /* the top: solid round buttons, a search pill, Compose as the one coloured disc; refresh is a pull */
  .topbar { height: calc(var(--topbar-h) + var(--safe-top)); }
  .topbar .menu-btn, .topbar #calendarBtn, .topbar #composeBtn {
    width: 44px; height: 44px; padding: 0; border-radius: 50%; justify-content: center; border: 0;
    background: color-mix(in srgb, var(--bg) 84%, var(--text) 16%); color: var(--text);
    -webkit-backdrop-filter: none; backdrop-filter: none;
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.28), 0 1px 3px rgba(0, 0, 0, 0.2), inset 0 1px 0 color-mix(in srgb, white 22%, transparent);
  }
  .topbar #composeBtn { background: var(--accent); color: #fff; }
  .topbar #calendarBtn .label, .topbar #composeBtn .label { display: none; }
  .topbar .menu-btn .icon, .topbar #calendarBtn .icon { width: 21px; height: 21px; }
  .topbar #composeBtn .icon { width: 22px; height: 22px; }
  .topbar #syncBtn { display: none; }
  .topbar .search { height: 44px; border-radius: 22px; padding: 0 16px; }
  .topbar .search input { font-size: 17px; }
  .topbar #searchIcon .icon { width: 22px; height: 22px; }
  .topbar .search .kbd { display: none; }
  .topbar .profile-btn { width: 44px; height: 44px; border: 0; box-shadow: 0 6px 16px rgba(0, 0, 0, 0.28), 0 1px 3px rgba(0, 0, 0, 0.2); }
  .topbar .profile-btn .avatar { width: 44px; height: 44px; font-size: 15px; }

  /* motion on the iOS curve */
  .sheet, .sheet.open { transition-duration: var(--d-push); transition-timing-function: var(--ease-ios); }
  .sidebar { transition: transform var(--t-push); }

  /* gestures: pull the list to refresh, swipe a row to delete or flag */
  .list { position: relative; }
  .list .row { touch-action: pan-y; }
  .list .row.swiping { z-index: 1; background: var(--sheet-mid); }
  .list .row.swiping.flagged { background: color-mix(in srgb, var(--accent-2) 16%, var(--sheet-mid)); }
  .list .row.settle { transition: transform var(--t-slide); }
  .swipe-under {
    --p: 0; --act: var(--danger);
    position: absolute; left: 8px; right: 8px; z-index: 0; overflow: hidden; border-radius: 14px;
    display: flex; align-items: center; padding: 0 22px;
    color: #fff; font-size: 13px; font-weight: 600;
    background: color-mix(in srgb, var(--text) 16%, var(--bg));
  }
  .swipe-under::before { content: ""; position: absolute; inset: 0; background: var(--act); opacity: calc(0.25 + var(--p) * 0.75); }
  .swipe-under.delete { justify-content: flex-end; }
  .swipe-under.flag { --act: var(--accent-2); justify-content: flex-start; }
  .swipe-act {
    position: relative; display: inline-flex; flex-direction: column; align-items: center; gap: 4px;
    opacity: calc(0.4 + var(--p) * 0.6); transform: scale(calc(0.72 + var(--p) * 0.28));
    transition: transform var(--t-fast);
  }
  .swipe-act .icon { width: 22px; height: 22px; }
  .swipe-under.armed .swipe-act { transform: scale(1.14); }
  .ptr {
    position: fixed; z-index: 33; left: 50%; top: calc(var(--safe-top) + 4px);
    width: 36px; height: 36px; border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    background: var(--glass-solid); color: var(--text-2);
    border: 0.5px solid var(--glass-border); box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
    transform: translate(-50%, -60px); opacity: 0; pointer-events: none;
    transition: transform var(--t-slide), opacity var(--t-fade), color var(--t-fast);
  }
  .ptr.pulling { transition: color var(--t-fast); }
  .ptr.armed { color: var(--accent-text); }
  .ptr.busy .icon { animation: spin 0.8s linear infinite; }
}

/* No haze on a touch screen, and an installed app to the very bottom (SPEC 87).
   The coloured blooms behind the glass read as a blur at the top of a phone or
   an iPad, around the status bar, and so did the glow under the logo; a touch
   screen gets the plain field. Installed on an iPad, the dynamic viewport height
   stopped short of the home indicator and left a band of another colour under
   the columns; there the full screen height is the app's. */
@media (hover: none) and (pointer: coarse) {
  body::before { display: none; }
  .brand .logo { box-shadow: none; }
}
@media (hover: none) and (pointer: coarse) and (min-width: 700px) {
  .topbar { background: transparent; -webkit-backdrop-filter: none; backdrop-filter: none; box-shadow: none; border-bottom: 0; }
}
@media (display-mode: standalone) {
  .app { height: 100vh; }
  html.doc-scroll .app { min-height: 100vh; }
}

/* ==========================================================================
   An iPad spends its screen on what you are doing (SPEC 88).
   - Nothing open: the list has the whole width, instead of a column beside an
     empty "Select a message".
   - A message open: the two share it, the message the larger part (SPEC 87).
   - Full screen (the expand button in the message's bar): the message has the
     whole width; the button again, or a swipe in from the left edge, gives the
     list back. Closing the message leaves full screen.
   ========================================================================== */
.focus-btn { display: none; }
@media (hover: none) and (pointer: coarse) and (min-width: 700px) {
  .focus-btn { display: inline-flex; }
  .app:not(.reading) .panes { grid-template-columns: minmax(0, 1fr) 0px; column-gap: 0; }
  .app.reading.focus .panes { grid-template-columns: 0px minmax(0, 1fr); column-gap: 0; }
  .app:not(.reading) .thread-pane,
  .app.reading.focus .list-pane { opacity: 0; pointer-events: none; overflow: hidden; border-width: 0; box-shadow: none; }
  .list-pane, .thread-pane { transition: opacity var(--t-fade); }
  .app:not(.reading) .list-tabs, .app:not(.reading) .list-head { padding-left: 24px; padding-right: 24px; }
}
@media (hover: none) and (pointer: coarse) and (min-width: 1100px) {
  .app:not(.reading) .panes { grid-template-columns: var(--sidebar-w) minmax(0, 1fr) 0px; column-gap: var(--gap-sheet); }
  .app.reading.focus .panes { grid-template-columns: 0px 0px minmax(0, 1fr); }
  .app.reading.focus .sidebar { opacity: 0; pointer-events: none; overflow: hidden; }
}
@container reader (max-width: 640px) {
  .thread-toolbar .thread-btn .label, .thread-toolbar .thread-btn .count { display: none; }
  .thread-toolbar .thread-btn { width: 44px; padding: 0; justify-content: center; }
}

/* ==========================================================================
   Peek and pop (SPEC 89). A message held under the finger rises out of the
   list: the page behind dims and blurs, the preview card scales up into the
   middle with the message's actions under it, the way iOS lifts a preview.
   Tap the card to open the message; tap anywhere else to put it back.
   ========================================================================== */
@keyframes peek-in { from { opacity: 0; transform: scale(0.9); } to { opacity: 1; transform: none; } }
@keyframes peek-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes peek-out { to { opacity: 0; transform: scale(0.96); } }
.peek {
  position: fixed; inset: 0; z-index: 70; isolation: isolate;
  display: flex; align-items: center; justify-content: center;
  padding: calc(24px + var(--safe-top)) calc(16px + var(--safe-right)) calc(24px + var(--safe-bottom)) calc(16px + var(--safe-left));
  animation: peek-fade var(--t-fade) both;
}
/* the dim and the blur are a layer behind the preview, never on the overlay that holds it (SPEC 84) */
.peek::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: color-mix(in srgb, black 34%, transparent);
  -webkit-backdrop-filter: blur(18px) saturate(140%); backdrop-filter: blur(18px) saturate(140%);
}
.peek.closing { animation: peek-out var(--t-fast) forwards; pointer-events: none; }
.peek-stack {
  width: min(520px, 100%); max-height: 100%;
  display: flex; flex-direction: column; gap: 12px;
  animation: peek-in var(--t-push) both;
}
.peek-card {
  display: flex; flex-direction: column; gap: 10px; text-align: left; width: 100%;
  padding: 20px 20px 22px; border-radius: 22px;
  background: var(--bg); color: var(--text);
  box-shadow: 0 30px 70px rgba(0, 0, 0, 0.45), 0 2px 8px rgba(0, 0, 0, 0.2);
  overflow: hidden; min-height: 0;
}
.peek-card:active { transform: scale(0.985); transition: transform var(--t-fast); }
.peek-head { display: flex; align-items: center; gap: 12px; min-width: 0; }
.peek-head .avatar { width: 44px; height: 44px; font-size: 15px; flex: none; }
.peek-who { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.peek-who strong { font-size: 17px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.peek-who span { font-size: 14px; color: var(--text-3); }
.peek-subject { font-size: 20px; font-weight: 700; line-height: 1.25; letter-spacing: -0.2px; }
.peek-body {
  font-size: 17px; line-height: 1.45; color: var(--text-2);
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 9; overflow: hidden;
}
.peek-actions {
  align-self: stretch; border-radius: 16px; overflow: hidden;
  background: color-mix(in srgb, var(--bg) 88%, var(--text) 12%);
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.35);
}
.peek-act {
  display: flex; align-items: center; justify-content: space-between; width: 100%;
  height: 50px; padding: 0 18px; font-size: 17px; color: var(--text); text-align: left;
}
.peek-act + .peek-act { border-top: 1px solid var(--hair-soft); }
.peek-act .icon { width: 20px; height: 20px; }
.peek-act:active { background: color-mix(in srgb, var(--text) 8%, transparent); }
.peek-act.danger { color: var(--danger); }
@media (min-width: 700px) { .peek-actions { width: 280px; align-self: flex-end; } }
@media (hover: none) and (pointer: coarse) {
  .list .row { -webkit-touch-callout: none; -webkit-user-select: none; user-select: none; }
}

/* ==========================================================================
   Clear of the system's edge, and Select in words (SPEC 90). iOS blurs the
   strip under the status bar by itself, and no page can switch that off, so
   the phone's top bar keeps out of it: its buttons sit 12px lower, and all
   that is measured from the bar (the thread panel, compose, the selection
   bar, the profile sheet, the drawer) moves down with it. Select is the word
   in the mailbox's colour on the title's line, as in Mail -- not a lone tick
   that read as a mark under the profile picture.
   ========================================================================== */
@media (max-width: 699px) {
  .app { --bar-drop: 12px; }
  .topbar { height: calc(56px + var(--bar-drop) + var(--safe-top)); padding-top: calc(var(--safe-top) + var(--bar-drop)); }
  .sidebar { padding-top: calc(56px + var(--bar-drop) + var(--safe-top) + 6px); }
  html.doc-scroll .list-pane, html.doc-scroll .thread-pane { min-height: calc(100dvh - 56px - var(--bar-drop) - var(--safe-top)); }
  html.doc-scroll .thread-panel { top: calc(56px + var(--bar-drop) + var(--safe-top)); }
  html.doc-scroll .sheet { top: calc(64px + var(--bar-drop) + var(--safe-top)); }
  html.doc-scroll .bulk-bar { top: calc(56px + var(--bar-drop) + var(--safe-top)); }
  .menu.profile-menu { top: calc(64px + var(--bar-drop) + var(--safe-top)); }

  .list-head .select-btn {
    width: auto; height: 40px; padding: 0 2px 0 8px; border-radius: 0; background: none; box-shadow: none;
    color: var(--accent-text); font-size: 17px; font-weight: 500;
  }
  .list-head .select-btn .icon { display: none; }
  .list-head .select-btn .label { display: inline; }
}

/* Peek never selects text (SPEC 89): on any device with a touch screen -- an iPad
   with a keyboard and trackpad included -- the rows and the preview take no text
   selection and no system callout, so a long press lifts the preview and nothing
   else. */
.peek, .peek * { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
@media (any-pointer: coarse) {
  .list .row, .list .row * { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
}

/* ==========================================================================
   The selection bar, for a mouse and for a finger (SPEC 92). Its two groups --
   what is selected (the tick, the count, Select all, Done) and what to do
   with it -- flow as one line under a mouse, as before. On a touch screen the
   bar grows to two rows: the count with Done, then the actions as large
   labelled buttons in a row that scrolls sideways and settles on a button,
   fading out at its edges. It is solid, not glass: nothing blurs over it.
   ========================================================================== */
.bulk-bar .bulk-top, .bulk-bar .bulk-acts { display: contents; }
.bulk-bar .bulk-done { order: 99; }
.bulk-bar .bulk-done .label, .bulk-bar .bulk-extra .label { display: none; }
@media (hover: none) and (pointer: coarse), (max-width: 699px) {
  .bulk-bar {
    height: auto; flex-direction: column; align-items: stretch; gap: 0; padding: 0;
    background: color-mix(in srgb, var(--bg) 94%, var(--text) 6%);
    -webkit-backdrop-filter: none; backdrop-filter: none;
    box-shadow: 0 10px 24px rgba(0, 0, 0, 0.22);
  }
  .bulk-bar .bulk-top {
    display: flex; align-items: center; gap: 10px; min-height: 52px;
    padding: 0 var(--gutter-r, 16px) 0 var(--gutter-l, 16px);
  }
  .bulk-bar .bulk-top .check input { width: 22px; height: 22px; }
  .bulk-bar .n { font-size: 17px; font-weight: 600; margin-left: 0; }
  .bulk-bar .select-all-link { font-size: 16px; margin-left: 4px; text-decoration: none; }
  .bulk-bar .bulk-done { order: 0; width: auto; height: 40px; padding: 0 4px; color: var(--accent-text); font-size: 17px; font-weight: 600; }
  .bulk-bar .bulk-done .icon { display: none; }
  .bulk-bar .bulk-done .label { display: inline; }

  .bulk-bar .bulk-acts {
    display: flex; gap: 10px; overflow-x: auto; overscroll-behavior-x: contain;
    scroll-snap-type: x proximity; scroll-padding: 0 var(--gutter-l, 16px);
    padding: 2px var(--gutter-r, 16px) 14px var(--gutter-l, 16px);
    scrollbar-width: none; -webkit-overflow-scrolling: touch;
    -webkit-mask-image: linear-gradient(to right, transparent 0, black 14px, black calc(100% - 28px), transparent 100%);
    mask-image: linear-gradient(to right, transparent 0, black 14px, black calc(100% - 28px), transparent 100%);
  }
  .bulk-bar .bulk-acts::-webkit-scrollbar { display: none; }
  .bulk-bar .bulk-acts > .btn, .bulk-bar .bulk-acts > .icon-btn, .bulk-bar .bulk-acts > .menu-wrap > .icon-btn {
    flex: none; scroll-snap-align: start;
    display: inline-flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px;
    width: auto; min-width: 76px; height: 64px; padding: 0 14px; border-radius: 16px;
    background: color-mix(in srgb, var(--text) 8%, transparent); color: var(--text);
    font-size: 14px; font-weight: 500;
  }
  .bulk-bar .bulk-acts .menu-wrap { flex: none; scroll-snap-align: start; }
  .bulk-bar .bulk-acts .icon { width: 22px; height: 22px; }
  .bulk-bar .bulk-acts .label { display: inline !important; white-space: nowrap; }
  .bulk-bar .bulk-acts .danger { color: var(--danger); }
  .bulk-bar .bulk-acts > .btn:active, .bulk-bar .bulk-acts > .icon-btn:active, .bulk-bar .bulk-acts .menu-wrap > .icon-btn:active {
    transform: scale(0.95); background: color-mix(in srgb, var(--text) 14%, transparent);
  }
}
@media (hover: none) and (pointer: coarse) and (min-width: 700px) {
  .bulk-bar { position: absolute; top: 0; left: 0; right: 0; border-radius: var(--radius-sheet) var(--radius-sheet) 0 0; }
}

/* Auto's tile shows both marks it switches between, as one split tile (SPEC 92) */
.logo-auto { position: relative; display: inline-block; width: 44px; height: 44px; }
.logo-auto img { position: absolute; inset: 0; width: 44px; height: 44px; }
.logo-auto img:first-child { clip-path: inset(0 50% 0 0); }
.logo-auto img:last-child { clip-path: inset(0 0 0 50%); }

/* ==========================================================================
   The selection bar's icons (SPEC 93). Drawn rounder and fuller than the rest,
   in the manner of the system's own symbols; under a mouse they sit in the
   line as before. On a touch screen each action is a coloured disc with its
   symbol in white and its word under it, the colours iOS gives the same
   actions when a message is swiped: Read grey, Unread and the ways back to the
   inbox blue, Archive purple, Delete red, Spam brown, Flag orange, Move teal,
   Restore green.
   ========================================================================== */
.bulk-bar .act-disc { display: inline-flex; align-items: center; justify-content: center; }
.bulk-bar .bulk-act .icon, .bulk-bar .bulk-extra .icon { stroke-width: 1.8; }
.bulk-bar [data-act] { --act: #8E8E93; }
.bulk-bar [data-act="unread"], .bulk-bar [data-act="unarchive"], .bulk-bar [data-act="unspam"] { --act: var(--accent); }
.bulk-bar [data-act="archive"] { --act: #AF52DE; }
.bulk-bar [data-act="delete"], .bulk-bar [data-act="purge"] { --act: #FF3B30; }
.bulk-bar [data-act="spam"] { --act: #A2845E; }
.bulk-bar [data-act="flag"], .bulk-bar [data-act="unflag"] { --act: #FF9500; }
.bulk-bar [data-act="move"] { --act: #32ADE6; }
.bulk-bar [data-act="restore"] { --act: #34C759; }
@media (hover: none) and (pointer: coarse), (max-width: 699px) {
  .bulk-bar .bulk-acts > .btn, .bulk-bar .bulk-acts > .icon-btn, .bulk-bar .bulk-acts > .menu-wrap > .icon-btn {
    height: auto; min-width: 72px; padding: 4px 6px 2px; gap: 7px;
    background: transparent; color: var(--text-2); font-size: 13px; font-weight: 500;
  }
  .bulk-bar .bulk-acts .danger { color: var(--text-2); }
  .bulk-bar .bulk-acts .act-disc {
    width: 48px; height: 48px; border-radius: 50%;
    background: var(--act); color: #fff;
    box-shadow: 0 6px 14px color-mix(in srgb, var(--act) 34%, transparent), inset 0 1px 0 color-mix(in srgb, white 30%, transparent);
    transition: transform var(--t-fast), filter var(--t-fast);
  }
  .bulk-bar .bulk-acts .act-disc .icon { width: 24px; height: 24px; stroke-width: 2; }
  .bulk-bar .bulk-acts > .btn:active, .bulk-bar .bulk-acts > .icon-btn:active, .bulk-bar .bulk-acts .menu-wrap > .icon-btn:active { transform: none; background: transparent; }
  .bulk-bar .bulk-acts > :active .act-disc, .bulk-bar .bulk-acts .menu-wrap > .icon-btn:active .act-disc { transform: scale(0.9); filter: brightness(1.12); }
  .bulk-bar .bulk-acts { gap: 6px; padding-bottom: 12px; }
}

/* Select keeps its colour after a tap: no stuck hover box, no focus ring (SPEC 94) */
@media (hover: none) {
  .list-head .select-btn:hover, .list-head .select-btn:focus { background: transparent; box-shadow: none; outline: none; }
}
@media (max-width: 699px) {
  .list-head .select-btn:hover, .list-head .select-btn:focus { color: var(--accent-text); }
}
@media (hover: none) { .icon-btn.danger:hover { background: transparent; } }

/* The AI notice on a phone (SPEC 95) sits under the top buttons, not over them,
   fits the screen, and goes away with a tap for the rest of the visit. */
@media (max-width: 699px) {
  .status-chip.alert {
    top: calc(var(--safe-top) + var(--bar-drop, 0px) + 56px + 6px);
    max-width: calc(100% - 32px); height: auto; min-height: 30px; padding: 6px 12px;
    white-space: normal; text-align: center; font-size: 14px; cursor: pointer;
    background: color-mix(in srgb, var(--bg) 88%, var(--danger) 12%);
  }
}

/* ==========================================================================
   A phone on its side (SPEC 97). Wider than 700px but under 500px tall, an
   iPhone in landscape gets the iPad's layout with the screen spent even more
   tightly: the list alone across the width, and an open message (or compose)
   alone across the whole screen, under a slim bar that holds only the way
   back. The margins shrink to the safe areas, so the notch is respected and
   nothing else is wasted. Back, or a swipe in from the left edge, gives the
   list back.
   ========================================================================== */
/* compose lives in the message's column, so that column is open while writing, everywhere this layout folds it away */
@media (hover: none) and (pointer: coarse) and (min-width: 700px) {
  .app.composing:not(.reading) .panes { grid-template-columns: var(--list-w) minmax(0, 1fr); column-gap: var(--gap-sheet); }
  .app.composing:not(.reading) .thread-pane { opacity: 1; pointer-events: auto; overflow: hidden; border-width: 1px; }
}
@media (hover: none) and (pointer: coarse) and (min-width: 1100px) {
  .app.composing:not(.reading) .panes { grid-template-columns: var(--sidebar-w) var(--list-w) minmax(0, 1fr); }
}
@media (hover: none) and (pointer: coarse) and (orientation: landscape) and (max-height: 500px) and (min-width: 700px) {
  :root { --topbar-h: 52px; --gap-sheet: 6px; }
  .topbar { height: calc(var(--topbar-h) + var(--safe-top)); }
  .topbar .brand { display: none; }
  .panes { padding: 0 calc(6px + var(--safe-right)) calc(6px + var(--safe-bottom)) calc(6px + var(--safe-left)); }
  .list-head { min-height: 0; padding: 6px 16px 4px; }
  .list-head h2 { font-size: 26px; }
  .list-tabs { padding: 0 16px 8px; }

  /* a message, or compose, has the whole screen */
  .app.app.reading .panes, .app.app.composing .panes { grid-template-columns: 0px minmax(0, 1fr); column-gap: 0; }
  .app.reading .list-pane, .app.composing .list-pane { opacity: 0; pointer-events: none; overflow: hidden; border-width: 0; box-shadow: none; }
  .app.reading .thread-pane, .app.composing .thread-pane { opacity: 1; pointer-events: auto; }
  .app.reading .focus-btn { display: none; }

  /* the bar, slim, with only the way back */
  .app.reading .topbar, .app.composing .topbar { height: calc(46px + var(--safe-top)); }
  .app.reading .topbar > :not(.back-btn), .app.composing .topbar > :not(.back-btn) { display: none; }
  .app.reading .topbar .back-btn, .app.composing .topbar .back-btn {
    display: inline-flex; width: 40px; height: 40px; border-radius: 50%; justify-content: center; align-items: center;
    background: color-mix(in srgb, var(--bg) 84%, var(--text) 16%); color: var(--text);
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.28), 0 1px 3px rgba(0, 0, 0, 0.2);
  }
  .app.reading .topbar .back-btn .icon, .app.composing .topbar .back-btn .icon { width: 21px; height: 21px; }
  .reader-head { padding-top: 10px; }
  .thread-toolbar { height: 52px; }
}

/* ==========================================================================
   A message on a phone on its side, edge to edge (SPEC 98). SPEC 97 gave the
   message the screen but kept a row for Back above it and drew the message
   as a sheet with a rim and margins. Now there is no row above: Back is the
   first button of the message's own bar; the message runs from edge to edge
   with no sheet, rim or radius; only the text keeps clear of the notch and
   the home indicator, through the safe areas.
   ========================================================================== */
.tb-back { display: none; }
@media (hover: none) and (pointer: coarse) and (orientation: landscape) and (max-height: 500px) and (min-width: 700px) {
  .app.reading .topbar { display: none; }
  .app.app.reading .panes { grid-row: 1 / -1; padding: 0; }
  .app.reading .thread-pane { border: 0; border-radius: 0; box-shadow: none; background: var(--bg); }
  .app.reading .thread-toolbar {
    height: 48px; border-radius: 0; border-bottom: 1px solid var(--hair-soft);
    padding: 0 calc(var(--safe-right) + 10px) 0 calc(var(--safe-left) + 6px);
  }
  .app.reading .thread-toolbar .tb-back {
    display: inline-flex; width: 40px; height: 40px; border-radius: 50%; margin-right: 6px;
    background: color-mix(in srgb, var(--text) 10%, transparent); color: var(--text);
  }
  .app.reading .thread-toolbar .tb-back .icon { width: 21px; height: 21px; }
  .app.reading .reader-head { padding: 10px calc(var(--safe-right) + 20px) 2px calc(var(--safe-left) + 20px); }
  .app.reading .reader-head h1 { font-size: 24px; }
  .app.reading .msg-head, .app.reading .msg-enrich, .app.reading .body-tools, .app.reading .attachments,
  .app.reading .msg-fold, .app.reading .msg-newer {
    padding-left: calc(var(--safe-left) + 20px); padding-right: calc(var(--safe-right) + 20px);
  }
  .app.reading .msg-enrich.ai-card { margin-left: calc(var(--safe-left) + 20px); margin-right: calc(var(--safe-right) + 20px); }
  .app.reading .msg-body { padding: 6px var(--safe-right) 6px var(--safe-left); }
  .app.reading .msg-body .frame-scroll, .app.reading .msg-body iframe, .app.reading .msg-body pre.plain {
    border-radius: 0; box-shadow: none; border: 0;
  }
  .app.reading .msg-body .frame-scroll { max-height: none; }
  .app.reading .msg-body iframe { max-height: none; }
  .app.reading .thread-scroll { padding-bottom: var(--safe-bottom); }
}

/* ==========================================================================
   Loading like iOS, and quieter errors (SPEC 99).
   The pull indicator is the system's activity indicator: eight rounded
   spokes on nothing, fading round the circle. As the list is pulled they
   appear one by one (--shown, set from the pull); while the refresh runs the
   wheel turns a spoke at a time. A toast is a small dark glass card with the
   message in the text colour and only its icon in colour.
   ========================================================================== */
.ios-spin { position: relative; display: block; width: 30px; height: 30px; }
.ios-spin i {
  position: absolute; left: calc(50% - 1.5px); top: 1px; width: 3px; height: 8.5px; border-radius: 2px;
  background: currentColor; transform-origin: 1.5px 14px;
  transform: rotate(calc(var(--i) * 45deg));
  opacity: calc((1 - var(--i) * 0.105) * clamp(0, var(--shown, 8) - var(--i), 1));
}
.ptr {
  width: 36px !important; height: 36px !important; border-radius: 50%;
  background: transparent !important; border: 0 !important; box-shadow: none !important;
  color: var(--text-2);
}
.ptr.armed { color: var(--text); }
.ptr.busy .ios-spin { animation: spin 0.8s steps(8, end) infinite; }
@media (max-width: 699px) {
  .ptr { top: calc(var(--safe-top) + var(--bar-drop, 0px) + 50px); }
}

.toast {
  gap: 10px; padding: 11px 12px 11px 14px; border-radius: 16px;
  background: color-mix(in srgb, var(--bg) 86%, var(--text) 14%);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.32), inset 0 1px 0 color-mix(in srgb, white 10%, transparent);
  border: 0; font-size: 14px; font-weight: 500; line-height: 1.3; color: var(--text);
}
.toast.error, .toast.ok { color: var(--text); }
.toast.error > .icon:first-child { color: var(--danger); }
.toast.ok > .icon:first-child { color: var(--ok); }
.toast > button:last-child { opacity: 0.55; margin-left: 2px; }
@media (max-width: 699px) {
  .toast { font-size: 15px; max-width: calc(100vw - 32px); }
}

/* ==========================================================================
   Pull to refresh as a drop (SPEC 101). Pulling the list down from its top
   lets a drop grow from the top edge of the list: a tail that narrows to a
   thread where it hangs, and a round head that holds the spinner's spokes,
   appearing one by one. The list follows the finger at half speed, so the
   drop has the room it grows into. Let go past the point of refresh and the
   drop detaches -- the tail snaps up, the head gives a small bounce -- and
   rests at the top, on the level of the list's title, while the list stays
   held just below it; the spokes turn until the refresh is done, then the
   head shrinks away and the list glides back up. Short of the point, the
   drop draws back up and the list returns.
   ========================================================================== */
@keyframes ptr-pop { 0% { transform: scale(1); } 45% { transform: scale(1.14); } 100% { transform: scale(1); } }
.list-pane > .list-head, .list-pane > .list-tabs, .list-pane > .list { transform: translateY(var(--pull, 0px)); }
.list-pane.ptr-settling > .list-head, .list-pane.ptr-settling > .list-tabs, .list-pane.ptr-settling > .list {
  transition: transform var(--t-push);
}
.ptr {
  position: fixed !important; z-index: 33; width: 0 !important; height: 0 !important;
  transform: none !important; opacity: 0; pointer-events: none; --d: 0px;
  transition: opacity var(--t-fade);
}
.ptr.pulling { transition: none; }
.ptr-head {
  position: absolute; left: -19px; top: calc(var(--d) - 46px); width: 38px; height: 38px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--bg) 80%, var(--text) 20%); color: var(--text-2);
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.28), inset 0 1px 0 color-mix(in srgb, white 16%, transparent);
  transition: top var(--t-push), transform var(--t-fast), opacity var(--t-fade), color var(--t-fast);
}
.ptr-tail {
  position: absolute; left: -10px; top: 0; width: 20px; height: max(0px, calc(var(--d) - 28px));
  background: color-mix(in srgb, var(--bg) 80%, var(--text) 20%);
  clip-path: polygon(38% 0, 62% 0, 100% 100%, 0 100%);
  border-radius: 0 0 10px 10px;
  transition: height var(--t-push), opacity var(--t-fade);
}
.ptr.pulling .ptr-head, .ptr.pulling .ptr-tail { transition: none; }
.ptr.armed .ptr-head { color: var(--text); }
.ptr.busy .ptr-tail { height: 0; opacity: 0; transition: height var(--t-fast), opacity var(--t-fast); }
.ptr.busy .ptr-head { animation: ptr-pop var(--t-push); }
.ptr.busy .ios-spin { animation: spin 0.8s steps(8, end) infinite; }
.ptr.leaving { opacity: 0; }
.ptr.leaving .ptr-head { transform: scale(0.5); }
.ptr.leaving .ptr-tail { height: 0; }
@media (max-width: 699px) { .ptr { top: auto; } }

/* The order of the mailboxes (SPEC 107): arrows in Mailboxes, drag in the sidebar */
.acct-move { display: inline-flex; gap: 2px; margin-right: 4px; }
.acct-move .icon-btn { width: 30px; height: 30px; }
@media (hover: none) and (pointer: coarse) {
  .acct-move .icon-btn { width: 40px; height: 40px; }
}

/* Download all (SPEC 108): the last chip in the row, in the accent */
.att.att-all { color: var(--accent-text); font-weight: 600; }
.att.att-all .size { font-weight: 400; }
.att.att-all.busy { opacity: 0.6; pointer-events: none; }

/* ==========================================================================
   Invite, set out like the rest of Settings (SPEC 111): a card for your own
   link with Share and Copy, then grouped rows -- each link with its count, a
   share button and an on/off switch, a New link row that opens its form in
   place -- and the people who joined. No monospace boxes cut off mid-address.
   ========================================================================== */
.inv-hero { display: flex; flex-direction: column; gap: 10px; padding: 16px; border-radius: 16px; background: var(--accent-bg); margin: 6px 0 4px; }
.inv-hero-top { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.inv-hero-label { font-size: 14px; font-weight: 600; color: var(--text); }
.inv-count { font-size: 13px; color: var(--text-2); font-variant-numeric: tabular-nums; white-space: nowrap; }
.inv-url { font-size: 14px; color: var(--accent-text); overflow-wrap: anywhere; line-height: 1.35; }
.inv-hero-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.inv-hero-actions .btn { height: 40px; justify-content: center; gap: 8px; font-size: 14px; border-radius: 12px; }
.inv-hero-actions .inv-copy { background: var(--bg); color: var(--text); }
.inv-heading { margin: 22px 0 8px; font-size: 13px; font-weight: 600; color: var(--text-2); }
.inv-group { border-radius: 14px; background: color-mix(in srgb, var(--text) 5%, var(--bg)); overflow: hidden; }
.inv-row { display: flex; align-items: center; gap: 10px; min-height: 52px; padding: 8px 12px 8px 16px; width: 100%; text-align: left; color: var(--text); }
.inv-row + .inv-row, .inv-row + .inv-new, .inv-new + .inv-row { border-top: 1px solid var(--hair-soft); }
.inv-row.off .inv-row-main { opacity: 0.55; }
.inv-row-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.inv-row-title { font-size: 15px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.inv-row-sub { font-size: 12.5px; color: var(--text-3); }
.inv-row-copy { width: 40px; height: 40px; color: var(--accent-text); }
.inv-switch { flex: none; }
.inv-add { gap: 10px; color: var(--accent-text); font-size: 15px; font-weight: 500; cursor: pointer; }
.inv-add .icon { color: var(--accent-text); }
.inv-empty { color: var(--text-3); font-size: 14px; }
.inv-new { display: flex; flex-direction: column; gap: 8px; padding: 12px 16px 14px; }
.inv-new .text-input { height: 42px; }
.inv-preview { font-size: 12.5px; color: var(--text-3); overflow-wrap: anywhere; }
.inv-new-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 2px; }
.inv-note { margin: 8px 2px 0; font-size: 12.5px; color: var(--text-3); line-height: 1.45; }
@media (max-width: 699px) {
  .inv-hero-label { font-size: 16px; }
  .inv-url { font-size: 15px; }
  .inv-hero-actions .btn { height: 46px; font-size: 16px; }
  .inv-row { min-height: 58px; }
  .inv-row-title, .inv-add { font-size: 17px; }
  .inv-row-sub { font-size: 14px; }
  .inv-heading { font-size: 14px; }
  .inv-new .text-input { height: 46px; font-size: 17px; }
  .inv-row-copy { width: 44px; height: 44px; }
  /* the tabs: room at both ends, so the first and last are never cut against the edge */
  .settings-nav { scroll-padding-inline: 16px; padding-left: 12px; padding-right: 12px; scrollbar-width: none; }
  .settings-nav::-webkit-scrollbar { display: none; }
}

[hidden] { display: none !important; }
/* SPEC 111: Settings on a phone is a sheet to the bottom of the screen, not a 640px box with a band under it */
@media (max-width: 699px) {
  .modal .modal-card.settings-card { height: 100%; max-height: none; }
}

/* Where notifications go (SPEC 117) */
.push-device-list { list-style: none; margin: 4px 0 12px; padding: 0; display: grid; gap: 6px; }
.push-device-list li { font-size: 0.92em; color: var(--text-2, var(--text)); }

/* ---- security, and work and life (SPEC 118) --------------------------------- */
.wx { display: grid; gap: 12px; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.wx .tile { display: flex; flex-direction: column; gap: 0; }
.wx-eyebrow { margin: 0 0 10px; font-size: 13px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--accent-text); }
.wx h2 { font-size: clamp(26px, 2.5vw, 34px); line-height: 1.08; letter-spacing: -0.03em; text-wrap: balance; }
.wx-lede { margin: 14px 0 0; max-width: 36em; font-size: 16px; line-height: 1.55; color: var(--text-2); }
.wx-list { list-style: none; margin: 24px 0 0; padding: 0; display: flex; flex-direction: column; gap: 14px; }
.wx-list li { position: relative; padding-left: 30px; font-size: 15px; line-height: 1.5; color: var(--text-2); }
.wx-list li::before {
  content: ""; position: absolute; left: 0; top: 3px; width: 18px; height: 18px; border-radius: 50%;
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--accent) 55%, transparent);
}
.wx-list li::after {
  content: ""; position: absolute; left: 6px; top: 7px; width: 6px; height: 9px;
  border: solid var(--accent-text); border-width: 0 2px 2px 0; rotate: 45deg;
}
.wx-list b { color: var(--text); font-weight: 600; }
.wx-sec { background: linear-gradient(160deg, color-mix(in srgb, var(--accent) 9%, var(--sheet-front)) 0%, var(--sheet-front) 60%); }
@media (max-width: 999px) {
  .wx { grid-template-columns: minmax(0, 1fr); }
}

/* ==========================================================================
   SPEC 124: the message as a sheet of paper
   Three layers, each a step lighter and higher: the reader's ground, the
   summary a shade above it, and the sender's page on top like paper on a
   tablet, with a soft shadow under it. In the dark the paper is dimmed a
   little, so a white newsletter no longer glares out of a dark room.
   ========================================================================== */
:root {
  --paper-ring: rgba(16, 24, 40, 0.07);
  --paper-shadow: 0 1px 1px rgba(16, 24, 40, 0.04), 0 10px 24px -10px rgba(16, 24, 40, 0.16), 0 32px 64px -28px rgba(16, 24, 40, 0.22);
  --paper-dim: none;
  --summary-ground: color-mix(in srgb, var(--accent) 4%, var(--bg-2));
  --summary-ring: color-mix(in srgb, var(--accent) 12%, var(--hair-soft));
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper-ring: rgba(255, 255, 255, 0.09);
    --paper-shadow: 0 1px 1px rgba(0, 0, 0, 0.5), 0 14px 30px -12px rgba(0, 0, 0, 0.7), 0 44px 80px -32px rgba(0, 0, 0, 0.8);
    --paper-dim: brightness(0.88) saturate(0.96);
    --summary-ground: color-mix(in srgb, var(--accent) 5%, #1f2127);
    --summary-ring: rgba(255, 255, 255, 0.06);
  }
}
:root[data-theme="dark"] {
  --paper-ring: rgba(255, 255, 255, 0.09);
  --paper-shadow: 0 1px 1px rgba(0, 0, 0, 0.5), 0 14px 30px -12px rgba(0, 0, 0, 0.7), 0 44px 80px -32px rgba(0, 0, 0, 0.8);
  --paper-dim: brightness(0.88) saturate(0.96);
  --summary-ground: color-mix(in srgb, var(--accent) 5%, #1f2127);
  --summary-ring: rgba(255, 255, 255, 0.06);
}
.msg-enrich.ai-card {
  background: var(--summary-ground); border: 0;
  box-shadow: inset 0 0 0 1px var(--summary-ring), var(--sheet-lift);
}
.msg-body { padding-bottom: 26px; }
.msg-body .frame-scroll {
  border-radius: 18px; background: #fff;
  box-shadow: 0 0 0 1px var(--paper-ring), var(--paper-shadow);
}
.msg-body .frame-scroll iframe { border: 0; border-radius: 18px; box-shadow: none; filter: var(--paper-dim); }
.msg-body pre.plain {
  border-radius: 18px; background: var(--sheet-front);
  box-shadow: 0 0 0 1px var(--paper-ring), var(--paper-shadow);
}
/* a rebuilt part of the page does not replay its transitions */
.no-motion, .no-motion * { transition: none !important; animation: none !important; }

/* SPEC 125: in the dark the mail is a dark sheet of its own -- a step lighter than the summary, with an edge and a
   shadow, so the body is plainly the body -- instead of a white page dimmed */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --paper-dim: none; }
}
:root[data-theme="dark"] { --paper-dim: none; }
.msg-body .frame-scroll.dark-mail {
  background: #262626;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.1), var(--paper-shadow);
}

/* SPEC 126: the mail is part of the message, not a box of its own -- full height, and the reader scrolls it */
.msg-body .frame-scroll, .msg-body .frame-scroll.expanded { max-height: none; overflow: hidden; }
.msg-body iframe, .msg-body .frame-scroll iframe { max-height: none; }

/* SPEC 126: the wrapper alone rounds and clips the mail. The frame's own white ground and rounding left a white
   hairline at the corners of a dark mail. */
.msg-body .frame-scroll iframe { border-radius: 0; }
.msg-body .frame-scroll.dark-mail iframe { background: #262626; }

/* SPEC 126: the edge of a dark mail is drawn over the frame's outermost pixels, in the paper's own grey with a faint
   light rim outside it, so no white from inside the frame can ever show along the rounding */
.msg-body .frame-scroll { position: relative; }
.msg-body .frame-scroll.dark-mail::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  box-shadow: inset 0 0 0 2px #262626;
}

/* SPEC 128: the app's own tooltip -- a floating pill in the app's colours, not the browser's grey box */
.vtip {
  position: fixed; z-index: 10000; left: 0; top: 0; pointer-events: none;
  max-width: min(320px, calc(100vw - 12px)); padding: 6px 12px; border-radius: 999px;
  background: var(--tip-bg);
  -webkit-backdrop-filter: blur(14px) saturate(1.4); backdrop-filter: blur(14px) saturate(1.4);
  color: var(--text); font-size: 12.5px; font-weight: 500; line-height: 1.35; white-space: nowrap;
  box-shadow: 0 0 0 1px var(--tip-rim), 0 2px 4px rgba(0, 0, 0, 0.12), 0 10px 26px -8px rgba(0, 0, 0, 0.45);
  opacity: 0; translate: 0 -3px; transition: opacity var(--t-fast), translate var(--t-fast);
}
.vtip.shown { opacity: 1; translate: 0 0; }
.vtip.multi { white-space: pre-line; border-radius: 14px; padding: 8px 12px; }
@media (prefers-reduced-motion: reduce) { .vtip { transition: none; translate: none; } }
:root { --tip-bg: rgba(255, 255, 255, 0.94); --tip-rim: rgba(16, 24, 40, 0.08); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --tip-bg: rgba(52, 54, 62, 0.96); --tip-rim: rgba(255, 255, 255, 0.1); }
}
:root[data-theme="dark"] { --tip-bg: rgba(52, 54, 62, 0.96); --tip-rim: rgba(255, 255, 255, 0.1); }

/* ==========================================================================
   The selection bar under a mouse (SPEC 132): the touch screen's coloured
   actions, brought to the desk. Each action is a soft disc tinted in its own
   colour -- Read grey, Unread blue, Archive purple, Delete red, Spam brown,
   Flag orange, Move teal -- with its symbol at full size in that colour, so
   the row reads at a glance instead of as a line of small grey outlines.
   Where the list is wide enough for words, the disc becomes a pill with the word.
   ========================================================================== */
@media (hover: hover) and (pointer: fine) and (min-width: 700px) {
  .bulk-bar { gap: 6px; }
  .bulk-bar .n { font-size: 14px; }
  .bulk-bar .bulk-act, .bulk-bar .bulk-extra, .bulk-bar .menu-wrap > .bulk-extra {
    height: 34px; min-width: 34px; width: auto; padding: 0; gap: 6px; border-radius: 999px;
    background: color-mix(in srgb, var(--act) 15%, transparent); color: var(--act);
    transition: background var(--t-fast), transform var(--t-fast);
  }
  .bulk-bar .bulk-act:hover, .bulk-bar .bulk-extra:hover {
    background: color-mix(in srgb, var(--act) 26%, transparent); color: var(--act);
  }
  .bulk-bar .bulk-act:active, .bulk-bar .bulk-extra:active { transform: scale(0.94); }
  .bulk-bar .bulk-act.danger, .bulk-bar .bulk-act.danger:hover { color: var(--act); }
  .bulk-bar [data-act="read"] { --act: color-mix(in srgb, var(--text) 70%, #8E8E93); }
  .bulk-bar .act-disc { width: 34px; height: 34px; }
  .bulk-bar .bulk-act .icon, .bulk-bar .bulk-extra .icon { width: 18px; height: 18px; stroke-width: 1.9; }
  .bulk-bar .bulk-act .label { font-size: 13px; font-weight: 600; padding-right: 13px; margin-left: -8px; }
  .bulk-bar .bulk-done { width: 34px; height: 34px; border-radius: 999px; margin-left: 4px; }
  .bulk-bar .bulk-done .icon { width: 18px; height: 18px; }
}
@container list (max-width: 560px) {
  .bulk-bar .bulk-act { width: 34px; }
}

/* ==========================================================================
   An attachment as a small card (SPEC 135): a tile with its type in the type's
   colour, the name shortened in the middle -- its end and extension always
   show -- and the kind and size on a line of their own, never broken.
   ========================================================================== */
.attachments .att:not(.att-all) {
  height: auto; min-height: 48px; padding: 7px 14px 7px 7px; gap: 10px; max-width: 320px;
  border-radius: 12px; align-items: center;
}
.att .att-tile {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 9px;
  font-size: 9.5px; font-weight: 700; letter-spacing: 0.04em;
  --kind: #8E8E93; color: var(--kind); background: color-mix(in srgb, var(--kind) 16%, transparent);
}
.att .att-tile[data-kind="sheet"] { --kind: #1D8A4E; }
.att .att-tile[data-kind="pdf"] { --kind: #E5484D; }
.att .att-tile[data-kind="doc"] { --kind: #2F6FEB; }
.att .att-tile[data-kind="slides"] { --kind: #E8772E; }
.att .att-tile[data-kind="image"] { --kind: #AF52DE; }
.att .att-tile[data-kind="archive"] { --kind: #A2845E; }
.att .att-tile[data-kind="cad"] { --kind: #0F9BA8; }
.att .att-tile[data-kind="mail"] { --kind: var(--accent); }
@media (prefers-color-scheme: dark) { .att .att-tile[data-kind="sheet"] { --kind: #3DBE74; } }
:root[data-theme="dark"] .att .att-tile[data-kind="sheet"] { --kind: #3DBE74; }
.att .att-text { display: flex; flex-direction: column; align-items: flex-start; text-align: left; min-width: 0; gap: 2px; line-height: 1.25; }
.att .att-text .fname { max-width: 100%; }
.att .att-text .fname { display: flex; min-width: 0; font-size: 13px; font-weight: 500; overflow: visible; }
.att .att-text .stem { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.att .att-text .tail { flex: none; white-space: nowrap; }
.att .att-text .size { font-size: 11.5px; white-space: nowrap; }

/* ==========================================================================
   How unread mail stands out (SPEC 140), the user's choice under Appearance.
   Vivid is the look above: a tint, a bar, the dot, a subject and time in the
   mailbox's colour -- four signals, and with Gmail's red it shouted. The
   others step back:
   - quiet (the default): the dot alone carries the colour; unread is bold text
     in the ordinary colours, as in Apple Mail;
   - neutral: the same, with the dot always the app's own blue -- the mailbox's
     colour stays on the frame (selection, Compose);
   - soft: the mailbox's colour everywhere, toned halfway toward grey, with a
     faint wash and no bar.
   ========================================================================== */
:root[data-unread="quiet"] .list .row.unread,
:root[data-unread="neutral"] .list .row.unread { background: transparent; }
:root[data-unread="quiet"] .list .row.unread:hover,
:root[data-unread="neutral"] .list .row.unread:hover { background: var(--hover); }
:root[data-unread="quiet"] .list .row.unread::before,
:root[data-unread="neutral"] .list .row.unread::before,
:root[data-unread="soft"] .list .row.unread::before { display: none; }
:root[data-unread="quiet"] .list .row.unread .subject,
:root[data-unread="neutral"] .list .row.unread .subject,
:root[data-unread="soft"] .list .row.unread .subject { color: var(--text); }
:root[data-unread="quiet"] .list .row.unread .date,
:root[data-unread="neutral"] .list .row.unread .date { color: var(--text-2); }
:root[data-unread="neutral"] .row.unread .unread-dot { background: #1b7cf5; }
:root[data-unread="soft"][data-tint] {
  --accent: color-mix(in srgb, var(--tint) 58%, #8e8e93);
  --accent-text: color-mix(in srgb, color-mix(in srgb, var(--tint) 58%, #8e8e93) 70%, var(--text));
}
:root[data-unread="soft"] .list .row.unread { background: color-mix(in srgb, var(--accent) 3.5%, transparent); }
:root[data-unread="soft"] .list .row.unread:hover { background: color-mix(in srgb, var(--accent) 7%, transparent); }
/* SPEC 142: a chosen or ticked unread row keeps its selection in every unread style */
:root[data-unread] .list .row.selected.unread, :root[data-unread] .list .row.checked.unread,
:root[data-unread] .list .row.selected.unread:hover, :root[data-unread] .list .row.checked.unread:hover { background: var(--sel); }

/* SPEC 143: the smart features' mark -- filled, never outlined; one half takes the text colour around it */
svg.icon.smart-mark { stroke: none; }
svg.icon.smart-mark path { stroke: none; }
.ai-card-label svg.smart-mark, .wd-label svg.smart-mark { color: var(--text); }
.ai-row-mark { display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; flex: none; color: var(--text); }
.ai-row-mark svg.smart-mark { width: 17px; height: 17px; }
.preview-card .card-head .title { display: inline-flex; align-items: center; gap: 6px; }
.status-chip svg.smart-mark { color: var(--text); }

/* ---------------------------------------------------------------- topics (SPEC 152) */

.topic-offer {
  display: flex; align-items: center; gap: 8px; width: calc(100% - 32px); margin: 2px 16px 10px; padding: 9px 12px;
  border-radius: 12px; border: 1px dashed var(--hair); background: transparent; color: var(--text-2);
  font: inherit; font-size: 13px; text-align: left; cursor: pointer; transition: background var(--t-fast), color var(--t-fast);
}
.topic-offer:hover { background: var(--hover); color: var(--text); }
.topic-card { padding: 2px 0 8px; margin-bottom: 4px; }
.topic-card h3 .topic-name { color: var(--text); font-weight: 600; }
.topic-card h3 .topic-count { margin-left: auto; font-weight: 400; }
.topic-kinds { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 16px 8px; }
.topic-item .top .kind { display: inline-flex; align-self: center; color: var(--text-3); }
.topic-item.current { background: var(--accent-bg); }
.topic-more { margin: 8px 16px 0; }
.topic-modal { z-index: 59; align-items: flex-start; padding-top: max(9vh, env(safe-area-inset-top)); }
.topic-modal-card { width: min(720px, 100%); max-height: min(84vh, 100%); }
.topic-title { display: flex; align-items: center; gap: 8px; }
.topic-view .topic-sub { font-size: 12.5px; color: var(--text-3); margin-bottom: 10px; }
.topic-filters { display: flex; flex-direction: column; gap: 8px; margin-bottom: 8px; }
.topic-filters, .topic-people { display: flex; flex-wrap: wrap; gap: 6px; }
.topic-filters { flex-direction: row; }
.topic-people { flex-basis: 100%; }
.topic-chip.on { background: var(--accent-bg); color: var(--accent-text); }
.topic-list { padding: 4px 0 8px; margin: 0 -16px; }
.topic-form { display: flex; flex-direction: column; gap: 6px; }
.topic-form label { font-size: 12px; font-weight: 600; color: var(--text-3); margin-top: 6px; }
.topic-input {
  width: 100%; padding: 9px 12px; border-radius: 10px; border: 1px solid var(--hair); background: var(--bg-2);
  color: var(--text); font: inherit; font-size: 14px; resize: vertical;
}
.topic-input:focus { outline: 0; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-bg); }
.topic-hint { font-size: 12px; color: var(--text-3); }
.topic-preview { margin-top: 8px; padding: 10px 12px; border-radius: 12px; background: var(--bg-2); border: 1px solid var(--hair-soft); min-height: 44px; }
.topic-preview-count { font-size: 13px; font-weight: 600; margin-bottom: 6px; }
.topic-preview-row { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--text-2); padding: 2px 0; }
.topic-preview-row span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.topic-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 12px; }
@media (max-width: 720px) {
  .topic-modal { padding-top: 0; align-items: stretch; }
  .topic-modal-card { max-height: 100%; border-radius: 0; }
}
.topic-item.mention { opacity: 0.62; }
.topic-item.mention:hover { opacity: 1; }
.topic-foot { display: flex; align-items: center; gap: 8px; margin: 8px 16px 0; }
.topic-foot .topic-more { margin: 0; }
.topic-foot .topic-keep { margin-left: auto; }
.topic-suggested { font-weight: 500; }
.topic-card.suggested { border-left: 2px solid var(--accent); }

/* ---------------------------------------------------------------- thread sense (SPEC 154) */

.sense-people { padding-bottom: 6px; }
.person { padding: 6px 16px; }
.person-top { display: flex; align-items: baseline; gap: 8px; }
.person-name { font-size: 13px; font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.person-side { font-size: 10.5px; padding: 0 6px; height: 17px; line-height: 17px; }
.person-count { margin-left: auto; font-size: 11.5px; color: var(--text-3); white-space: nowrap; }
.person-role { font-size: 12px; color: var(--text-2); margin-top: 1px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.person.internal .person-name { font-weight: 500; color: var(--text-2); }
.sense-flow { margin: 6px 16px 2px; padding-top: 6px; border-top: 1px solid var(--hair-soft); font-size: 12px; color: var(--text-3); }
.sense-flow div { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 1px 0; }
.sense-connected { padding-top: 4px; }

/* The blue buttons -- Compose, Thread, Send -- are one control in three places (SPEC 155): one height,
   one shape, one type size, one paint and one shadow, and the same 18px from the edge of the sheet
   they stand in, so the eye finds them the same way each time. */
@media (min-width: 700px) {
  .app {
    --pb-h: 36px;
    --pb-bg: linear-gradient(180deg, color-mix(in srgb, var(--accent) 76%, white) 0%, color-mix(in srgb, var(--accent) 88%, black) 100%);
    --pb-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.38), 0 2px 8px color-mix(in srgb, var(--accent) 32%, transparent);
    --edge: 18px;
  }
  :root .app .btn.primary, :root .app .thread-toolbar .thread-btn {
    height: var(--pb-h); padding: 0 18px; gap: 8px; justify-content: center;
    border-radius: 999px; border: 0;
    background: var(--pb-bg); color: #fff;
    font-size: 14px; font-weight: 600; letter-spacing: -0.005em;
    box-shadow: var(--pb-shadow);
  }
  :root .app .thread-toolbar .thread-btn { width: auto; padding: 0 14px; }
  :root .app .thread-toolbar .thread-btn.active { box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, 0.55), 0 2px 8px color-mix(in srgb, var(--accent) 32%, transparent); }
  #composeSend { min-width: 96px; }
  /* the search pill beside Compose: the same height and type size, the same pill, the same 14px */
  .topbar .search { height: var(--pb-h); padding: 0 16px; gap: 10px; }
  .topbar .search input { font-size: 14px; }
  .topbar .search .kbd { line-height: 18px; }
  .sheet-foot { gap: 6px; padding-left: var(--edge); padding-right: var(--edge); }
  .sheet-foot #composeSend { margin-right: 6px; }
  .sheet-foot #composeDiscard { height: var(--pb-h); padding: 0 14px; font-size: 14px; }
  /* the same edge on the toolbar above the message, so Thread and Reply stand where Send does */
  .thread-toolbar { padding-left: calc(var(--edge) - 8px); padding-right: var(--edge); }
}


/* ---- sign-up confirmation, legal pages, the map that waits to be asked for (SPEC 155) ---------------- */
.accept-row { display: flex; align-items: flex-start; gap: 10px; margin: 4px 0 2px; font-size: 13px; line-height: 1.45; color: var(--text-2); text-align: left; cursor: pointer; }
.accept-row input { flex: none; width: 18px; height: 18px; margin: 1px 0 0; accent-color: var(--accent); }
.accept-row a { color: var(--accent-text); text-decoration: underline; text-underline-offset: 2px; }
.accept-row.hidden { display: none; }
.login-legal, .w-legal { font-size: 12px; color: var(--text-3); }
.login-legal { margin: 0; text-align: center; }
.login-legal a, .w-legal a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.login-legal a:hover, .w-legal a:hover { color: var(--accent-text); }
.w-legal { display: block; margin-top: 8px; }
.mc-map-ask { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; text-align: center; padding: 16px;
  background: var(--bg-3); border-radius: 12px; }
.mc-map-note { font-size: 11.5px; color: var(--text-3); max-width: 28ch; }

.legal { max-width: 680px; margin: 0 auto; padding: calc(36px + var(--safe-top)) 20px calc(64px + var(--safe-bottom)); color: var(--text); }
.legal-brand { display: inline-flex; align-items: center; gap: 10px; font-weight: 600; font-size: 17px; letter-spacing: -0.02em; color: var(--text); text-decoration: none; margin-bottom: 28px; }
.legal-brand img { border-radius: 8px; }
.legal h1 { font-size: 32px; line-height: 1.15; letter-spacing: -0.03em; margin: 0 0 6px; text-wrap: balance; }
.legal h2 { font-size: 17px; letter-spacing: -0.01em; margin: 30px 0 6px; }
.legal p, .legal li { font-size: 15px; line-height: 1.65; color: var(--text-2); }
.legal p { margin: 0 0 12px; }
.legal ul { margin: 0 0 12px; padding-left: 20px; }
.legal li { margin-bottom: 6px; }
.legal li b { color: var(--text); font-weight: 600; }
.legal a { color: var(--accent-text); text-underline-offset: 2px; }
.legal-meta { font-size: 13px !important; color: var(--text-3) !important; margin-bottom: 22px !important; }

/* ---- the mobile number, confirmed by text message (SPEC 156) ---------------------------------------- */
.phone-step { text-align: left; }
.phone-line { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; align-items: center; }
.phone-line.hidden { display: none; }
.phone-step .form-hint.bad { color: var(--danger); }
.phone-step.done .form-hint { color: var(--ok, var(--text-2)); }
.phone-step.done input { opacity: 0.75; }
.phone-slot { display: grid; gap: 4px; }
.phone-slot.hidden { display: none; }
.phone-slot .form-label { font-size: 12px; color: var(--text-2); }
.phone-slot .form-hint { font-size: 11.5px; color: var(--text-3); }
