/*
 * Application styles.
 *
 * Everything here is written against the tokens in tokens.css; no colour or
 * spacing value is hardcoded below. The layout is a three-column shell —
 * sidebar, list, reading pane — that collapses to one column on a narrow
 * screen, which is the same structure a mail client has had for thirty years
 * because it is the one that works.
 */

@import url("tokens.css");

/* ---------------------------------------------------------------- reset */

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

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100vh;
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  color: var(--colour-text);
  background: var(--colour-surface-sunken);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, h5, h6 {
  margin: 0;
  font-weight: var(--weight-semibold);
  line-height: var(--leading-tight);
}

p { margin: 0 0 var(--space-3); }
p:last-child { margin-bottom: 0; }

a {
  color: var(--colour-accent-text);
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}

img { max-width: 100%; height: auto; }

/* The hidden attribute must beat any class that sets display.
   The browser's own [hidden] { display: none } is a single attribute selector,
   so any class rule with a display property silently overrides it — which is
   how .compose, .badge and .button all ended up permanently visible despite
   carrying the attribute. Making it authoritative here means the bug cannot
   come back the next time a component sets display. */
[hidden] {
  display: none !important;
}

/* A visible focus ring on every interactive element, never removed. It is the
   only way a keyboard user can tell where they are. */
:focus-visible {
  outline: 2px solid var(--colour-focus);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ------------------------------------------------------------- utilities */

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

.skip-link {
  position: absolute;
  top: var(--space-2);
  left: var(--space-2);
  z-index: 100;
  padding: var(--space-2) var(--space-4);
  background: var(--colour-accent);
  color: var(--colour-text-inverse);
  border-radius: var(--radius-md);
  transform: translateY(-200%);
  transition: transform var(--transition-base);
}

.skip-link:focus { transform: translateY(0); }

.truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.stack > * + * { margin-top: var(--space-3); }

/* Small layout helpers, alongside .truncate and .stack above.
   They exist because the content security policy forbids style attributes
   outright — a blocked attribute is not a slightly-off layout, it is no layout
   at all — so the handful of one-off tweaks the templates used to carry
   inline live here instead. */
.row            { display: flex; align-items: center; gap: var(--space-2); }
.row--wide      { gap: var(--space-3); }
.row--tight     { gap: 2px; }
.row--spaced    { margin-bottom: var(--space-3); }
.actions        { display: flex; gap: var(--space-2); }
.text-muted     { color: var(--colour-text-muted); }
.text-subtle    { color: var(--colour-text-subtle); }
.text-centre    { text-align: center; }
.full-width     { width: 100%; }
.push-right     { margin-right: auto; }
.spaced-top     { margin-top: var(--space-2); }
.spaced-top--wide { margin-top: var(--space-3); }
.prewrap        { white-space: pre-wrap; }
.square         { border-radius: 0; }
.width-auto     { width: auto; }
.clickable      { cursor: pointer; }
.as-block       { display: block; }
.inset          { margin: 0 var(--space-4) var(--space-3); }
.swatch         { width: 3rem; padding: 2px; }
.bare-fieldset  { border: 0; padding: 0; margin: 0; }
.hint-list {
  margin: 0;
  padding-left: var(--space-4);
  font-size: var(--text-sm);
  color: var(--colour-text-muted);
}


/* --------------------------------------------------------------- buttons */

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: 0.5rem var(--space-4);
  font: inherit;
  font-weight: var(--weight-medium);
  color: var(--colour-text);
  background: var(--colour-surface-raised);
  border: 1px solid var(--colour-border);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: background var(--transition-fast), border-color var(--transition-fast);
  /* Touch targets stay at least 40px tall so they are usable on a phone. */
  min-height: 2.5rem;
}

.button:hover { background: var(--colour-surface-hover); }
.button:active { background: var(--colour-surface-active); }

.button[disabled],
.button[aria-disabled="true"] {
  opacity: 0.55;
  cursor: not-allowed;
}

.button--primary {
  color: var(--colour-text-inverse);
  background: var(--colour-accent);
  border-color: var(--colour-accent);
}

.button--primary:hover { background: var(--colour-accent-strong); border-color: var(--colour-accent-strong); }

.button--ghost { background: transparent; border-color: transparent; }
.button--ghost:hover { background: var(--colour-surface-hover); }

.button--danger { color: var(--colour-danger); border-color: var(--colour-border); }
.button--danger:hover { background: var(--colour-danger-soft); }

.button--icon {
  padding: var(--space-2);
  min-width: 2.5rem;
  border-radius: var(--radius-full);
}

.button--block { width: 100%; }

/* ---------------------------------------------------------------- forms */

.field { display: flex; flex-direction: column; gap: var(--space-1); }

.field__label {
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--colour-text-muted);
}

.field__hint {
  font-size: var(--text-xs);
  color: var(--colour-text-subtle);
}

.field__error {
  font-size: var(--text-xs);
  color: var(--colour-danger);
}

.input,
.select,
.textarea {
  width: 100%;
  padding: 0.5rem var(--space-3);
  font: inherit;
  color: var(--colour-text);
  background: var(--colour-surface-raised);
  border: 1px solid var(--colour-border-strong);
  border-radius: var(--radius-md);
  min-height: 2.5rem;
}

