/* Uproad Hub — base styles. Self-hosted fonts, ink-on-paper defaults,
   and the small utility vocabulary from the brand system. Mobile-first. */

@font-face {
  font-family: "Libre Caslon Display";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/LibreCaslonDisplay.woff2") format("woff2");
}
@font-face {
  font-family: "Work Sans";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/fonts/WorkSans-var.woff2") format("woff2");
}
@font-face {
  font-family: "Work Sans";
  font-style: italic;
  font-weight: 100 900;
  font-display: swap;
  src: url("/fonts/WorkSans-var-italic.woff2") format("woff2");
}

/* Base — "most layouts are ink on paper" */
* { box-sizing: border-box; }
body {
  background: var(--up-bg);
  color: var(--up-fg);
  font-family: var(--up-font-body);
  font-size: var(--up-text-body);
  font-weight: var(--up-weight-regular);
  line-height: 1.55;
  margin: 0;
}

/* Accessibility: text size (Settings). Whole-page zoom rather than a
   font-size token rewrite — every font-size in this file is a literal
   px value, so scaling the root font-size alone wouldn't cascade. */
body[data-font-scale="small"] { zoom: 0.9; }
body[data-font-scale="large"] { zoom: 1.15; }
body[data-font-scale="xlarge"] { zoom: 1.3; }

/* Headlines: Libre Caslon Display — big, upright, never italicized */
h1, h2 {
  font-family: var(--up-font-display);
  font-weight: 400;
  font-style: normal;
  line-height: 1.12;
  margin: 0 0 var(--up-space-md);
}
h1 { font-size: var(--up-text-headline); }
h2 { font-size: var(--up-text-subhead); }
h3 {
  font-family: var(--up-font-body);
  font-weight: var(--up-weight-semibold);
  font-size: 18px;
  margin: 0 0 var(--up-space-sm);
}

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

/* Utility classes — the brand's small vocabulary */
.up-caption {
  font-size: var(--up-text-caption);
  font-weight: var(--up-weight-semibold);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--up-muted);
}
.up-kicker {
  font-size: var(--up-text-caption);
  font-weight: var(--up-weight-bold);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--up-accent);
}
.up-dark-ground {
  background: var(--up-ground);
  color: var(--up-paper);
}
.up-dark-ground .up-kicker { color: var(--up-copper); }

/* Top bar */
.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--up-space-md);
  padding: var(--up-space-md);
  flex-wrap: wrap;
}
.topbar-right {
  display: flex;
  align-items: center;
  gap: var(--up-space-md);
  flex-wrap: wrap;
}
.topbar-left {
  display: flex;
  align-items: center;
  gap: var(--up-space-md);
}
.topbar-link {
  color: var(--up-paper);
  font-size: 14px;
}
.topbar-brand,
.sidebar-brand {
  display: flex;
  align-items: center;
  gap: var(--up-space-sm);
  color: var(--up-paper);
  text-decoration: none;
}
.topbar-mark { height: 28px; width: auto; }
.topbar-org-label,
.topbar-mark-divided {
  padding-right: var(--up-space-sm);
  border-right: 1px solid var(--up-neutral-500);
}
.topbar-org-label {
  font-family: var(--up-font-display);
  font-size: 20px;
}
.topbar-wordmark {
  font-family: var(--up-font-display);
  font-size: 20px;
  letter-spacing: 0.01em;
}
.topbar-version-badge {
  font-family: var(--up-font-body, inherit);
  font-size: 9px;
  font-weight: var(--up-weight-semibold);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--up-neutral-400);
  margin-left: var(--up-space-xs);
  vertical-align: super;
}
.topbar-wordmark-group { display: flex; flex-direction: column; line-height: 1.15; }
.topbar-wordmark-accent { color: var(--up-copper); }
.topbar-tagline {
  font-size: 9px;
  font-weight: var(--up-weight-semibold);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--up-neutral-300);
}

/* Sidebar toggle (hamburger). Desktop: hides/shows the rail, state
   persisted per-user. Mobile: opens/closes the drawer, not persisted —
   see nav.js, which picks the behavior based on viewport width. */
.sidebar-toggle {
  background: none;
  border: none;
  color: var(--up-paper);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  padding: var(--up-space-xs);
  border-radius: var(--up-radius-sm);
}
.sidebar-toggle:hover { background: var(--up-surface); color: var(--up-copper); }

/* Sidebar — a persistent left rail on desktop (position: sticky, so it
   rides along with page scroll instead of scrolling away), an off-canvas
   drawer on mobile (see the mobile pass below). Same dark ground as the
   old topbar/tabs it replaces. */
.sidebar {
  width: 240px;
  flex: none;
  position: sticky;
  top: 0;
  height: 100vh;
  display: flex;
  flex-direction: column;
  overflow-x: hidden;
  overflow-y: auto;
  border-right: 1px solid var(--up-line);
  transition: width 0.22s ease-in-out, border-color 0.22s ease-in-out;
}
/* Collapsed is a desktop-only, persisted preference (users.sidebar_collapsed)
   — scoped to min-width so it never fights the mobile drawer's own
   open/close state (.sidebar-open below), which is transient and viewport-
   driven instead. Width (not display:none) so the collapse animates —
   .sidebar-head/.sidebar-nav below hold their expanded width so they clip
   via overflow-x: hidden instead of reflowing/wrapping mid-slide. */
