.shell {
  display: grid;
  grid-template-columns: var(--sidebar-w) minmax(0, 1fr);
  height: 100dvh;
  overflow: hidden;
}

/* ---- Sidebar ---------------------------------------------------------- */
.sidebar {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  padding: var(--s-3) var(--s-3) var(--s-2);
  background: var(--surface-2);
  border-right: 1px solid var(--hairline);
  overflow-y: auto;
  z-index: var(--z-sticky);
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-2) var(--s-2) var(--s-4);
}
.brand-mark {
  width: 28px; height: 28px;
  display: grid; place-items: center;
  border-radius: var(--r-md);
  background: var(--accent);
  color: var(--ink-invert);
  flex: none;
}
.brand-name {
  font-size: var(--t-15);
  font-weight: var(--w-semibold);
  letter-spacing: -0.02em;
}
.brand-sub { font-size: var(--t-11); color: var(--ink-3); letter-spacing: 0.01em; }

.nav { display: flex; flex-direction: column; gap: 1px; }
.nav-label {
  padding: var(--s-4) var(--s-2) var(--s-1);
  font-size: var(--t-11);
  font-weight: var(--w-semibold);
  color: var(--ink-3);
}
.nav-item {
  display: flex;
  /* The icon sits on the name, not between the two lines. */
  align-items: flex-start;
  gap: var(--s-3);
  width: 100%;
  padding: var(--s-2);
  border-radius: var(--r-md);
  color: var(--ink-2);
  font-size: var(--t-13);
  font-weight: var(--w-medium);
  text-align: left;
  transition: background var(--d-fast) var(--ease), color var(--d-fast) var(--ease);
}
.nav-item:hover { background: var(--surface-hover); color: var(--ink); text-decoration: none; }
.nav-item:active { background: var(--surface-active); }
.nav-item svg {
  color: var(--ink-4);
  flex: none;
  margin-top: 1px;
  transition: color var(--d-fast) var(--ease);
}
.nav-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.nav-name { line-height: 1.25; }
/* What the screen is for, in one line. Four of these screens send email and the
   names alone never said which was which. Sized down and muted so the names still
   read as the list, and the answer is there when it is needed. */
.nav-about {
  font-size: var(--t-11);
  font-weight: var(--w-regular);
  line-height: 1.3;
  color: var(--ink-4);
}
.nav-item:hover .nav-about { color: var(--ink-3); }
.nav-item[aria-current="page"] .nav-about { color: var(--accent-ink); opacity: 0.72; }
.nav-item:hover svg { color: var(--ink-2); }
.nav-item[aria-current="page"] {
  background: var(--accent-soft);
  color: var(--accent-ink);
  font-weight: var(--w-semibold);
}
.nav-item[aria-current="page"] svg { color: var(--accent-ink); }
.nav-count {
  margin-left: auto;
  font-size: var(--t-11);
  font-variant-numeric: tabular-nums;
  color: var(--ink-3);
  background: var(--neutral-soft);
  padding: 1px 6px;
  border-radius: var(--r-full);
}

.sidebar-foot {
  margin-top: auto;
  padding-top: var(--s-3);
  border-top: 1px solid var(--hairline);
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
}
.user-chip {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-2);
  border-radius: var(--r-md);
  width: 100%;
  text-align: left;
  transition: background var(--d-fast) var(--ease);
}
.user-chip:hover { background: var(--surface-hover); }
.avatar {
  width: 26px; height: 26px; flex: none;
  border-radius: 50%;
  display: grid; place-items: center;
  background: var(--accent-soft);
  color: var(--accent-ink);
  font-size: var(--t-11);
  font-weight: var(--w-semibold);
}

/* ---- Main ------------------------------------------------------------- */
.main {
  display: flex;
  flex-direction: column;
  min-width: 0;
  overflow: hidden;
}

.topbar {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  height: var(--topbar-h);
  flex: none;
  padding: 0 var(--s-6);
  border-bottom: 1px solid var(--hairline);
  background: var(--chrome);
  backdrop-filter: saturate(180%) blur(20px);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  z-index: var(--z-sticky);
}
/* The .truncate wrapper clips but cannot ellipsis a block child, so a long
   campaign name was cut mid-glyph. The heading truncates itself. */
.topbar h1 {
  font-size: var(--t-17);
  letter-spacing: -0.015em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.topbar-sub { font-size: var(--t-12); color: var(--ink-3); }

.view {
  flex: 1 1 auto;
  overflow-y: auto;
  overflow-x: hidden;
  scroll-behavior: smooth;
}
.view-inner {
  max-width: var(--content-max);
  margin: 0 auto;
  padding: var(--s-8) var(--s-6) var(--s-16);
  animation: fade-in var(--d-base) var(--ease);
}
.view-wide .view-inner { max-width: none; }
.view-flush { display: flex; flex-direction: column; height: 100%; }

.page-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--s-4);
  margin-bottom: var(--s-6);
  flex-wrap: wrap;
}