.input:focus,
.select:focus,
.textarea:focus {
  border-color: var(--colour-accent);
  outline: 2px solid var(--colour-focus);
  outline-offset: -1px;
}

.input[aria-invalid="true"] { border-color: var(--colour-danger); }

.textarea { min-height: 8rem; resize: vertical; line-height: var(--leading-relaxed); }

.checkbox { display: flex; align-items: center; gap: var(--space-2); cursor: pointer; }
.checkbox input { width: 1.05rem; height: 1.05rem; accent-color: var(--colour-accent); }

.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: var(--space-4);
}

/* --------------------------------------------------------------- alerts */

.alert {
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  border: 1px solid transparent;
  font-size: var(--text-sm);
}

.alert--error { background: var(--colour-danger-soft); border-color: var(--colour-danger); color: var(--colour-text); }
.alert--success { background: var(--colour-success-soft); border-color: var(--colour-success); }
.alert--warning { background: var(--colour-warning-soft); border-color: var(--colour-warning); }
.alert--info { background: var(--colour-accent-soft); border-color: var(--colour-accent); }

/* ------------------------------------------------------------ app shell */

.shell {
  display: grid;
  grid-template-columns: var(--sidebar-width) 1fr;
  grid-template-rows: var(--header-height) 1fr;
  grid-template-areas:
    "header header"
    "sidebar main";
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
}

/*
 * Wide screens keep the sidebar in the grid and the header's menu button
 * collapses it; below the breakpoint the same button slides it in as an
 * overlay instead (see the responsive section).
 */
@media (min-width: 60.0625rem) {
  .shell[data-sidebar="closed"] { grid-template-columns: 0 1fr; }
  .shell[data-sidebar="closed"] .sidebar { display: none; }
}

.header {
  grid-area: header;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: 0 var(--space-4);
  background: var(--colour-surface-raised);
  border-bottom: 1px solid var(--colour-border);
}

.header__brand {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
  color: var(--colour-text);
  text-decoration: none;
  flex-shrink: 0;
}

.header__logo { width: 1.5rem; height: 1.5rem; color: var(--colour-accent); }

.header__search { flex: 1; max-width: 42rem; position: relative; }

.header__actions { display: flex; align-items: center; gap: var(--space-1); margin-left: auto; }

/* The notification count is positioned against this wrapper, so the wrapper
   has to be the badge's containing block. It cannot be an inline style: the
   application's CSP has no 'unsafe-inline' in style-src, so a style attribute
   in the markup is dropped and the badge would escape to the page corner. */
.header__notifications { position: relative; display: flex; }

.sidebar {
  grid-area: sidebar;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-3);
  background: var(--colour-surface-raised);
  border-right: 1px solid var(--colour-border);
  overflow-y: auto;
}

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

.sidebar__heading {
  padding: var(--space-2) var(--space-3) var(--space-1);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--colour-text-subtle);
}

.sidebar__link {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-full);
  color: var(--colour-text);
  text-decoration: none;
  font-size: var(--text-base);
  transition: background var(--transition-fast);
}

.sidebar__link:hover { background: var(--colour-surface-hover); }

.sidebar__link[aria-current="page"] {
  background: var(--colour-accent-soft);
  color: var(--colour-accent-text);
  font-weight: var(--weight-medium);
}

.sidebar__icon { width: 1.15rem; height: 1.15rem; flex-shrink: 0; }
.sidebar__label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.sidebar__count {
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  color: var(--colour-text-muted);
}

.sidebar__dot { width: 0.6rem; height: 0.6rem; border-radius: var(--radius-full); flex-shrink: 0; }

/* The hide button of a sidebar folder — the same reveal-on-hover treatment as
   the read/unread control on a message row, so a list of a dozen folders is
   not a dozen visible dismiss buttons at once, but a keyboard user can still
   always tab to it. */
.sidebar__hide {
  border: 0;
  background: none;
  padding: 2px;
  border-radius: var(--radius-full);
  color: var(--colour-text-subtle);
  cursor: pointer;
  flex-shrink: 0;
  opacity: 0;
}

.sidebar__link:hover .sidebar__hide,
.sidebar__hide:focus-visible { opacity: 1; }
.sidebar__hide:hover { background: var(--colour-surface-active); color: var(--colour-text); }

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

.main { grid-area: main; overflow: hidden; display: flex; }

/* ------------------------------------------------------------ mail view */

.mail {
  display: grid;
  grid-template-columns: var(--list-width) 1fr;
  width: 100%;
  overflow: hidden;
}

.mail__list {
  display: flex;
  flex-direction: column;
  min-height: 0;
  border-right: 1px solid var(--colour-border);
  background: var(--colour-surface-raised);
  overflow: hidden;
}

.mail__toolbar {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--colour-border);
  min-height: 3rem;
}

/* A little daylight between the refresh icon and the mark-all pair, so the
   toolbar reads as two related but distinct groups rather than one row of
   unrelated buttons. */
.markall { margin-left: var(--space-2); }