@media (min-width: 701px) {
  .app-shell.sidebar-collapsed .sidebar { width: 0; border-right-color: transparent; }
}
.sidebar-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--up-space-sm);
  padding: var(--up-space-md);
  width: 240px;
  flex-shrink: 0;
}
.sidebar-close {
  display: none;
  background: none;
  border: none;
  color: var(--up-paper);
  font-size: 16px;
  cursor: pointer;
  padding: 2px 6px;
}
.sidebar-nav {
  display: flex;
  flex-direction: column;
  gap: var(--up-space-md);
  padding: 0 var(--up-space-sm) var(--up-space-lg);
  width: 240px;
  flex-shrink: 0;
}
.nav-section { display: flex; flex-direction: column; }
.nav-section-kicker { padding: var(--up-space-xs) var(--up-space-sm); }
.nav-item-list { display: flex; flex-direction: column; }
.nav-item {
  display: flex;
  align-items: center;
  gap: 6px;
  border-radius: var(--up-radius-sm);
}
.nav-item:hover { background: var(--up-surface); }
.nav-item-active { background: var(--up-strong-bg); }
.nav-item-active .nav-link { color: var(--up-strong-fg); font-weight: var(--up-weight-semibold); }
.nav-item.dragging { opacity: 0.4; }
.nav-grip {
  cursor: grab;
  color: var(--up-neutral-400);
  font-size: 12px;
  padding-left: var(--up-space-sm);
  flex: none;
}
.nav-link {
  flex: 1;
  min-width: 0;
  padding: 7px var(--up-space-sm) 7px 4px;
  color: var(--up-fg);
  text-decoration: none;
  font-size: 14px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.nav-item:hover .nav-link { color: var(--up-copper); }
.nav-item-active:hover .nav-link { color: var(--up-strong-fg); }
.sidebar .menu-newws { padding: 0 var(--up-space-sm) 0 var(--up-space-lg); }
.sidebar-backdrop { display: none; }

/* Dropdown backdrop (nav.js): a full-screen tap target that sits behind
   any open .menu (user menu, quick create, gear transfer), same idiom as
   .sidebar-backdrop above. A document-level pointerdown listener alone
   turned out not to reliably close dropdowns on every mobile browser —
   this covers the full viewport itself, so an outside tap has a direct,
   unambiguous element to land on instead of depending on the tap event
   bubbling all the way up. Sits above ordinary content but below the
   open menu panel itself (z-index 20, see .menu-panel). */
.menu-backdrop { display: none; }
.menu-backdrop.menu-backdrop-visible {
  display: block;
  position: fixed;
  inset: 0;
  z-index: 15;
}

/* Content */
.content {
  /* Explicit width: 100% — .content is now a flex item of .main-col (the
     sidebar shell's column), and a flex item's cross-axis auto margins
     (the centering trick below) suppress the default stretch-to-fill
     behavior, sizing the item to its own max-width instead of the
     available space. Without this it renders at a fixed 720px and
     overflows any viewport narrower than that. */
  width: 100%;
  max-width: 720px;
  margin: 0 auto;
  padding: var(--up-space-xl) var(--up-space-md) var(--up-space-2xl);
}
/* Cards go paper (Cream, #F7F5F1 — the Brand Book's actual "paper white,"
   same hex as the Brand Guide swatch, not an invented light gray) instead
   of a dark surface, for legibility. Re-pointing fg, muted, surface,
   surface-2, and line here (rather than just the background) is what
   makes this safe: every descendant already reads its text, border, and
   nested-surface color through those same tokens, so this one block
   re-themes the whole card subtree — tables, stage tracks, comment
   bubbles, form inputs — without touching any of those rules
   individually. Copper stays the copper token throughout; it was already
   the Brand Book's ink-on-paper accent before Muted Navy became the
   app's ground. */
.card {
  --up-fg: var(--up-ink);
  --up-muted: color-mix(in srgb, var(--up-ink) 55%, var(--up-paper));
  --up-border: color-mix(in srgb, var(--up-ink) 15%, var(--up-paper));
  --up-line: color-mix(in srgb, var(--up-ink) 15%, var(--up-paper));
  --up-surface: var(--up-paper);
  --up-surface-2: color-mix(in srgb, var(--up-ink) 5%, var(--up-paper));

  border: 1px solid var(--up-border);
  background: var(--up-paper);
  color: var(--up-fg);
  border-radius: var(--up-radius);
  padding: var(--up-space-lg);
  margin-top: var(--up-space-lg);
}
.card .up-caption { margin-bottom: var(--up-space-md); }

/* A card-scoped error: the card itself gets a danger outline, the
   heading gets a small warning badge, and the message renders as a
   highlighted callout right where the problem is — instead of a generic
   banner at the top of the page. */
.card-danger {
  border-color: var(--up-danger);
  box-shadow: 0 0 0 1px var(--up-danger);
}
.danger-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  margin-left: var(--up-space-xs);
  border-radius: 50%;
  background: var(--up-danger);
  color: var(--up-ink);
  font-size: 12px;
  font-weight: var(--up-weight-bold);
  vertical-align: middle;
  cursor: default;
}
.section-alert {
  background: color-mix(in srgb, var(--up-danger) 14%, transparent);
  border: 1px solid var(--up-danger);
  border-radius: var(--up-radius-sm);
  color: var(--up-danger);
  font-size: 14px;
  font-weight: var(--up-weight-medium);
  padding: var(--up-space-sm) var(--up-space-md);
  margin: var(--up-space-md) 0;
}

/* Palette swatches (Phase 0 placeholder page) */
.swatches {
  display: flex;
  flex-wrap: wrap;
  gap: var(--up-space-lg);
}
.swatch {
  display: flex;
  align-items: center;
  gap: var(--up-space-sm);
  font-size: 14px;
}
.chip {
  display: inline-block;
  width: 28px;
  height: 28px;
  border-radius: 50%;
}
.chip-outline { border: 1px solid var(--up-border); }

.specimen-display {
  font-family: var(--up-font-display);
  font-size: var(--up-text-subhead);
  margin: 0 0 var(--up-space-sm);
}
.specimen-body { margin: 0; }