.section { margin-top: var(--s-10); }
.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-4);
  margin-bottom: var(--s-4);
}
.section-head h2 { font-size: var(--t-15); }

/* ---- Collapsing the sidebar ------------------------------------------- */
/* The same button drives both states: below 900px it slides the sidebar in as
   an overlay (data-nav), above it collapses the grid column away (data-rail).
   Reusing one control keeps a single mental model at every width. */
.sidebar-toggle { display: inline-flex; }
.sidebar-scrim { display: none; }

.shell[data-rail="on"] { grid-template-columns: 0 minmax(0, 1fr); }
.shell[data-rail="on"] .sidebar {
  transform: translateX(-100%);
  border-right: 0;
}
/* The sidebar's transform carries the motion on its own, on the compositor. The grid
   track used to be transitioned with it, which relaid out the whole document every
   frame: on a 200-row screen one toggle blocked the main thread for 1,564 ms and ran
   at 37 fps, against 164 ms and 58 fps without it. It also fired on any window resize
   crossing 900px. Nothing that costs layout gets animated here. */
.sidebar { transition: transform var(--d-slow) var(--ease); }

@media (prefers-reduced-motion: reduce) {
  .shell, .sidebar { transition: none; }
}

/* ---- Mobile ----------------------------------------------------------- */

@media (max-width: 900px) {
  /* [data-rail="on"] has to be named here or it wins on specificity and keeps the
     two-track layout, and below this width the sidebar is position:fixed and no
     longer fills a cell — so .main lands in the 0px track and the whole app
     renders blank. The rail state is remembered in localStorage, so railing it
     away on a desktop and then opening the panel on a phone was enough. */
  .shell, .shell[data-rail="on"] { grid-template-columns: minmax(0, 1fr); }
  .sidebar {
    position: fixed;
    inset: 0 auto 0 0;
    width: var(--sidebar-w);
    transform: translateX(-100%);
    transition: transform var(--d-slow) var(--ease);
    z-index: var(--z-modal);
    box-shadow: var(--shadow-4);
  }
  .shell[data-nav="open"] .sidebar { transform: none; }
  .shell[data-nav="open"] .sidebar-scrim {
    display: block;
    position: fixed;
    inset: 0;
    background: var(--scrim);
    z-index: var(--z-backdrop);
    animation: fade-in var(--d-base) var(--ease);
  }
  .sidebar-toggle { display: inline-flex; }
  .view-inner { padding: var(--s-6) var(--s-4) var(--s-12); }
  .topbar { padding: 0 var(--s-4); }
}

/* ---- Start here (dashboard) --------------------------------------------- */
/* Three doors, one per thing this panel does. Equal width on purpose: they are
   alternatives, not a ranked list, and the job line under each name is what
   actually distinguishes them. */
.doors {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--s-4);
}
.door {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-areas: "icon name" ". about";
  gap: var(--s-1) var(--s-3);
  padding: var(--s-5);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--r-lg);
  background: var(--surface);
  color: var(--ink);
  transition: border-color var(--d-fast) var(--ease), background var(--d-fast) var(--ease);
}
.door:hover {
  background: var(--surface-hover);
  border-color: var(--accent-ink);
  text-decoration: none;
}
.door:active { background: var(--surface-active); }
.door-icon { grid-area: icon; display: flex; color: var(--accent-ink); }
.door-name { grid-area: name; font-weight: var(--w-semibold); font-size: var(--t-14); }
.door-about { grid-area: about; font-size: var(--t-12); color: var(--ink-3); line-height: 1.45; }

/* The one thing standing between this install and a sent message. Deliberately not a
   .callout: it is the whole content of the screen until it is resolved. */
.blocker {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--s-4);
  padding: var(--s-5);
  border: 1px solid color-mix(in oklch, var(--warn) 34%, transparent);
  border-radius: var(--r-lg);
  background: var(--warn-soft);
  color: var(--warn-ink);
}
.blocker svg { flex: none; margin-top: 2px; }
.blocker p { margin-top: 3px; font-size: var(--t-13); }
.blocker .btn { flex: none; align-self: center; }
/* Below the wrap the button lands on its own line, where centring it beside nothing
   reads as a stray control. The text keeps its column; the button takes the width. */
@media (max-width: 620px) {
  .blocker { flex-direction: column; }
  .blocker .btn { align-self: stretch; text-align: center; justify-content: center; }
}