/* The bulk-trash form wraps the bulk bar and the scrollable list, so it sits
   between .mail__list and .mail__scroll in the flex chain — without its own
   flex sizing here, it takes its default auto size (all the rows stacked)
   instead of passing the available height down to .mail__scroll. */
.mail__list > form {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}

.mail__scroll { overflow-y: auto; flex: 1; min-height: 0; }

.thread-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: var(--row-gap);
  align-items: start;
  padding: var(--row-padding-block) var(--space-3);
  border-bottom: 1px solid var(--colour-border);
  cursor: pointer;
  text-decoration: none;
  color: inherit;
  transition: background var(--transition-fast);
}

.thread-row:hover { background: var(--colour-surface-hover); }
.thread-row[aria-current="true"] { background: var(--colour-surface-selected); }

.thread-row--unread .thread-row__from,
.thread-row--unread .thread-row__subject { font-weight: var(--weight-semibold); }

.thread-row--unread { border-left: 3px solid var(--colour-accent); padding-left: calc(var(--space-3) - 3px); }

.thread-row__controls {
  display: flex;
  align-items: center;
  gap: var(--space-1);
}

.thread-row__select {
  width: 1rem;
  height: 1rem;
  margin: 0;
  cursor: pointer;
  flex-shrink: 0;
  /* Hidden until the row is hovered or the box itself holds focus or is
     checked, the same rule the per-row read/unread control already uses —
     a list of fifty conversations should not be fifty visible checkboxes at
     once, but a keyboard user must always be able to reach it. */
  opacity: 0;
}

.thread-row:hover .thread-row__select,
.thread-row__select:focus-visible,
.thread-row__select:checked { opacity: 1; }

@media (hover: none) {
  .thread-row__select { opacity: 1; }
}

.thread-row.is-selected { background: var(--colour-surface-selected); }

.thread-row__star { background: none; border: 0; padding: 2px; cursor: pointer; color: var(--colour-text-subtle); }
.thread-row__star[aria-pressed="true"] { color: var(--colour-warning); }

.thread-row__body { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.thread-row__from { font-size: var(--text-base); }
.thread-row__subject { font-size: var(--text-sm); }
.thread-row__snippet { font-size: var(--text-sm); color: var(--colour-text-subtle); }

.thread-row__meta {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--space-1);
  font-size: var(--text-xs);
  color: var(--colour-text-subtle);
  white-space: nowrap;
}

.thread-row__count {
  padding: 0 0.35rem;
  border-radius: var(--radius-full);
  background: var(--colour-surface-active);
  font-size: var(--text-xs);
}

.mail__reader { overflow-y: auto; background: var(--colour-surface); }

.reader { max-width: var(--content-max); margin: 0 auto; padding: var(--space-5) var(--space-5) var(--space-7); }

.reader__subject { font-size: var(--text-2xl); margin-bottom: var(--space-4); }

.message {
  border: 1px solid var(--colour-border);
  border-radius: var(--radius-lg);
  background: var(--colour-surface-raised);
  margin-bottom: var(--space-4);
  overflow: hidden;
}

.message__header {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-4);
  cursor: pointer;
  width: 100%;
  background: none;
  border: 0;
  text-align: left;
  font: inherit;
  color: inherit;
}

.avatar {
  display: grid;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  flex-shrink: 0;
  border-radius: var(--radius-full);
  background: var(--colour-accent-soft);
  color: var(--colour-accent-text);
  font-weight: var(--weight-semibold);
  font-size: var(--text-sm);
}

.message__meta { flex: 1; min-width: 0; }
.message__from { font-weight: var(--weight-medium); }
.message__recipients { font-size: var(--text-sm); color: var(--colour-text-subtle); }
.message__date { font-size: var(--text-xs); color: var(--colour-text-subtle); white-space: nowrap; }

.message__body {
  padding: 0 var(--space-4) var(--space-4);
  line-height: var(--leading-relaxed);
  overflow-wrap: anywhere;
}

/* An email body is untrusted markup, so tables inside it get their own scroll
   container rather than being allowed to widen the page. */
.message__body table { display: block; overflow-x: auto; max-width: 100%; }
.message__body img { max-width: 100%; height: auto; }

.message__body .mail-quote {
  margin: var(--space-3) 0;
  padding-left: var(--space-3);
  border-left: 2px solid var(--colour-border-strong);
  color: var(--colour-text-muted);
}

.mail-plain { white-space: normal; }

.message__actions { display: flex; gap: var(--space-2); padding: 0 var(--space-4) var(--space-4); flex-wrap: wrap; }

.attachments { display: flex; flex-wrap: wrap; gap: var(--space-2); padding: 0 var(--space-4) var(--space-4); }

.attachment {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--colour-border);
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
  text-decoration: none;
  color: var(--colour-text);
  background: var(--colour-surface);
}

.attachment:hover { background: var(--colour-surface-hover); }
.attachment__size { color: var(--colour-text-subtle); font-size: var(--text-xs); }

/* ----------------------------------------------------------- empty state */

.empty {
  display: grid;
  place-content: center;
  justify-items: center;
  gap: var(--space-3);
  height: 100%;
  padding: var(--space-6);
  text-align: center;
  color: var(--colour-text-muted);
}