/* Forms */
.stack { display: flex; flex-direction: column; gap: var(--up-space-md); max-width: 380px; }
.stack label {
  display: flex;
  flex-direction: column;
  gap: var(--up-space-xs);
  font-size: 14px;
  font-weight: var(--up-weight-medium);
}
input, select, textarea {
  font: inherit;
  color: var(--up-fg);
  background: var(--up-surface);
  border: 1px solid var(--up-line);
  border-radius: var(--up-radius-sm);
  padding: 10px 12px;
}
textarea { resize: vertical; }
input:focus, select:focus, textarea:focus { outline: 2px solid var(--up-copper); outline-offset: 0; }

.btn {
  font: inherit;
  font-weight: var(--up-weight-semibold);
  background: var(--up-copper);
  color: var(--up-paper);
  border: none;
  border-radius: var(--up-radius-sm);
  padding: 10px 20px;
  cursor: pointer;
  align-self: flex-start;
}
.btn-ghost {
  font: inherit;
  font-size: 14px;
  background: none;
  border: 1px solid var(--up-neutral-400);
  border-radius: var(--up-radius-sm);
  color: inherit;
  padding: 5px 12px;
  cursor: pointer;
}
.btn-small { font-size: 12px; padding: 3px 10px; }
.inline-form { display: inline; }

.form-error { color: var(--up-danger); font-weight: var(--up-weight-medium); }
.form-notice { color: var(--up-copper); font-weight: var(--up-weight-medium); }

.auth-wrap { max-width: 380px; margin: var(--up-space-2xl) auto 0; }

/* Tables */
.table { width: 100%; border-collapse: collapse; margin: var(--up-space-lg) 0; }
.table th {
  text-align: left;
  font-size: var(--up-text-caption);
  font-weight: var(--up-weight-semibold);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--up-muted);
  padding: var(--up-space-sm);
  border-bottom: 1px solid var(--up-line);
}
.table td {
  padding: var(--up-space-sm);
  border-bottom: 1px solid var(--up-border);
  font-size: 14px;
  vertical-align: middle;
}
.row-inactive td { color: var(--up-muted); }
.row-inactive .avatar { opacity: 0.6; }
.task-done { text-decoration: line-through; color: var(--up-muted); }

/* Owner/assignee avatars standing in for a name — hover for who it is
   (avatarHtml sets title=), click through to their profile (avatarLink). */
.avatar-link { display: inline-block; line-height: 0; border-radius: 50%; }
.avatar-link:focus-visible { outline: 2px solid var(--up-copper); outline-offset: 1px; }
.owner-line { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.owner-line .avatar { vertical-align: middle; }

/* Multiple assignees on one project: overlap into a facepile instead of a
   row — a ring in the card's own background separates the circles, and
   whichever one you're hovering pops in front so its title tooltip and
   click target aren't half-covered by its neighbor. */
.avatar-stack { display: flex; }
.avatar-stack .avatar-link {
  margin-left: -10px;
  position: relative;
  z-index: 1;
  border-radius: 50%;
  box-shadow: 0 0 0 2px var(--up-surface);
}
.avatar-stack .avatar-link:first-child { margin-left: 0; }
.avatar-stack .avatar-link:hover,
.avatar-stack .avatar-link:focus-visible { z-index: 2; }

/* Sidebar shell — see the "Sidebar" block further down for the aside
   itself. .app-shell is the flex row (sidebar + main column); the topbar
   above now only holds the collapse/drawer toggle and the account cluster. */
.app-shell { display: flex; align-items: stretch; min-height: 100vh; }
.main-col { flex: 1; min-width: 0; display: flex; flex-direction: column; }

/* Bell */
.bell { position: relative; display: inline-flex; align-items: center; }
.bell-count {
  position: absolute;
  top: -7px; right: -9px;
  background: var(--up-copper);
  color: var(--up-paper);
  font-size: 10px;
  font-weight: var(--up-weight-bold);
  border-radius: 8px;
  padding: 0 5px;
  line-height: 14px;
}

/* Avatar: a real image if the user set an avatar link, otherwise their
   initials on the brand accent — same fallback in the topbar and on the
   profile page, sized via inline style at each call site. */
.avatar {
  border-radius: 50%;
  object-fit: cover;
  flex: none;
}
.avatar-initials {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--up-copper);
  color: var(--up-paper);
  font-weight: var(--up-weight-semibold);
  letter-spacing: 0.02em;
}

/* Account menu: avatar trigger, dropdown to Profile/Settings/Log out. */
.user-menu > summary { border-radius: 50%; }
.user-menu > summary::-webkit-details-marker { display: none; }
/* .menu-list defaults to left:0 (right-expanding) for Studio/Ops, which
   sit on the left of the topbar. This trigger sits at the far right
   instead, so its panel needs to expand leftward or it runs off-screen. */
.user-menu .menu-panel { left: auto; right: 0; }
.menu-logout-form { padding: var(--up-space-xs) 10px 0; }
.menu-logout-form .btn-ghost { width: 100%; }

.profile-header {
  display: flex;
  align-items: center;
  gap: var(--up-space-md);
  margin-bottom: var(--up-space-lg);
}
.profile-header p { margin: 0; }

/* Projects: one row per project with a compact dot tracker instead of a
   horizontal-scrolling kanban — the whole lifecycle stays in view. */