.empty__icon { width: 3rem; height: 3rem; color: var(--colour-text-subtle); }
.empty__title { font-size: var(--text-lg); color: var(--colour-text); }

/* -------------------------------------------------------------- compose */

.compose {
  position: fixed;
  right: var(--space-5);
  bottom: 0;
  z-index: 40;
  width: min(38rem, calc(100vw - var(--space-6)));
  display: flex;
  flex-direction: column;
  background: var(--colour-surface-raised);
  border: 1px solid var(--colour-border);
  border-bottom: 0;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  box-shadow: var(--shadow-lg);
  max-height: min(40rem, 85vh);
}

.compose__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  background: var(--colour-surface-sunken);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  border-bottom: 1px solid var(--colour-border);
  font-weight: var(--weight-medium);
}

.compose__fields { display: flex; flex-direction: column; overflow-y: auto; flex: 1; }

.compose__row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  border-bottom: 1px solid var(--colour-border);
}

.compose__row label { font-size: var(--text-sm); color: var(--colour-text-subtle); min-width: 2.5rem; }

.compose__row input {
  flex: 1;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  padding: var(--space-1) 0;
  min-height: 2rem;
}

.compose__row input:focus { outline: none; }

.compose__body {
  flex: 1;
  border: 0;
  padding: var(--space-4);
  font: inherit;
  line-height: var(--leading-relaxed);
  background: none;
  color: inherit;
  resize: none;
  min-height: 10rem;
}

.compose__body:focus { outline: none; }

.compose__footer {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  border-top: 1px solid var(--colour-border);
}

.compose__row--attachments { flex-direction: column; align-items: stretch; gap: var(--space-2); }

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

.compose__attachment {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  font-size: var(--text-sm);
  padding: var(--space-1) var(--space-2);
  background: var(--colour-surface-sunken);
  border-radius: var(--radius-md);
}

/* --------------------------------------------------------------- dialog */

.dialog {
  border: 1px solid var(--colour-border);
  border-radius: var(--radius-lg);
  background: var(--colour-surface-raised);
  color: var(--colour-text);
  box-shadow: var(--shadow-lg);
  padding: 0;
  max-width: min(34rem, calc(100vw - var(--space-6)));
  width: 100%;
}

.dialog::backdrop { background: var(--colour-overlay); }

.dialog__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-4);
  border-bottom: 1px solid var(--colour-border);
}

.dialog__body { padding: var(--space-4); max-height: 60vh; overflow-y: auto; }
.dialog__footer { display: flex; justify-content: flex-end; gap: var(--space-2); padding: var(--space-4); border-top: 1px solid var(--colour-border); }

/* ------------------------------------------------------------ auth page */

.auth {
  display: grid;
  place-items: center;
  min-height: 100vh;
  min-height: 100dvh;
  padding: var(--space-4);
  background: var(--colour-surface-sunken);
}

.auth__card {
  width: 100%;
  max-width: 26rem;
  padding: var(--space-6);
  background: var(--colour-surface-raised);
  border: 1px solid var(--colour-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
}

.auth__brand { display: flex; align-items: center; gap: var(--space-2); justify-content: center; margin-bottom: var(--space-2); }
.auth__title { text-align: center; font-size: var(--text-xl); margin-bottom: var(--space-5); }
.auth__hint { text-align: center; font-size: var(--text-sm); color: var(--colour-text-muted); margin-bottom: var(--space-4); }
.auth__form { display: flex; flex-direction: column; gap: var(--space-4); }
.auth__footer { margin-top: var(--space-4); text-align: center; font-size: var(--text-sm); color: var(--colour-text-muted); }

/* A long-form document (privacy policy, terms) reads badly in the narrow
   login card, so it opts into the wider measure content already uses for a
   reading pane — the auth shell still centres and scrolls it the same way. */
.auth:has(.legal) .auth__card { max-width: var(--content-max); text-align: left; }

.legal h1 { font-size: var(--text-2xl); margin-bottom: var(--space-1); }
.legal .auth__hint { text-align: left; margin-bottom: var(--space-6); }
.legal h2 { font-size: var(--text-lg); margin: var(--space-6) 0 var(--space-2); }
.legal p { margin-bottom: var(--space-3); }
.legal ul { margin: 0 0 var(--space-3); padding-left: var(--space-5); }
.legal li { margin-bottom: var(--space-1); }
.legal a { color: var(--colour-accent); }

/* ------------------------------------------------------------- settings */

.settings { display: grid; grid-template-columns: 14rem 1fr; width: 100%; overflow: hidden; }
.settings__nav { border-right: 1px solid var(--colour-border); background: var(--colour-surface-raised); padding: var(--space-4) var(--space-2); overflow-y: auto; }
.settings__panel { overflow-y: auto; padding: var(--space-5); }
.settings__inner { max-width: 48rem; margin: 0 auto; display: flex; flex-direction: column; gap: var(--space-5); }

.card {
  background: var(--colour-surface-raised);
  border: 1px solid var(--colour-border);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
}

.card__title { font-size: var(--text-md); margin-bottom: var(--space-1); }
.card__description { font-size: var(--text-sm); color: var(--colour-text-muted); margin-bottom: var(--space-4); }

.settings__subheading {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--colour-text-muted);
  margin: var(--space-4) 0 var(--space-1);
}