.stage-track-list { display: flex; flex-direction: column; gap: var(--up-space-sm); }
.stage-track-row {
  border: 1px solid var(--up-border);
  background: var(--up-surface);
  border-radius: var(--up-radius);
  padding: var(--up-space-sm) var(--up-space-md);
}
.stage-track-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--up-space-sm);
  flex-wrap: wrap;
  margin-bottom: var(--up-space-sm);
}
.stage-track-head a { font-weight: var(--up-weight-medium); text-decoration: none; color: var(--up-fg); }
.stage-track-head a:hover { color: var(--up-copper); }
.stage-track { display: flex; align-items: center; gap: var(--up-space-xs); }
.stage-track-dots { display: flex; align-items: center; flex: 1; min-width: 0; }
.stage-dot {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: var(--up-surface);
  border: 2px solid var(--up-line);
  flex: 0 0 auto;
}
.stage-dot-past { background: var(--up-copper); border-color: var(--up-copper); }
.stage-dot-current {
  width: 15px;
  height: 15px;
  background: var(--up-copper);
  border-color: var(--up-copper);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--up-copper) 25%, transparent);
}
.stage-dot-line { flex: 1 1 auto; height: 2px; min-width: 8px; background: var(--up-line); }
.stage-dot-line-past { background: var(--up-copper); }
.stage-track-label {
  font-size: 12px;
  font-weight: var(--up-weight-medium);
  color: var(--up-muted);
  white-space: nowrap;
  min-width: 88px;
  text-align: right;
}
.stage-track-nav {
  background: none;
  border: none;
  color: var(--up-muted);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  padding: 0 var(--up-space-xs);
}
.stage-track-nav:hover { color: var(--up-copper); }
.stage-track-nav-spacer { display: inline-block; width: 22px; }

/* Project stage strip */
.stage-strip {
  display: flex;
  align-items: center;
  gap: var(--up-space-xs);
  flex-wrap: wrap;
  margin: var(--up-space-md) 0;
}
.stage-pill {
  font-size: 12px;
  font-weight: var(--up-weight-medium);
  padding: 3px 10px;
  border: 1px solid var(--up-line);
  border-radius: 12px;
  color: var(--up-muted);
}
.stage-past { border-color: var(--up-copper); color: var(--up-copper); }
.stage-current {
  background: var(--up-strong-bg);
  border-color: var(--up-strong-bg);
  color: var(--up-strong-fg);
}
.stage-sep { color: var(--up-line); font-size: 12px; }

/* Inline stacked forms */
.stack-inline {
  display: flex;
  gap: var(--up-space-sm);
  flex-wrap: wrap;
  align-items: center;
  margin-top: var(--up-space-md);
}
.stack-row { display: flex; gap: var(--up-space-lg); align-items: center; flex-wrap: wrap; }
.admin-tools { margin: var(--up-space-md) 0; }
.admin-tools summary { cursor: pointer; }
.sendback-form { display: inline-flex; gap: 4px; }
.sendback-form input { padding: 4px 8px; font-size: 13px; }

.view-toggle { font-size: 14px; }
.view-toggle a { text-decoration: none; color: var(--up-muted); }
.view-toggle a.toggle-active { color: var(--up-fg); font-weight: var(--up-weight-semibold); }

/* Todos */
.todos { list-style: none; padding: 0; margin: 0 0 var(--up-space-md); }
.todo {
  display: flex;
  align-items: center;
  gap: var(--up-space-sm);
  padding: var(--up-space-xs) 0;
  border-bottom: 1px solid var(--up-border);
}
.todo-title { flex: 1; }
.todo-done .todo-title { text-decoration: line-through; color: var(--up-muted); }
.todo-check {
  width: 22px; height: 22px;
  border: 1px solid var(--up-neutral-400);
  border-radius: var(--up-radius-sm);
  background: var(--up-surface);
  cursor: pointer;
  color: var(--up-copper);
  font-weight: var(--up-weight-bold);
}

/* Feeds */
.feed { list-style: none; padding: 0; margin: 0; }
.feed li { padding: var(--up-space-sm) 0; border-bottom: 1px solid var(--up-border); font-size: 14px; }
.feed .up-caption { display: block; }
.notif-unread { font-weight: var(--up-weight-medium); }
.notif-unread::before { content: '●'; color: var(--up-copper); margin-right: 6px; }
.notif-read { color: var(--up-muted); }
.sendback-note { font-style: italic; }

/* Comments: avatar, bubble, time — texting-app minimal, no name line (the
   avatar carries identity). Reactions and delete tuck into the same small
   caption-height row under the bubble so a comment with nothing on it
   stays this quiet. */
.comment-list {
  list-style: none; padding: 0; margin: 0 0 var(--up-space-md);
  display: flex; flex-direction: column; gap: var(--up-space-md);
}
.comment { display: flex; gap: var(--up-space-sm); align-items: flex-start; }
.comment-main { min-width: 0; max-width: 80%; }
.comment-bubble {
  background: var(--up-surface-2);
  border-radius: var(--up-radius);
  padding: 8px 12px;
  white-space: pre-wrap;
  overflow-wrap: break-word;
}
.comment-foot {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  margin-top: 4px;
}
.comment-time { font-size: 11px; color: var(--up-muted); }

.reaction-pill {
  background: var(--up-surface);
  border: 1px solid var(--up-line);
  border-radius: 999px;
  padding: 1px 7px;
  font-size: 12px;
  line-height: 1.6;
  color: var(--up-fg);
  cursor: pointer;
}
.reaction-pill.reaction-mine { border-color: var(--up-copper); background: color-mix(in srgb, var(--up-copper) 22%, var(--up-surface)); }

.reaction-picker { display: inline-block; }
.reaction-picker > summary {
  list-style: none;
  cursor: pointer;
  color: var(--up-muted);
  font-size: 12px;
  padding: 0 4px;
  border: 1px solid var(--up-line);
  border-radius: 999px;
}
.reaction-picker > summary::-webkit-details-marker { display: none; }
.reaction-picker > summary:hover { color: var(--up-copper); border-color: var(--up-copper); }
.reaction-picker[open] > summary { color: var(--up-copper); border-color: var(--up-copper); }
/* Author `display` on a details child outranks the UA's collapse-when-closed
   rule (see .menu-panel above) — state it explicitly or options leak through. */
.reaction-picker:not([open]) > .reaction-options { display: none; }
.reaction-picker .reaction-options { display: inline-flex; gap: 3px; margin-left: 4px; }
.reaction-options .reaction-pill { font-size: 15px; padding: 0 5px; }