.settings__subheading:first-of-type { margin-top: 0; }

.status {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0.125rem var(--space-2);
  border-radius: var(--radius-full);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
}

.status--ok { background: var(--colour-success-soft); color: var(--colour-success); }
.status--error { background: var(--colour-danger-soft); color: var(--colour-danger); }
.status--warning { background: var(--colour-warning-soft); color: var(--colour-warning); }
.status--neutral { background: var(--colour-surface-active); color: var(--colour-text-muted); }

.account-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--colour-border);
}

.account-row:last-child { border-bottom: 0; }
.account-row__body { flex: 1; min-width: 0; }
.account-row__title { font-weight: var(--weight-medium); }
.account-row__meta { font-size: var(--text-sm); color: var(--colour-text-subtle); }
.account-row__import { display: flex; align-items: center; gap: var(--space-2); }
.account-row__import input[type="file"] { max-width: 12rem; font-size: var(--text-sm); }
.strikethrough { text-decoration: line-through; color: var(--colour-text-subtle); }

/* ------------------------------------------------------------- calendar */

.calendar { display: flex; flex-direction: column; width: 100%; overflow: hidden; }

.calendar__toolbar {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--colour-border);
  background: var(--colour-surface-raised);
  flex-wrap: wrap;
}

.calendar__title { font-size: var(--text-lg); margin-right: auto; }

.calendar__grid {
  flex: 1;
  overflow: auto;
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  background: var(--colour-surface-raised);
}

.calendar__weekday {
  padding: var(--space-2);
  text-align: center;
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--colour-text-subtle);
  border-bottom: 1px solid var(--colour-border);
  position: sticky;
  top: 0;
  background: var(--colour-surface-raised);
  z-index: 1;
}