/* Admin Users page: reset-password trigger, same details-as-button idiom
   as .reaction-picker — a small popover form instead of a page round-trip
   for a one-off field. */
.pw-reset { display: inline-block; }
.pw-reset > summary {
  list-style: none;
  cursor: pointer;
  font-size: 12px;
  padding: 3px 10px;
  border: 1px solid var(--up-neutral-400);
  border-radius: var(--up-radius-sm);
}
.pw-reset > summary::-webkit-details-marker { display: none; }
.pw-reset > summary:hover { color: var(--up-copper); border-color: var(--up-copper); }
.pw-reset[open] > summary { color: var(--up-copper); border-color: var(--up-copper); }
.pw-reset:not([open]) > form { display: none; }
.pw-reset > form { margin-top: var(--up-space-sm); min-width: 220px; }

.comment-delete-form { margin-left: auto; }
.comment-delete {
  background: none;
  border: none;
  color: var(--up-muted);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  padding: 0 2px;
}
.comment-delete:hover { color: var(--up-danger); }
.mention { color: var(--up-copper); font-weight: var(--up-weight-medium); }
.comment-form input { flex: 1; }

/* Schedule */
.cal { width: 100%; border-collapse: collapse; table-layout: fixed; }
.cal th {
  font-size: var(--up-text-caption);
  font-weight: var(--up-weight-semibold);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--up-muted);
  padding: var(--up-space-xs);
  text-align: left;
}
.cal td {
  border: 1px solid var(--up-border);
  vertical-align: top;
  padding: var(--up-space-xs);
  height: 72px;
}
.cal-empty { background: var(--up-surface); }
.cal-today { outline: 2px solid var(--up-copper); outline-offset: -2px; }
.cal-day { font-size: 12px; color: var(--up-muted); margin-bottom: 2px; }
.cal-nav { display: flex; align-items: center; gap: var(--up-space-md); }
.cal-nav h2 { margin: 0; }
.event-chip {
  display: block;
  font-size: 11px;
  line-height: 1.3;
  padding: 2px 4px;
  margin-bottom: 2px;
  background: var(--up-surface);
  border-left: 3px solid var(--up-copper);
  border-radius: var(--up-radius-sm);
  color: var(--up-fg);
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.event-project { border-left-color: var(--up-copper); }
.event-call { border-left-color: var(--up-paper); }
.call-card h2 a { text-decoration: none; color: var(--up-fg); }
.badge-muted { color: var(--up-muted); border-color: var(--up-line); }
.role-picks { border: 1px solid var(--up-border); border-radius: var(--up-radius); padding: var(--up-space-md); }
.role-picks legend { padding: 0 var(--up-space-xs); }
.role-check {
  display: inline-flex !important;
  flex-direction: row !important;
  align-items: center;
  gap: var(--up-space-xs);
  margin-right: var(--up-space-md);
  font-weight: var(--up-weight-regular) !important;
}
.role-check input { accent-color: var(--up-copper); }

/* Search */
.searchform input {
  padding: 5px 10px;
  font-size: 13px;
  width: 140px;
  background: var(--up-neutral-600);
  border: 1px solid var(--up-neutral-500);
  border-radius: var(--up-radius-sm);
  color: var(--up-paper);
}
.searchform input::placeholder { color: var(--up-neutral-400); }
.search-snippet { font-size: 13px; color: var(--up-muted); margin-top: 2px; }
.search-snippet mark {
  background: color-mix(in srgb, var(--up-copper) 25%, transparent);
  color: inherit;
  padding: 0 1px;
  border-radius: 3px;
}

/* Docs */
.docs-layout {
  display: grid;
  grid-template-columns: 220px 1fr;
  gap: var(--up-space-xl);
  align-items: start;
}
.doc-sidebar {
  border-right: 1px solid var(--up-border);
  padding-right: var(--up-space-md);
}
.doc-tree { list-style: none; padding-left: 0; margin: var(--up-space-sm) 0; }
.doc-tree .doc-tree { padding-left: var(--up-space-md); }
.doc-tree a {
  display: block;
  padding: 3px 6px;
  text-decoration: none;
  color: var(--up-fg);
  font-size: 14px;
}
.doc-tree a:hover { color: var(--up-copper); }
.doc-tree a.doc-active { background: var(--up-strong-bg); color: var(--up-strong-fg); border-radius: var(--up-radius-sm); }
.doc-body { max-width: 640px; }
.doc-body pre {
  background: var(--up-surface);
  border: 1px solid var(--up-border);
  border-radius: var(--up-radius);
  padding: var(--up-space-md);
  overflow-x: auto;
  font-size: 13px;
}
.doc-body code { background: var(--up-surface); border-radius: var(--up-radius-sm); padding: 0 3px; font-size: 0.92em; }
.doc-body pre code { background: none; padding: 0; }
.doc-editor { max-width: 640px; }
.doc-editor textarea {
  font: 13px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;
  color: var(--up-fg);
  background: var(--up-surface);
  border: 1px solid var(--up-line);
  border-radius: var(--up-radius-sm);
  padding: var(--up-space-md);
  width: 100%;
}

/* Mobile pass */
@media (max-width: 700px) {
  .content { padding: var(--up-space-lg) var(--up-space-sm) var(--up-space-xl); }
  h1 { font-size: 27px; }
  .topbar { padding: var(--up-space-sm) var(--up-space-md); }
  .topbar-tagline { display: none; }
  .searchform input { width: 90px; }
  .table { display: block; overflow-x: auto; white-space: nowrap; }
  .docs-layout { grid-template-columns: 1fr; }
  .doc-sidebar { border-right: none; border-bottom: 1px solid var(--up-border); padding: 0 0 var(--up-space-md); }
  .cal td { height: 52px; padding: 2px; }
  .event-chip { font-size: 9px; padding: 1px 2px; }
  .cal-day { font-size: 10px; }
  .stack, .doc-editor, .doc-body { max-width: 100%; }

  /* Sidebar becomes an off-canvas drawer: hidden by default, slid in over
     the content (not pushing it) when .sidebar-open is toggled by
     nav.js's hamburger handler. No drag handles here — reordering is a
     desktop-only affordance, touch drag-and-drop is unreliable and the
     grip icon just adds noise to a narrow drawer. */
  .sidebar {
    position: fixed;
    inset: 0 auto 0 0;
    width: 260px;
    max-width: 84vw;
    z-index: 210;
    transform: translateX(-100%);
    transition: transform 0.2s ease;
    box-shadow: 0 0 32px rgba(0, 0, 0, 0.5);
  }
  .app-shell.sidebar-open .sidebar { transform: translateX(0); }
  .sidebar-close { display: block; }
  .nav-grip { display: none; }
  /* Desktop pins these to 240px so the collapse animation clips instead of
     reflowing (see .sidebar above); the mobile drawer isn't width-animated,
     so let them fill its full (slightly wider, 260px) box instead. */
  .sidebar-head, .sidebar-nav { width: 100%; }
  .sidebar-backdrop {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 205;
  }
  .app-shell.sidebar-open .sidebar-backdrop { display: block; }
}

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

/* CRM */
.deal-value {
  font-weight: var(--up-weight-semibold);
  color: var(--up-copper);
  font-size: 15px;
  margin-left: var(--up-space-xs);
}
.agenda-day { margin-bottom: var(--up-space-md); }
.agenda-day .event-chip { font-size: 14px; white-space: normal; max-width: 480px; }
.agenda-overdue { color: var(--up-danger); }
.ics-url {
  display: block;
  background: var(--up-surface);
  border: 1px solid var(--up-border);
  border-radius: var(--up-radius-sm);
  padding: var(--up-space-sm);
  font-size: 13px;
  word-break: break-all;
}

/* Excel-style grid tables (gear locker & friends) — the outer edge rounds
   with the rest of the UI; individual cells stay square, so the grid
   itself still reads as a dense data table. */
.table-grid { border: 1px solid var(--up-line); border-radius: var(--up-radius); overflow: hidden; }
.table-grid th, .table-grid td {
  border: 1px solid var(--up-line);
  padding: 5px 8px;
  font-size: 13px;
}
.table-grid th {
  background: var(--up-surface-2);
  border-color: var(--up-line);
}
.table-grid tbody tr:hover td {
  background: color-mix(in srgb, var(--up-copper) 5%, transparent);
}

/* Click-to-open dropdown popover (<details>) */
.menu { position: relative; display: inline-block; }
.menu > summary {
  list-style: none;
  cursor: pointer;
  display: inline-block;
}
.menu > summary::-webkit-details-marker { display: none; }
.menu[open] > summary { background: var(--up-surface); border-radius: var(--up-radius-sm); }
/* Quick Create's trigger is a filled .btn, not a plain text link like the
   other topbar menus — .menu[open] > summary above would otherwise swap it
   to the neutral surface color while the panel is open. */
.quick-create-menu[open] > summary.qc-trigger { background: var(--up-copper); }
/* .menu-panel sets its own `display`, which as an author rule outranks the
   UA stylesheet's `details:not([open]) > *:not(summary) { display: none }`
   — so closed panels stay visible unless we hide them explicitly here. */
.menu:not([open]) > .menu-panel { display: none; }
.menu-panel {
  position: absolute;
  right: 0;
  top: calc(100% + 4px);
  z-index: 20;
  display: flex;
  gap: var(--up-space-sm);
  align-items: center;
  background: var(--up-surface-2);
  border: 1px solid var(--up-line);
  border-radius: var(--up-radius);
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.5);
  padding: var(--up-space-sm);
  white-space: nowrap;
}
.menu-panel select { padding: 5px 8px; font-size: 13px; }