.calendar__day {
  min-height: 6.5rem;
  padding: var(--space-1);
  border-right: 1px solid var(--colour-border);
  border-bottom: 1px solid var(--colour-border);
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.calendar__day--outside { background: var(--colour-surface-sunken); color: var(--colour-text-subtle); }
.calendar__day--today .calendar__daynumber { background: var(--colour-accent); color: var(--colour-text-inverse); }

.calendar__daynumber {
  align-self: flex-start;
  display: grid;
  place-items: center;
  min-width: 1.6rem;
  height: 1.6rem;
  padding: 0 0.35rem;
  border-radius: var(--radius-full);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
}

.event-chip {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px var(--space-2);
  border-radius: var(--radius-sm);
  font-size: var(--text-xs);
  background: var(--colour-surface-hover);
  color: inherit;
  text-decoration: none;
  cursor: pointer;
  border: 0;
  text-align: left;
  width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.event-chip:hover { background: var(--colour-surface-active); }
.event-chip__dot { width: 0.5rem; height: 0.5rem; border-radius: var(--radius-full); flex-shrink: 0; }
.event-chip__time { color: var(--colour-text-subtle); font-variant-numeric: tabular-nums; }

/* The count that stands in for a day's tasks in the month grid. It is
   deliberately not an .event-chip: a cell mixing appointments and tasks has to
   read as two different things at a glance, not as one list with an odd row. */
.task-count {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  margin-top: 2px;
  padding: 2px var(--space-2);
  border: 1px dashed var(--colour-border-strong);
  border-radius: var(--radius-sm);
  background: none;
  color: var(--colour-text-muted);
  font-size: var(--text-xs);
  cursor: pointer;
  text-align: left;
  width: 100%;
  min-width: 0;
}

.task-count:hover {
  background: var(--colour-surface-hover);
  color: var(--colour-text);
}

.task-count__icon { width: 0.85rem; height: 0.85rem; flex-shrink: 0; }
.task-count__number { font-weight: var(--weight-semibold); font-variant-numeric: tabular-nums; }

/* One task inside the dialog the count opens. */
.task-row {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  width: 100%;
  padding: var(--space-2);
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: inherit;
  font-size: var(--text-sm);
  text-align: left;
  cursor: pointer;
}

.task-row:hover { background: var(--colour-surface-hover); }

.agenda__day .task-count { margin-top: var(--space-2); padding: var(--space-2); }
.task-row .event-chip__dot { margin-top: 0.4rem; }

/* ---------------------------------------------------------- week grid --- */

/* The week and day views share one layout: a fixed gutter for the hour labels
   and one equal column per day. The hour axis is a stack of one-hour cells
   rather than a background gradient, because a cell can be a drop target and a
   gradient cannot. */
.weekgrid {
  --weekgrid-gutter: 3.5rem;
  --weekgrid-hour: 3rem;
  --weekgrid-height: calc(var(--weekgrid-hour) * 24);
  --weekgrid-days: 7;
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  overflow: hidden;
}

.weekgrid__head,
.weekgrid__allday {
  display: grid;
  grid-template-columns: var(--weekgrid-gutter) repeat(var(--weekgrid-days, 7), minmax(0, 1fr));
  border-bottom: 1px solid var(--colour-border);
}

.weekgrid__head { position: sticky; top: 0; z-index: 2; background: var(--colour-surface); }

.weekgrid__heading {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 0.35rem;
  padding: var(--space-2);
  border-left: 1px solid var(--colour-border);
  font-size: var(--text-xs);
  color: var(--colour-text-muted);
}

.weekgrid__daynumber { font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--colour-text); }
.weekgrid__heading--today .weekgrid__daynumber { color: var(--colour-accent); }

.weekgrid__allday { min-height: 2.25rem; max-height: 7rem; overflow-y: auto; }

.weekgrid__alldaycell {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 2px;
  border-left: 1px solid var(--colour-border);
  min-width: 0;
}

.weekgrid__gutter {
  padding: var(--space-1);
  font-size: var(--text-xs);
  color: var(--colour-text-subtle);
  text-align: right;
}

.weekgrid__body {
  display: grid;
  grid-template-columns: var(--weekgrid-gutter) repeat(var(--weekgrid-days, 7), minmax(0, 1fr));
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  /* Without this the single auto row stretches to fill a tall viewport. */
  align-content: start;
}

/* The axis is exactly twenty-four hours tall, stated rather than inferred.
   A grid row is sized by its content and then stretched to whatever space is
   going, so on a screen taller than 24 × 3rem the column grew while the hour
   cells inside it did not — and the events, placed at a percentage of the
   column, drifted an hour clear of the line they belonged on. Pinning the
   height is what makes a percentage and an hour mean the same thing. */
.weekgrid__hours,
.weekgrid__column { height: var(--weekgrid-height); }

.weekgrid__hours { padding: 0; }

.weekgrid__hour {
  height: var(--weekgrid-hour);
  position: relative;
  padding-right: var(--space-2);
}

/* The label sits astride the line it names rather than inside the hour below
   it, which is how every calendar draws an hour axis. */
.weekgrid__hour span {
  position: absolute;
  top: -0.5em;
  right: var(--space-2);
  background: var(--colour-surface);
  padding: 0 0.2rem;
}

.weekgrid__hour:first-child span { top: 0; }

.weekgrid__column {
  position: relative;
  border-left: 1px solid var(--colour-border);
  min-width: 0;
}

.weekgrid__column--today { background: var(--colour-surface-sunken); }
.weekgrid__slot { height: var(--weekgrid-hour); border-bottom: 1px solid var(--colour-border); }

.weekgrid__event {
  position: absolute;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 2px var(--space-1);
  border: 1px solid var(--colour-border);
  border-left: 3px solid var(--colour-accent);
  border-radius: var(--radius-sm);
  background: var(--colour-surface-raised);
  color: inherit;
  font-size: var(--text-xs);
  text-align: left;
  cursor: pointer;
  /* A hairline keeps two adjacent lanes from looking like one block. */
  margin-right: 1px;
}

.weekgrid__event:hover { background: var(--colour-surface-hover); z-index: 1; }
.weekgrid__event-time { color: var(--colour-text-subtle); font-variant-numeric: tabular-nums; }
.weekgrid__event-title { font-weight: var(--weight-medium); }

.weekgrid[data-days="1"] { --weekgrid-days: 1; }

/* ------------------------------------------------------- drag and drop --- */

[data-event-move] { cursor: grab; }
[data-event-move]:active { cursor: grabbing; }

/* The block being carried stays visible but recedes, so the grid underneath —
   which is what the user is aiming at — reads clearly. */
.is-dragging { opacity: 0.4; pointer-events: none; }

.is-drop-target { outline: 2px dashed var(--colour-accent); outline-offset: -2px; }

/* An agenda day has no padding of its own, so its outline is drawn outside the
   rows rather than through them. Offsetting rather than adding padding keeps
   the list from shifting under the pointer mid-drag. */
.agenda__day.is-drop-target { outline-offset: 6px; border-radius: var(--radius-md); }

/* Where the block would land. It is drawn by the drag handler rather than by
   the drop target, because a slot is 15 minutes and a cell is an hour. */
.drop-preview {
  position: absolute;
  left: 0;
  right: 0;
  border: 1px dashed var(--colour-accent);
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--colour-accent) 12%, transparent);
  pointer-events: none;
  z-index: 3;
}

.drop-preview__label {
  position: absolute;
  top: 2px;
  left: var(--space-1);
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
  color: var(--colour-accent);
}

.agenda { padding: var(--space-4); overflow-y: auto; flex: 1; }
.agenda__day { margin-bottom: var(--space-5); }
.agenda__date { font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--colour-text-muted); margin-bottom: var(--space-2); }

.agenda__event {
  display: flex;
  gap: var(--space-3);
  align-items: flex-start;
  padding: var(--space-3);
  border: 1px solid var(--colour-border);
  border-radius: var(--radius-md);
  background: var(--colour-surface-raised);
  margin-bottom: var(--space-2);
  text-decoration: none;
  color: inherit;
  width: 100%;
  text-align: left;
  font: inherit;
  cursor: pointer;
}