.menu-list {
  flex-direction: column;
  align-items: stretch;
  left: 0;
  right: auto;
  min-width: 220px;
  padding: var(--up-space-xs);
}
.qc-panel { min-width: 260px; gap: 0; }
/* Each Quick Create item (Task/Project/To-do) is its own <details name=
   "qc-item"> — the shared `name` makes them mutually exclusive natively,
   so opening one closes whichever other was open, and the form stays
   hidden until its label is clicked. */
.qc-item { padding: 0 var(--up-space-sm); }
.qc-item > summary {
  list-style: none;
  cursor: pointer;
  padding: 9px 2px;
  font-size: 14px;
  font-weight: var(--up-weight-medium);
  color: var(--up-fg);
}
.qc-item > summary::-webkit-details-marker { display: none; }
.qc-item > summary:hover { color: var(--up-copper); }
.qc-item + .qc-item { border-top: 1px solid var(--up-line); }
.qc-form { gap: var(--up-space-sm); margin: 0 0 var(--up-space-md); max-width: none; }
.qc-empty { padding: var(--up-space-xs) var(--up-space-sm) 0; max-width: 240px; }
.menu-list a {
  padding: 7px 10px;
  text-decoration: none;
  color: var(--up-fg);
  font-size: 14px;
  border-radius: var(--up-radius-sm);
}
.menu-list a:hover { background: var(--up-surface); color: var(--up-copper); }
.menu-list .menu-kicker { padding: 7px 10px 2px; }
.menu-list .menu-divider { height: 1px; margin: var(--up-space-xs) 0; background: var(--up-line); }
.menu-newws { padding: 0 10px; }
.menu-newws > summary {
  list-style: none;
  cursor: pointer;
  font-size: 14px;
  color: var(--up-fg);
  padding: 7px 0;
}
.menu-newws > summary::-webkit-details-marker { display: none; }
.menu-newws > summary:hover { color: var(--up-copper); }
.menu-newws form { margin: var(--up-space-xs) 0 var(--up-space-sm); max-width: none; }