.agenda__event:hover { background: var(--colour-surface-hover); }
.agenda__time { font-variant-numeric: tabular-nums; color: var(--colour-text-muted); font-size: var(--text-sm); min-width: 6.5rem; }

/* --------------------------------------------------------- AI assistant */

.assistant { border: 1px solid var(--colour-accent); border-radius: var(--radius-lg); background: var(--colour-accent-soft); padding: var(--space-4); margin-bottom: var(--space-4); }
.assistant__header { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-3); font-weight: var(--weight-medium); }
.assistant__actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.assistant__result { margin-top: var(--space-3); padding: var(--space-3); background: var(--colour-surface-raised); border-radius: var(--radius-md); white-space: pre-wrap; line-height: var(--leading-relaxed); }
.assistant__privacy { font-size: var(--text-xs); color: var(--colour-text-muted); margin-top: var(--space-2); }

/* ------------------------------------------------------- notifications */

.toast-region {
  position: fixed;
  bottom: var(--space-4);
  left: var(--space-4);
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  max-width: 24rem;
}

.toast {
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  background: var(--colour-surface-raised);
  border: 1px solid var(--colour-border);
  box-shadow: var(--shadow-md);
  font-size: var(--text-sm);
}

.toast--error { border-color: var(--colour-danger); }
.toast--success { border-color: var(--colour-success); }
.toast--action { display: flex; align-items: center; gap: var(--space-3); justify-content: space-between; }

.badge {
  position: absolute;
  top: 0.15rem;
  right: 0.15rem;
  min-width: 1rem;
  height: 1rem;
  padding: 0 0.2rem;
  display: grid;
  place-items: center;
  border-radius: var(--radius-full);
  background: var(--colour-danger);
  color: #fff;
  font-size: 0.65rem;
  font-weight: var(--weight-semibold);
}

/* ------------------------------------------------------------ responsive */

/* Below this width the three columns cannot all be useful at once, so the
   shell becomes single-column and the panes stack, driven by the same
   data-pane attribute the router sets. */
@media (max-width: 60rem) {
  .shell {
    grid-template-columns: 1fr;
    grid-template-areas:
      "header"
      "main";
  }

  .sidebar {
    position: fixed;
    inset: var(--header-height) auto 0 0;
    width: min(18rem, 80vw);
    z-index: 50;
    transform: translateX(-100%);
    transition: transform var(--transition-base);
    box-shadow: var(--shadow-lg);
  }

  .shell[data-sidebar="open"] .sidebar { transform: translateX(0); }

  .mail { grid-template-columns: 1fr; }
  .mail__list { border-right: 0; }

  /* One pane at a time: the list, or the message. */
  .mail[data-pane="reader"] .mail__list { display: none; }
  .mail[data-pane="list"] .mail__reader { display: none; }

  .settings { grid-template-columns: 1fr; }
  .settings__nav { border-right: 0; border-bottom: 1px solid var(--colour-border); display: flex; gap: var(--space-1); overflow-x: auto; }

  .compose {
    inset: auto 0 0 0;
    width: 100%;
    max-height: 92dvh;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  }

  .calendar__day { min-height: 4.5rem; }
}

@media (max-width: 40rem) {
  .calendar__grid { font-size: var(--text-xs); }
  .reader { padding: var(--space-4) var(--space-3) var(--space-6); }
  .header__brand span { display: none; }
}

/* Printing a message should give the message, not the application. */
@media print {
  .header, .sidebar, .mail__list, .mail__toolbar, .message__actions, .assistant { display: none !important; }
  .shell { display: block; height: auto; }
  body { background: #fff; }
}

/* The mailbox a conversation arrived in. It sits between the sender and the
   subject, where it reads as a property of the message rather than as another
   piece of navigation. */
.mailbox-tag {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  align-self: flex-start;
  max-width: 100%;
  padding: 0 0.4rem;
  border: 1px solid var(--colour-border);
  border-radius: var(--radius-full);
  font-size: var(--text-xs);
  color: var(--colour-text-muted);
  line-height: 1.5;
}

.mailbox-tag__dot {
  width: 0.45rem;
  height: 0.45rem;
  border-radius: var(--radius-full);
  flex-shrink: 0;
  background: var(--entry-colour, var(--colour-accent));
}

/* The assistant's priority classification, shown in the same meta column as
   the date and the attachment clip. */
.priority-badge {
  padding: 0 0.4rem;
  border-radius: var(--radius-full);
  font-size: var(--text-xs);
  line-height: 1.5;
  text-transform: capitalize;
}
.priority-badge--urgent,
.priority-badge--high {
  background: var(--colour-danger-soft);
  color: var(--colour-danger);
}
.priority-badge--normal {
  background: var(--colour-warning-soft);
  color: var(--colour-warning);
}
.priority-badge--low {
  background: var(--colour-border);
  color: var(--colour-text-muted);
}

/* A mailbox section in the sidebar, folded away by default. */
.sidebar__heading--toggle {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  cursor: pointer;
  list-style: none;
}

.sidebar__heading--toggle::-webkit-details-marker { display: none; }
.sidebar__account[open] .sidebar__heading--toggle { margin-bottom: var(--space-1); }

/* ----------------------------------------------------------- palette --- */

.palette {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  margin-top: var(--space-2);
  flex-wrap: wrap;
}

.palette__swatch {
  width: 1.1rem;
  height: 1.1rem;
  padding: 0;
  border: 1px solid var(--colour-border);
  border-radius: var(--radius-full);
  cursor: pointer;
  background: var(--entry-colour, var(--colour-accent));
}

.palette__swatch:hover { transform: scale(1.15); }

/* The native picker, kept the same size as a swatch so the row reads as one
   set of choices rather than a palette with a form control stuck on the end. */
.palette__custom {
  width: 1.1rem;
  height: 1.1rem;
  border: 1px dashed var(--colour-border-strong);
  border-radius: var(--radius-full);
  overflow: hidden;
  cursor: pointer;
  display: grid;
  place-items: center;
}

.palette__custom input {
  width: 200%;
  height: 200%;
  padding: 0;
  border: 0;
  cursor: pointer;
  background: none;
}

/* -------------------------------------------------------------- sync --- */

@media (prefers-reduced-motion: no-preference) {
  .is-syncing svg { animation: kestrel-spin 0.9s linear infinite; }
}

@keyframes kestrel-spin {
  to { transform: rotate(360deg); }
}

/* -------------------------------------------------------- bulk select --- */

.bulk-bar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--colour-border);
  background: var(--colour-surface-raised);
}

.bulk-bar [data-select-all] { width: 1rem; height: 1rem; margin: 0; }

/* ----------------------------------------------- category tab strip --- */

.tab-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 0 var(--space-1);
  padding: 0 var(--space-3);
  border-bottom: 1px solid var(--colour-border);
}

.tab {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: var(--space-2) var(--space-1);
  border-bottom: 2px solid transparent;
  font-size: var(--text-xs);
  color: var(--colour-text-muted);
  text-decoration: none;
  white-space: nowrap;
}

.tab:hover { color: var(--colour-text); }

.tab--on {
  color: var(--colour-accent);
  border-bottom-color: var(--colour-accent);
  font-weight: 600;
}

.tab__icon { width: 0.9rem; height: 0.9rem; }

/* ----------------------------------------------------------- filters --- */

.filter-bar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  padding: 0 var(--space-3) var(--space-2);
  border-bottom: 1px solid var(--colour-border);
}

.filter-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.15rem var(--space-2);
  border: 1px solid var(--colour-border);
  border-radius: var(--radius-full);
  font-size: var(--text-xs);
  color: var(--colour-text-muted);
  text-decoration: none;
  white-space: nowrap;
}

.filter-chip:hover { background: var(--colour-surface-hover); color: var(--colour-text); }

.filter-chip--on {
  background: var(--colour-accent);
  border-color: var(--colour-accent);
  color: var(--colour-text-inverse);
}

.filter-chip--on:hover { background: var(--colour-accent); color: var(--colour-text-inverse); }
.filter-chip--clear { border-style: dashed; }
.filter-chip__icon { width: 0.85rem; height: 0.85rem; }

/* The read/unread control of a row. It stays out of the way until the row is
   hovered or the control itself is focused, so a list of fifty conversations
   is not fifty competing buttons — but it never disappears for a keyboard
   user, who has no hover to reveal it with. */
.thread-row__read {
  border: 0;
  background: none;
  color: var(--colour-text-subtle);
  cursor: pointer;
  padding: 0 0.15rem;
  align-self: flex-start;
  opacity: 0;
}

.thread-row:hover .thread-row__read,
.thread-row__read:focus-visible { opacity: 1; }
.thread-row__read:hover { color: var(--colour-text); }

@media (hover: none) {
  /* Nothing to hover with, so the control is simply always there. */
  .thread-row__read { opacity: 1; }
}

/* ------------------------------------------------------ entry colours --- */

/* A calendar's colour is a user's arbitrary hex, so it cannot be a class in a
   static stylesheet. It arrives as a custom property set by the one rule the
   page is allowed to generate, and is read here.
   These sit at the end deliberately: each overrides a property set by the
   component rules above, and between equal specificities the cascade takes
   whichever comes last. */
.event-chip__dot,
.sidebar__dot { background: var(--entry-colour, var(--colour-accent)); }
.event-chip__dot--top { margin-top: 0.4rem; }
.sidebar__dot--large { width: 0.75rem; height: 0.75rem; }
.weekgrid__event { border-left-color: var(--entry-colour, var(--colour-accent)); }

/* ---------------------------------------------------------------- dropdown */

/* A native <details>/<summary> disclosure: no JS needed to open or close it,
   which is exactly the "every action has a plain control behind it" rule the
   rest of this file follows. Only the positioning is custom. */
.dropdown { position: relative; display: inline-block; }
.dropdown > summary { list-style: none; cursor: pointer; }
.dropdown > summary::-webkit-details-marker { display: none; }
.dropdown__panel {
  position: absolute;
  top: calc(100% + var(--space-1));
  left: 0;
  z-index: 20;
  min-width: 14rem;
  padding: var(--space-3);
  background: var(--colour-surface);
  border: 1px solid var(--colour-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md, 0 4px 16px rgba(0, 0, 0, 0.15));
}