/* Cross-document view transition: a soft fade out of whatever page you're
   leaving (most noticeably the login page) into whatever loads next,
   instead of the instant cut a normal navigation gives you — no JS, and
   it's a real browser-native page navigation the whole time. Every page
   shares this stylesheet, so it quietly smooths every navigation in the
   app, not just login. Progressive enhancement: browsers without support
   (this API is recent) just navigate instantly like they always did —
   nothing to fall back to, nothing that can break. */
@view-transition {
  navigation: auto;
}
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 0.45s;
  animation-timing-function: ease-in-out;
}
@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation-duration: 0.01s;
  }
}

/* Welcome animation: only on the landing right after login (see
   routes/home.js justLoggedIn) — a quiet fade + rise, kicker then
   heading, never on ordinary visits to Home. */
@keyframes welcome-rise {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}
.welcome-in .up-kicker { animation: welcome-rise 0.5s ease-out both; }
.welcome-in h1 { animation: welcome-rise 0.5s ease-out 0.08s both; }
@media (prefers-reduced-motion: reduce) {
  .welcome-in .up-kicker, .welcome-in h1 { animation: none; }
}

/* Full-screen splash: every login (routes/home.js justLoggedIn) — sits
   above everything, fades itself out, and stops intercepting clicks the
   moment it's gone. `pointer-events: none` unconditionally (not just
   after the animation ends) is deliberate belt-and-suspenders: if the
   fade-out animation ever gets frozen mid-way — e.g. a cold app launch
   backgrounding the tab while the CSS animation clock is paused, which
   installed-PWA standalone mode is more prone to than a normal browser
   tab — a stuck opaque overlay would otherwise block every tap on the
   page indefinitely, with no way to tell why. Losing the ability to
   click something *through* the splash during its brief on-screen
   window is a fine trade for never risking that. */
.welcome-splash {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--up-space-sm);
  text-align: center;
  pointer-events: none;
  animation: welcome-splash-out 0.7s ease-in 2.4s both;
}
.welcome-splash-mark { height: 56px; width: auto; margin-bottom: var(--up-space-md); }
.welcome-splash h1 { margin: 0; font-size: 48px; }
.welcome-splash-name { color: var(--up-neutral-300); font-size: 15px; }
@keyframes welcome-splash-out {
  0% { opacity: 1; visibility: visible; }
  99% { opacity: 0; visibility: visible; }
  100% { opacity: 0; visibility: hidden; }
}
@media (prefers-reduced-motion: reduce) {
  .welcome-splash { animation-duration: 0.01s; animation-delay: 0.6s; }
}

/* Stacked card entrance: same every-login gate as the splash — the
   cards land one after another as the splash clears, instead of all at
   once. Counts <section> only (:nth-of-type), so .home-greeting sitting
   above them as a <div> doesn't throw off the numbering. */
.home-sections.stack-in > section {
  animation: welcome-rise 0.7s ease-out both;
}
.home-sections.stack-in > section:nth-of-type(1) { animation-delay: 2.5s; }
.home-sections.stack-in > section:nth-of-type(2) { animation-delay: 2.85s; }
.home-sections.stack-in > section:nth-of-type(3) { animation-delay: 3.2s; }
.home-sections.stack-in > section:nth-of-type(4) { animation-delay: 3.55s; }
.home-sections.stack-in > section:nth-of-type(5) { animation-delay: 3.9s; }
@media (prefers-reduced-motion: reduce) {
  .home-sections.stack-in > section { animation: none; }
}

/* Home: a narrow sticky sidebar (same grid idiom as .docs-layout) so the
   quick-nav stays in view instead of scrolling away — jumping to Gear
   shouldn't mean scrolling all the way back up to jump anywhere else.
   Sits on the right (explicit grid-column, not DOM order — quick-nav
   stays first in the markup so it's still reached first via keyboard/
   screen reader, just painted in the second/right column). */
.home-layout {
  display: grid;
  grid-template-columns: 1fr 110px;
  gap: var(--up-space-xl);
  align-items: start;
  /* .content's own right padding (--up-space-md, 16px) is enough breathing
     room for a card edge but reads as cramped for a nav element sitting
     right at that boundary — especially at "in-between" desktop widths
     where .content's centering margin has mostly collapsed to zero and
     that 16px is all that's left. This adds a dedicated buffer so the
     quick-nav never sits flush against the window edge. */
  padding-right: var(--up-space-lg);
}
.quick-nav {
  grid-column: 2;
  /* Without an explicit row, auto-placement put quick-nav (col 2) and
     .home-sections (col 1) in separate rows instead of side by side —
     each still landed in its own column correctly, which is what made it
     look right horizontally, but .home-sections' row started a whole row-
     height below quick-nav's, stranding the "Hey, Mark." heading way down
     the page. Pinning both to row 1 keeps them on the same line. */
  grid-row: 1;
  position: sticky;
  top: var(--up-space-lg);
  /* Lines the first icon up with the first card's top edge rather than
     the kicker/h1 text beside it (~80px of heading the sidebar has no
     equivalent for). */
  margin-top: 80px;
  display: flex;
  flex-direction: column;
  gap: var(--up-space-lg);
}
.home-sections { grid-column: 1; grid-row: 1; }
/* JS (home.js) adds this to .home-layout once it confirms the page
   actually scrolls — default visible so the nav still works with JS
   disabled/slow to load. Collapsing the grid itself (not just hiding the
   nav) keeps .home-sections from sliding into the now-empty 110px track. */
.home-layout.quick-nav-hidden { grid-template-columns: 1fr; }
.home-layout.quick-nav-hidden .quick-nav { display: none; }
.quick-nav-item {
  display: flex;
  align-items: center;
  gap: var(--up-space-sm);
  color: var(--up-muted);
  text-decoration: none;
  font-size: var(--up-text-caption);
  font-weight: var(--up-weight-semibold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.quick-nav-item svg { width: 20px; height: 20px; flex: none; }
.quick-nav-item:hover { color: var(--up-copper); }

/* Section heading + collapsed "add" form. The "+" trigger sits inline
   next to the heading; opening it drops the form onto its own full-width
   row via flex-wrap, so the list above it never shifts. */
.section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--up-space-sm);
}
.section-head h1, .section-head h2, .section-head h3 { margin: 0; flex: 1 1 auto; }
.section-head > details.collapse-form { flex: 0 0 auto; margin: 0; }
.section-head > details.collapse-form[open] { flex-basis: 100%; }
.section-head > details.collapse-form > summary {
  list-style: none;
  cursor: pointer;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 1px solid var(--up-line);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  line-height: 1;
  color: var(--up-muted);
  transition: transform 0.15s, color 0.15s, border-color 0.15s;
}
.section-head > details.collapse-form > summary::-webkit-details-marker { display: none; }
.section-head > details.collapse-form > summary:hover { color: var(--up-copper); border-color: var(--up-copper); }
.section-head > details.collapse-form[open] > summary {
  color: var(--up-copper);
  border-color: var(--up-copper);
  transform: rotate(45deg);
}
.section-head > details.collapse-form > form,
.section-head > details.collapse-form > .stack-inline,
.section-head > details.collapse-form > p { margin-top: var(--up-space-md); }

/* Gear */
.unconfirmed {
  font-size: var(--up-text-caption);
  font-weight: var(--up-weight-semibold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--up-copper);
  border: 1px dashed var(--up-copper);
  border-radius: var(--up-radius-sm);
  padding: 1px 6px;
}
.unconfirmed-stale {
  color: var(--up-danger);
  border-color: var(--up-danger);
}
.filter-bar { margin-bottom: var(--up-space-lg); }

.badge {
  display: inline-block;
  font-size: var(--up-text-caption);
  font-weight: var(--up-weight-bold);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--up-copper);
  border: 1px solid var(--up-copper);
  padding: 1px 8px;
  border-radius: var(--up-radius-sm);
}

/* Home sidebar on mobile: this has to come after the base .home-layout/
   .quick-nav rules (further up the file) to win the cascade at equal
   specificity — a second small mobile block here rather than folding
   into the one near the top. */
@media (max-width: 700px) {
  /* Single column again, so the explicit grid-column: 2/1 placement below
     (desktop-only in effect: with a single track defined, an explicit
     column 2 would otherwise generate its own implicit track and split
     the layout back into two narrow columns) resets to natural stacking. */
  .home-layout { grid-template-columns: 1fr; }
  .quick-nav, .home-sections { grid-column: auto; grid-row: auto; }
  /* min-width: 0 — a flex-wrap row's default min-width is its unwrapped
     (single-line) size, not its wrapped one, which otherwise forces this
     lone grid track wider than the viewport instead of actually wrapping. */
  .quick-nav { position: static; flex-direction: row; flex-wrap: wrap; gap: var(--up-space-md); margin-top: 0; min-width: 0; }
  /* Same "auto minimum" story, one level down: .home-sections is the
     other grid item sharing this track, and a wide My-Projects table
     (already made internally scrollable — see .table above) still
     bubbles its unscrolled max-content size up through this plain block
     wrapper unless it's told not to. Pre-existing, unrelated to the
     sidebar — just surfaced by checking mobile end to end. */
  .home-sections { min-width: 0; }
}

/* In-page confirm dialog (confirm.js) — replaces window.confirm()'s
   native OS-styled box with one in the app's own paper-on-ink language,
   for the same reason cards went paper: legibility and consistency, not
   a system alert that looks like it came from somewhere else. */
.confirm-dialog {
  border: none;
  border-radius: var(--up-radius);
  padding: var(--up-space-lg);
  background: var(--up-paper);
  color: var(--up-ink);
  max-width: 360px;
  width: calc(100% - 2 * var(--up-space-lg));
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.45);
}
.confirm-dialog::backdrop { background: color-mix(in srgb, var(--up-ink) 60%, transparent); }
.confirm-dialog-message { margin: 0 0 var(--up-space-lg); font-size: 15px; line-height: 1.4; }
.confirm-dialog-actions { display: flex; justify-content: flex-end; gap: var(--up-space-sm); }
.confirm-dialog .btn-ghost { border-color: color-mix(in srgb, var(--up-ink) 30%, var(--up-paper)); color: var(--up-ink); }

/* Avatar reposition dialog (avatar-crop.js) — same paper-on-ink language
   as confirm-dialog, pan/zoom a photo before it's uploaded. */
.avatar-crop-dialog {
  border: none;
  border-radius: var(--up-radius);
  padding: var(--up-space-lg);
  background: var(--up-paper);
  color: var(--up-ink);
  max-width: 360px;
  width: calc(100% - 2 * var(--up-space-lg));
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.45);
}
.avatar-crop-dialog::backdrop { background: color-mix(in srgb, var(--up-ink) 60%, transparent); }
.avatar-crop-dialog p { margin: 0 0 var(--up-space-md); font-size: 14px; }
.avatar-crop-stage {
  display: block;
  width: 260px;
  height: 260px;
  margin: 0 auto var(--up-space-md);
  border-radius: 50%;
  border: 2px solid var(--up-copper);
  touch-action: none;
  cursor: grab;
}
.avatar-crop-stage:active { cursor: grabbing; }
.avatar-crop-zoom { display: block; width: 100%; margin: 0 0 var(--up-space-lg); accent-color: var(--up-copper); }
.avatar-crop-actions { display: flex; justify-content: flex-end; gap: var(--up-space-sm); }
