/* Every reusable UI component in every state. See styleguide.html for a live
   catalog of all of these. */

/* ---- Buttons ------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  height: 40px;
  padding: 0 var(--space-4);
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 600;
  white-space: nowrap;
  text-decoration: none;
  transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.btn:disabled {
  opacity: 0.5;
}

.btn--primary {
  background: var(--brand);
  color: #ffffff;
}

.btn--primary:hover:not(:disabled) {
  background: var(--brand-strong);
}

.btn--secondary {
  background: var(--surface);
  color: var(--ink);
  border-color: var(--line);
}

.btn--secondary:hover:not(:disabled) {
  border-color: var(--muted);
}

.btn--ghost {
  background: transparent;
  color: var(--ink);
}

.btn--ghost:hover:not(:disabled) {
  background: var(--bg);
}

.btn--danger {
  background: var(--danger);
  color: #ffffff;
}

.btn--danger:hover:not(:disabled) {
  background: #b3262c;
}

.btn--sm {
  height: 32px;
  padding: 0 var(--space-3);
  font-size: var(--text-xs);
}

.icon-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-sm);
  background: transparent;
  border: 1px solid transparent;
  color: var(--ink);
}

.icon-btn:hover:not(:disabled) {
  background: var(--bg);
}

.btn--loading {
  position: relative;
  color: transparent !important;
  pointer-events: none;
}

.btn--loading::after {
  content: '';
  position: absolute;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 2px solid currentColor;
  border-top-color: transparent;
  color: inherit;
  animation: btn-spin 0.6s linear infinite;
}

.btn--primary.btn--loading::after,
.btn--danger.btn--loading::after {
  color: #ffffff;
}

.btn--secondary.btn--loading::after,
.btn--ghost.btn--loading::after {
  color: var(--ink);
}

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

/* ---- Forms ------------------------------------------------------------------------ */

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

/* A same-specificity author rule like the one above otherwise beats the UA
   stylesheet's [hidden] { display: none }, so toggling .hidden on a .field
   (conditional filter fields, position-dependent fields) silently does nothing. */
.field[hidden] {
  display: none;
}

.field__label {
  font-size: var(--text-sm);
  font-weight: 600;
}

.field__help {
  font-size: var(--text-xs);
  color: var(--muted);
}

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

.input, .select, .textarea {
  width: 100%;
  height: 40px;
  padding: 0 var(--space-3);
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  /* The size scale's own --text-md step (16px), not a new value -- this is
     the one piece of text a person is actually typing into, so it gets the
     same size as plain body prose rather than the smaller --text-sm tier
     dense, secondary content (table cells, captions) deliberately keeps. */
  font-size: var(--text-md);
}

.textarea {
  height: auto;
  min-height: 96px;
  padding: var(--space-2) var(--space-3);
  resize: vertical;
}

/* A small supplementary box (e.g. "anything the system missed?") next to a
   larger, already-composed summary -- shorter than the default so it
   doesn't visually compete with the real content above it. */
.textarea--sm {
  min-height: 48px;
}

/* A field meant to read as the primary thing on the page even though it
   sits lower down -- size and emphasis carry that weight, not position
   (the Daily Scrum form's own Blockers field is the reason this exists). */
.textarea--lg {
  min-height: 140px;
}

.select {
  appearance: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236E6669' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
  background-repeat: no-repeat;
  background-position: right var(--space-3) center;
  padding-right: var(--space-6);
}

.input:hover, .select:hover, .textarea:hover {
  border-color: var(--muted);
}

.input:focus-visible, .select:focus-visible, .textarea:focus-visible {
  border-color: var(--focus-ring);
}

.field--error .input,
.field--error .select,
.field--error .textarea {
  border-color: var(--danger);
}

.input:disabled, .select:disabled, .textarea:disabled {
  background: var(--bg);
  color: var(--muted);
}

.checkbox, .radio {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-sm);
}

.checkbox input, .radio input {
  width: 18px;
  height: 18px;
  accent-color: var(--brand);
}

/* ---- Badges ---------------------------------------------------------------------------- */

.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  height: 22px;
  padding: 0 var(--space-2);
  border-radius: 999px;
  font-size: var(--text-xs);
  font-weight: 600;
  white-space: nowrap;
}

.badge--neutral { background: var(--bg); color: var(--muted); }

/* Task status */
.badge--status-todo { background: var(--bg); color: var(--muted); }
.badge--status-in_progress { background: var(--tint-blue); color: var(--status-in-progress); }
.badge--status-in_review { background: var(--tint-amber); color: var(--status-in-review); }
.badge--status-done { background: var(--tint-green); color: var(--status-done); }

/* Priority */
.badge--priority-low { background: var(--bg); color: var(--muted); }
.badge--priority-medium { background: var(--tint-blue); color: var(--status-in-progress); }
.badge--priority-high { background: var(--tint-amber); color: var(--status-in-review); }
.badge--priority-urgent { background: var(--tint-red); color: var(--danger); }

/* Story point chip. Text color is --brand, not --brand-strong -- the dark
   maroon --brand-strong is unreadable as text on a dark tinted background
   (it was only ever meant for backgrounds/pressed-states); --brand is the
   one new vivid red tuned to work as text here. */
.badge--sp {
  background: var(--tint-brand);
  color: var(--brand);
  font-family: var(--font-heading);
}

.badge--sp-none {
  background: var(--bg);
  color: var(--muted);
  font-style: italic;
  font-weight: 500;
}

/* Load status */
.badge--load-underloaded { background: var(--tint-blue); color: var(--load-under); }
.badge--load-balanced { background: var(--tint-green); color: var(--load-balanced); }
.badge--load-at_limit { background: var(--tint-amber); color: var(--load-at-limit); }
.badge--load-overloaded { background: var(--tint-orange); color: var(--load-over); }
/* Not a fullness level -- a leader-set capacity of exactly 0 with nothing
   currently assigned (2026-10-21 correction). Deliberately neutral, not one
   of the three --load-* colors: CLAUDE.md's own design rule reserves those
   for actual workload status, and this isn't a point on that scale. */
.badge--load-no_capacity { background: var(--bg); color: var(--muted); }

/* The topbar's "TEST" badge (2026-10-23, 2026-10-11 incident response) --
   same amber tone as .badge--priority-high/.badge--status-in_review, since
   "you are not looking at the real database" is the same class of
   heads-up, never a load-status color (CLAUDE.md's own rule reserves
   --load-* for workload status alone). appShell.js never even creates this
   element when the real database is connected -- there is nothing here to
   hide, only something to show. */
.badge--env-test { background: var(--tint-amber); color: var(--status-in-review); }

/* ---- Tables ------------------------------------------------------------------------------ */

.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  /* Flex/grid items default to min-width: auto, which would let the table's
     intrinsic width push the whole page wider instead of scrolling in place. */
  min-width: 0;
}

.table {
  min-width: 100%;
}

.table th, .table td {
  text-align: left;
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--line);
  font-size: var(--text-sm);
}

.table th {
  font-size: var(--text-xs);
  color: var(--muted);
  font-weight: 600;
  background: var(--bg);
}

.table tr:last-child td {
  border-bottom: none;
}

.table tbody tr:hover {
  background: var(--bg);
}

/* ---- Tabs --------------------------------------------------------------------------------- */

.tabs__list {
  display: flex;
  gap: var(--space-2);
  border-bottom: 1px solid var(--line);
  overflow-x: auto;
  min-width: 0;
}

.tabs__tab {
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  padding: var(--space-3) var(--space-3);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--muted);
  flex-shrink: 0;
  white-space: nowrap;
}

.tabs__tab[aria-selected='true'] {
  color: var(--brand);
  border-bottom-color: var(--brand);
}

.tabs__panel {
  padding-top: var(--space-4);
}

/* Reveal the new view OVER an opaque old view. Fading both to transparent
   would expose the dark page background between screens. */
::view-transition-group(root) {
  animation-duration: 0s;
}

::view-transition-old(root) {
  animation: none;
  opacity: 1;
  mix-blend-mode: normal;
}

::view-transition-new(root) {
  /* A paused one-step reveal holds the old view without a visible fade. */
  animation: view-content-reveal 1ms steps(1, end) both;
  mix-blend-mode: normal;
}

@keyframes view-content-reveal {
  from { opacity: 0; }
  to { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(root),
  ::view-transition-new(root) {
    animation-duration: 0.01ms;
  }
}

/* ---- Modal -------------------------------------------------------------------------------- */

.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(31, 26, 28, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  z-index: 100;
}

.modal {
  background: var(--surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  width: 100%;
  max-width: 480px;
  max-height: calc(100vh - var(--space-6));
  overflow-y: auto;
  padding: var(--space-5);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.modal--sm { max-width: 400px; }
.modal--lg { max-width: 720px; }

.modal__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
}

.modal__title {
  font-size: var(--text-lg);
}

.modal__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.modal__message {
  color: var(--muted);
}

.modal__footer {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-3);
}

/* ---- Drawer ------------------------------------------------------------------------------- */

.drawer-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(31, 26, 28, 0.45);
  z-index: 100;
  display: flex;
  justify-content: flex-end;
}

.drawer {
  width: 100%;
  max-width: 480px;
  height: 100%;
  background: var(--surface);
  box-shadow: var(--shadow-md);
  display: flex;
  flex-direction: column;
  animation: drawer-in 0.2s ease;
}

.drawer-backdrop.is-closing .drawer {
  animation: drawer-out 0.2s ease forwards;
}

@keyframes drawer-in {
  from { transform: translateX(100%); }
  to { transform: translateX(0); }
}

@keyframes drawer-out {
  from { transform: translateX(0); }
  to { transform: translateX(100%); }
}

@media (prefers-reduced-motion: reduce) {
  .drawer { animation: none; }
  .drawer-backdrop.is-closing .drawer { animation: none; }
}

.drawer__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-5);
  border-bottom: 1px solid var(--line);
}

.drawer__title {
  font-size: var(--text-lg);
}

.drawer__body {
  padding: var(--space-5);
  overflow-y: auto;
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

/* ---- Toast -------------------------------------------------------------------------------- */

.toast-region {
  position: fixed;
  bottom: var(--space-5);
  right: var(--space-5);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  z-index: 200;
  max-width: calc(100vw - var(--space-6));
}

.toast {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  background: var(--ink);
  color: #ffffff;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.15s ease, transform 0.15s ease;
  font-size: var(--text-sm);
}

.toast.is-visible {
  opacity: 1;
  transform: translateY(0);
}

.toast--error {
  background: var(--danger);
}

.toast--success {
  background: var(--load-balanced);
}

/* ---- Dropdown menu -------------------------------------------------------------------------- */

.dropdown-menu {
  /* top/left/max-height are set in JS (dropdown.js's position()) from the
     trigger's real on-screen position, clamped to the viewport -- see that
     file's header comment for why this can't be CSS-only. */
  position: fixed;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md);
  min-width: 180px;
  max-width: calc(100vw - var(--space-6));
  padding: var(--space-1);
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  z-index: 90;
}

.dropdown-menu__item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  background: transparent;
  border: none;
  text-align: left;
  font-size: var(--text-sm);
  color: var(--ink);
}

.dropdown-menu__item:hover {
  background: var(--bg);
}

.dropdown-menu__item--danger {
  color: var(--danger);
}

/* ---- Notifications popover ------------------------------------------------------------------ */

.dropdown-menu--notifications {
  width: 340px;
  max-width: calc(100vw - var(--space-6));
  max-height: 420px;
  padding: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.notif-popover__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--line);
}

.notif-popover__list {
  overflow-y: auto;
}

/* Used both as a <button> (the topbar popover) and, since 2026-10-24, as a
   real <a href> (the right panel's own list, navigating directly instead of
   needing a JS click handler) -- text-decoration: none is required for the
   <a> case specifically, the same class of gap this project's own .btn
   already hit (CLAUDE.md's Sprint 11/12 log: a link styled as a control
   needs this declared, never inherited by accident). Harmless on the
   <button> case, which never had an underline to begin with. */
.notif-item {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  width: 100%;
  padding: var(--space-3) var(--space-4);
  border: none;
  border-left: 3px solid transparent;
  border-bottom: 1px solid var(--line);
  background: transparent;
  text-align: left;
  text-decoration: none;
  color: inherit;
}

.notif-item:hover {
  background: var(--bg);
}

.notif-item--unread {
  background: var(--bg);
  border-left-color: var(--brand);
}

.notif-item__message {
  font-size: var(--text-sm);
  color: var(--ink);
}

.notif-item__time {
  font-size: var(--text-xs);
  color: var(--muted);
}

.notif-popover__empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-6) var(--space-4);
  color: var(--muted);
}

/* ---- Topbar notification badge --------------------------------------------------------------- */

.topbar__badge {
  position: absolute;
  top: 2px;
  right: 2px;
  min-width: 16px;
  height: 16px;
  padding: 0 3px;
  border-radius: 999px;
  background: var(--danger);
  color: #ffffff;
  font-size: 10px;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
}

/* ---- Avatar ------------------------------------------------------------------------------- */

.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--avatar-color, var(--muted));
  color: #ffffff;
  font-family: var(--font-heading);
  font-weight: 600;
  font-size: var(--text-xs);
  flex-shrink: 0;
}

.avatar--lg {
  font-size: var(--text-sm);
}

.avatar__photo {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: inherit;
  object-fit: cover;
}

/* ---- Member row (person + info + trailing badge, e.g. suggestions, team alerts) --------------- */

.member-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  padding: var(--space-2) 0;
  border: none;
  border-bottom: 1px solid var(--line);
  background: transparent;
  text-align: left;
}

.member-row:last-child {
  border-bottom: none;
}

.member-row__info {
  flex: 1;
  min-width: 0;
}

/* ---- Progress bar --------------------------------------------------------------------------- */

.progress-bar {
  height: 8px;
  border-radius: 999px;
  background: var(--line);
  overflow: hidden;
}

.progress-bar__fill {
  height: 100%;
  width: var(--fill, 0%);
  background: var(--brand);
  border-radius: 999px;
  transition: width 0.2s ease;
}

/* ---- Load meter (signature element) ---------------------------------------------------------- */

.load-meter {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.load-meter__top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
}

.load-meter__label {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  flex-wrap: wrap;
}

.load-meter__status {
  font-family: var(--font-heading);
  font-weight: 600;
  font-size: var(--text-sm);
  /* "No capacity this sprint" is notably longer than the three original
     status words -- without this, a narrow container breaks mid-phrase
     instead of wrapping the whole label to its own line (the parent
     .load-meter__label's flex-wrap already handles that cleanly). */
  white-space: nowrap;
}

.load-meter__status--underloaded { color: var(--load-under); }
.load-meter__status--balanced { color: var(--load-balanced); }
.load-meter__status--at_limit { color: var(--load-at-limit); }
.load-meter__status--overloaded { color: var(--load-over); }
.load-meter__status--no_capacity { color: var(--muted); }

.load-meter__numbers {
  font-size: var(--text-sm);
  color: var(--muted);
}

.load-meter__percent {
  font-family: var(--font-heading);
  font-weight: 600;
  font-size: var(--text-lg);
}

.load-meter__track {
  position: relative;
  height: 12px;
  border-radius: 999px;
  background: var(--bg);
  border: 1px solid var(--line);
  overflow: visible;
}

.load-meter__fill {
  position: absolute;
  inset: 0;
  width: var(--fill, 0%);
  border-radius: 999px;
  transition: width 0.3s ease;
}

.load-meter__fill--underloaded { background: var(--load-under); }
.load-meter__fill--balanced { background: var(--load-balanced); }
/* "At limit" (2026-10-25): amber WITH diagonal stripes. The stripes are a
   signal, not decoration -- an exception to the "no decorative gradients"
   rule on purpose: (1) a solid full bar reads as "complete," the opposite
   of "this person can't take another task"; (2) amber and the Overloaded
   orange are nearly the same color to a red-green colorblind reader
   (CIEDE2000 1.6 under deuteranopia), so the pattern, not the hue, is what
   separates them. Overloaded stays solid orange and runs past the tick. */
.load-meter__fill--at_limit {
  background:
    repeating-linear-gradient(-45deg, transparent 0 4px, rgba(0, 0, 0, 0.38) 4px 7px),
    var(--load-at-limit);
}
.load-meter__fill--overloaded { background: var(--load-over); }
.load-meter__fill--no_capacity { background: var(--muted); }

.load-meter__tick {
  position: absolute;
  top: -3px;
  bottom: -3px;
  left: var(--tick, 100%);
  width: 2px;
  background: var(--ink);
  opacity: 0.35;
}

.load-meter--sm .load-meter__track {
  height: 8px;
}

.load-meter--sm .load-meter__percent {
  font-size: var(--text-md);
}

/* ---- Assignee picker (assigneePicker.js) ------------------------------------------------------ */
/* A custom listbox that shows each member's current load next to their name.
   The bar reuses .load-meter__track / .load-meter__fill--<status>, so its
   colors (and the "At limit" stripes) are the load meter's own. */

.assignee-picker {
  position: relative;
  min-width: 0;
}

.assignee-picker__trigger {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  text-align: left;
  cursor: pointer;
}

.assignee-picker__trigger-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.assignee-picker__list {
  /* --assignee-picker-width is the trigger's width, set in JS on open. */
  width: max(var(--assignee-picker-width, 0px), 300px);
  margin: 0;
  list-style: none;
  gap: 2px;
}

.assignee-picker__option {
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.assignee-picker__option.is-active {
  background: var(--bg);
}

.assignee-picker__option[aria-selected='true'] {
  box-shadow: inset 2px 0 0 var(--brand);
}

.assignee-picker__option[aria-selected='true'] .assignee-picker__name {
  font-weight: 600;
}

.assignee-picker__no-avatar {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  color: var(--muted);
  background: var(--bg);
}

.assignee-picker__text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.assignee-picker__name,
.assignee-picker__status {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.assignee-picker__name {
  font-size: var(--text-sm);
  color: var(--ink);
}

.assignee-picker__status {
  font-size: var(--text-xs);
  font-weight: 600;
}

.assignee-picker__load {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-shrink: 0;
}

.assignee-picker__track {
  display: block;
  width: 56px;
  height: 6px;
}

.assignee-picker__percent {
  min-width: 4ch;
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--ink);
  text-align: right;
  white-space: nowrap;
}

.assignee-picker__load--trigger .assignee-picker__track {
  width: 40px;
}

@media (max-width: 420px) {
  .assignee-picker__track { width: 40px; }
  .assignee-picker__load--trigger .assignee-picker__track { display: none; }
}

/* ---- Empty state ---------------------------------------------------------------------------- */

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-3);
  padding: var(--space-7) var(--space-4);
  color: var(--muted);
}

.empty-state__icon {
  color: var(--muted);
}

.empty-state__title {
  color: var(--ink);
  font-size: var(--text-md);
  font-weight: 600;
}

/* ---- Skeleton loaders ------------------------------------------------------------------------ */

.skeleton {
  background: linear-gradient(90deg, var(--line) 25%, var(--skeleton-highlight) 37%, var(--line) 63%);
  background-size: 400% 100%;
  border-radius: var(--radius-sm);
  animation: skeleton-shimmer 1.4s ease infinite;
}

@keyframes skeleton-shimmer {
  0% { background-position: 100% 50%; }
  100% { background-position: 0 50%; }
}

@media (prefers-reduced-motion: reduce) {
  .skeleton {
    animation: none;
  }
}

.skeleton--text {
  height: 14px;
  width: 100%;
}

.skeleton--title {
  height: 22px;
  width: 40%;
}

.skeleton--avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
}

.skeleton--block {
  width: 100%;
  height: 96px;
}

/* ---- Charts ------------------------------------------------------------------------------------- */

.chart {
  width: 100%;
  height: auto;
  overflow: visible;
}

.chart__gridline {
  stroke: var(--line);
  stroke-width: 1;
}

.chart__axis-label {
  font-size: 10px;
  font-family: var(--font-body);
  fill: var(--muted);
}

.chart__line {
  stroke-width: 2;
}

.chart__line--primary {
  stroke: var(--brand);
}

.chart__line--secondary {
  stroke: var(--muted);
  stroke-dasharray: 4 3;
}

.chart__line--primary-dot {
  fill: var(--brand);
}

.chart__line--secondary-dot {
  fill: var(--muted);
}

.chart__bar {
  fill: var(--bar-color, var(--brand));
}

.chart__hbar-track {
  fill: var(--bg);
}

.chart__hbar {
  fill: var(--muted);
}

.chart__hbar--underloaded { fill: var(--load-under); }
.chart__hbar--balanced { fill: var(--load-balanced); }
.chart__hbar--at_limit { fill: var(--load-at-limit); }
.chart__hbar--overloaded { fill: var(--load-over); }

/* The same "At limit" stripes in SVG charts (charts.js appendCautionStripes). */
.chart__caution-stripe { fill: rgba(0, 0, 0, 0.38); }
.chart__caution-overlay { pointer-events: none; }
.chart__hbar--no_capacity { fill: var(--muted); }

.chart__hbar-threshold {
  stroke: var(--ink);
  stroke-width: 1.5;
  stroke-dasharray: 3 3;
  opacity: 0.5;
}

/* ---- Sparkline (stat tiles) and donut (capacity ring) -- 2026-10-24 ------------------------------- */

.chart--sparkline {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.chart__sparkline-line {
  stroke: var(--brand);
  stroke-width: 1.25;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}

.chart__sparkline-area {
  stroke: none;
}

.chart__donut-track {
  stroke: var(--line);
}

.chart__donut-segment {
  stroke: var(--segment-color, var(--brand));
}

.chart__donut-value {
  font-size: 22px;
  font-weight: 700;
  fill: var(--ink);
  font-family: var(--font-heading);
}

.chart__donut-label {
  font-size: 11px;
  fill: var(--muted);
}

/* ---- Stat tile (dashboard summary cards) -- 2026-10-24 -------------------------------------------- */

.stat-tile {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 0;
}

.stat-tile__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  color: var(--muted);
}

.stat-tile__label {
  font-size: var(--text-xs);
  font-weight: 600;
}

.stat-tile__icon {
  flex-shrink: 0;
}

.stat-tile__value {
  font-size: var(--text-2xl);
  font-weight: 700;
  font-family: var(--font-heading);
  line-height: 1.1;
}

.stat-tile__meta {
  font-size: var(--text-xs);
}

.stat-tile__spark {
  margin-top: var(--space-2);
  height: 32px;
}

/* ---- Progress track with a dot marker -- 2026-10-24 -------------------------------------------------
   Deliberately its own class family (.progress-track*), NOT a reuse/rename
   of the pre-existing .progress-bar/.progress-bar__fill (still used as-is
   by project.js, sprint-board.js, styleguide.js -- none of them touched
   this session). Those two classes share a name on purpose only; giving
   .progress-bar__fill a second, conflicting definition here would have
   silently broken every one of those untouched pages the moment this file
   loaded, since CSS resolves the later rule by source order regardless of
   which caller "meant" which shape -- caught before it shipped, not after. */

.progress-track {
  position: relative;
  height: 6px;
  border-radius: 999px;
  background: var(--line);
  overflow: visible;
}

.progress-track__fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--fill, 0%);
  border-radius: 999px;
  background: var(--brand);
}

.progress-track__dot {
  position: absolute;
  top: 50%;
  left: var(--pos, 0%);
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--brand);
  border: 2px solid var(--surface);
  transform: translate(-50%, -50%);
}

/* ---- Date chip -- 2026-10-24 ------------------------------------------------------------------------ */

.date-chip {
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-sm);
  background: var(--tint-red);
  color: var(--danger);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  line-height: 1.1;
}

.date-chip--overdue {
  background: var(--brand);
  color: #ffffff;
}

.date-chip__day {
  font-size: var(--text-md);
  font-weight: 700;
  font-family: var(--font-heading);
}

.date-chip__month {
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.04em;
}

/* ---- Task card ------------------------------------------------------------------------------------ */

.task-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.task-card:hover {
  border-color: var(--muted);
}

.task-card.is-dragging {
  opacity: 0.5;
}

/* Narrower board columns (sprint-board.css) mean a card can be squeezed.
   Everything inside wraps rather than pushing past the card's edge
   (CLAUDE.md's min-width: 0 rule, applied to the card's own children). */
.task-card {
  min-width: 0;
}

.task-card__top {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

.task-card__top .task-card__menu {
  margin-left: auto;
}

.task-card__title {
  font-size: var(--text-sm);
  font-weight: 600;
  overflow-wrap: anywhere;
}

.task-card__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}

.task-card__meta {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
}

.task-card__comments {
  display: inline-flex;
  align-items: center;
  gap: 2px;
}

/* ---- Sprint timeline ------------------------------------------------------------------------------ */

.timeline-scroll {
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  min-width: 0;
}

.timeline-grid {
  display: grid;
  grid-template-columns: 140px repeat(var(--day-count), minmax(36px, 1fr));
  min-width: max-content;
}

.timeline-row {
  display: contents;
}

.timeline-cell {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-height: 36px;
  padding: var(--space-1);
  border-bottom: 1px solid var(--line);
  font-size: var(--text-xs);
}

.timeline-cell--label {
  justify-content: flex-start;
  font-weight: 600;
  padding-left: var(--space-3);
  position: sticky;
  left: 0;
  background: var(--surface);
  border-right: 1px solid var(--line);
  z-index: 1;
}

.timeline-row--header .timeline-cell {
  font-weight: 600;
  border-bottom: 2px solid var(--line);
}

.timeline-cell--weekend {
  background: var(--bg);
}

.timeline-cell--today {
  background: var(--tint-amber);
  font-weight: 700;
}

.timeline-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 4px;
  font-size: 9px;
  font-weight: 700;
  color: #ffffff;
  background: var(--muted);
  flex-shrink: 0;
}

.timeline-chip--ceremony {
  background: var(--brand);
}

.timeline-chip--activity {
  background: var(--status-in-progress);
}

/* A member row's deadline lane: one CSS grid column per sprint day, so a
   task renders either as a single-day marker (no start date -- the
   original look) or a bar spanning its StartDate-to-DueDate range.
   grid-auto-flow: row dense lets the browser stack overlapping tasks into
   extra rows automatically, with no manual collision handling needed. */
.timeline-lane {
  display: grid;
  grid-template-columns: repeat(var(--day-count), minmax(36px, 1fr));
  grid-auto-flow: row dense;
  grid-auto-rows: 18px;
  align-items: center;
  gap: 2px 0;
  min-height: 36px;
  padding: var(--space-1) 0;
  border-bottom: 1px solid var(--line);
}

.timeline-marker {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
  justify-self: center;
}

.timeline-marker--todo { background: var(--muted); }
.timeline-marker--in_progress { background: var(--status-in-progress); }
.timeline-marker--in_review { background: var(--status-in-review); }
.timeline-marker--done { background: var(--status-done); }

.timeline-bar {
  display: flex;
  align-items: center;
  height: 16px;
  margin: 0 1px;
  padding: 0 4px;
  border-radius: 4px;
  font-size: 9px;
  font-weight: 600;
  color: #ffffff;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  justify-self: stretch;
}

.timeline-bar--todo { background: var(--muted); }
.timeline-bar--in_progress { background: var(--status-in-progress); }
.timeline-bar--in_review { background: var(--status-in-review); }
.timeline-bar--done { background: var(--status-done); }

/* ---- Panels / cards ---------------------------------------------------------------------------- */

.panel {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
}

/* ---- Story points picker ---------------------------------------------------------------------- */

.sp-picker {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.sp-chip {
  height: 36px;
  min-width: 36px;
  padding: 0 var(--space-3);
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font-size: var(--text-sm);
  font-weight: 600;
}

.sp-chip:hover {
  border-color: var(--muted);
}

.sp-chip--selected {
  background: var(--brand);
  border-color: var(--brand);
  color: #ffffff;
}

/* ---- Small caption-style label above a block of content ------------------------------------------ */

.eyebrow {
  font-size: var(--text-xs);
  color: var(--muted);
}

.divider {
  border: none;
  border-top: 1px solid var(--line);
  margin: 0;
}

/* ---- Comments ----------------------------------------------------------------------------------- */

.comment-row {
  display: flex;
  gap: var(--space-3);
}

.comment-row__body {
  flex: 1;
  min-width: 0;
}

/* One level of replies -- indented beneath their parent, same margin+border
   pattern .sidebar__subnav already uses elsewhere for indented lists. */
.comment-row--reply {
  margin-left: var(--space-6);
  padding-left: var(--space-3);
  border-left: 2px solid var(--line);
}

.comment-row__reply-form {
  margin-top: var(--space-2);
}

/* ---- Drag-and-drop -------------------------------------------------------------------------- */

/* Generic "this is a valid drop target right now" indicator for a draggable
   list/container (the sprint board's columns, sprint planning's backlog
   panes, and the merged project backlog's sections). A more specific
   selector (e.g. .backlog-row.is-drag-over) still wins at equal specificity
   by appearing later in the cascade, so per-element drop styling (like a
   row's own insertion-point border) isn't affected by this default. */
.is-drag-over {
  outline: 2px dashed var(--brand);
  outline-offset: -4px;
}

/* ---- Sprint capacity (capacity-based planning, Phase 2) ------------------------------------- */
/* Shared between sprint-planning.html and sprint-board.html -- the latter
   needs its own copy of this control because CLAUDE.md's own decision is
   that capacity stays editable once a sprint goes active, and
   sprint-planning.html redirects away from an active sprint entirely (the
   Sprint 10 switcher rule), so it can never be the only place this lives.
   Three states shown distinctly (never color alone, per CLAUDE.md's own
   rule): "not_set" and "zero" are muted/italic text, since neither
   represents active, confident information the way a real committed number
   does; "set" is plain, confident text. */
.sc-row {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-2) 0;
  border-top: 1px dashed var(--line);
}

.sc-state {
  font-size: var(--text-sm);
}

.sc-state--not_set,
.sc-state--zero {
  color: var(--muted);
  font-style: italic;
}

/* The member's own declared hours, read-only, right beside the leader's
   committed-points line (2026-10-21). Same text-sm weight as .sc-state, so
   it reads as an equally real fact, not a footnote; muted color since it's
   context, not a decision; italic only in the "hasn't declared yet" state,
   the same visual language .sc-state--not_set already uses for "nothing
   here yet" -- that absence is itself information a leader should notice. */
.sc-declared-hours {
  font-size: var(--text-sm);
  color: var(--muted);
}

.sc-declared-hours--not_set {
  font-style: italic;
}

.sc-controls {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
}

.sc-controls .input {
  max-width: 140px;
}

/* The declare-hours input's placeholder ("Hours you can give this sprint")
   is longer than the generic 140px .sc-controls .input rule was sized for
   -- confirmed by screenshot, not assumed: it visibly truncated to "Hours
   you ca...". Widened only for this one input, not the whole rule, since
   the points/reason inputs next to it are still correctly sized at 140px.
   Needs .sc-controls .input.sc-controls__hours-input, not just the bare
   class, to actually win -- .sc-controls .input alone is two classes
   (specificity 0,2,0) and would otherwise beat a plain one-class selector
   (0,1,0) regardless of source order, confirmed live by a screenshot that
   still showed the old 140px width before this fix. */
.sc-controls .input.sc-controls__hours-input {
  max-width: 220px;
}

/* Phase 3 -- honest, display-only additions to the capacity row. Neither
   is a status/load color (CLAUDE.md's load-color palette is reserved for
   workload status alone): .sc-warning reuses the same amber tone
   components.css already uses for other non-blocking warnings (e.g.
   sprint-planning's unassigned-task notice) since "this looks impossible"
   is the same class of heads-up; .sc-idle is deliberately quieter --
   having no active work right now is informational, not a problem. */
.sc-warning {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  background: var(--tint-amber);
  color: var(--status-in-review);
  font-size: var(--text-sm);
}

.sc-warning svg {
  flex-shrink: 0;
  margin-top: 2px;
}

.sc-idle {
  font-size: var(--text-xs);
  color: var(--muted);
}

/* Phase 5 -- the capacity-relief suggestion list. A section, not a modal:
   it sits inline right under the member whose overload it's addressing,
   consistent with every other capacity control on this panel. */
.cr-section {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.cr-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}

.cr-row__info {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
}

.cr-row__title {
  font-size: var(--text-sm);
  font-weight: 500;
}

.cr-row__action {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

.cr-row__action .input {
  max-width: 220px;
}

/* Task attachments: shared by the board and every task drawer entry point. */
.task-attachments__dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-4);
  border: 1px dashed var(--line);
  border-radius: var(--radius-sm);
}
.task-attachments__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.task-attachments__item {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}
.task-attachments__item > svg { flex-shrink: 0; }
.task-attachments__details { min-width: 0; flex: 1; }
.task-attachments__name { overflow-wrap: anywhere; font-weight: 600; }
.task-attachments__actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-2);
}

/* Task details: shared by every task drawer, without changing other drawers. */
.task-drawer { max-width: 570px; background: #121214; }
.task-drawer .drawer__header { padding: 18px 20px; min-height: 84px; }
.task-drawer .drawer__body { padding: 24px 20px; }
.task-drawer__title-group { min-width: 0; }
.task-drawer .drawer__title { margin-top: 6px; overflow-wrap: anywhere; }
.task-detail { display: flex; flex-direction: column; gap: 28px; }
.task-detail__section { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.task-detail__label {
  display: flex; align-items: center; gap: 6px; margin: 0;
  font-size: 11px; font-weight: 500; letter-spacing: 1px;
  text-transform: uppercase; color: var(--muted);
}
.task-detail__label svg { flex-shrink: 0; }
.task-detail__metadata, .task-detail__dates { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.task-detail__metadata .badge { border: 1px solid var(--line); border-radius: 6px; padding: 4px 10px; }
.task-detail__metadata .badge--sp { border-color: var(--brand-strong); }
.task-detail__dates { margin-left: 4px; }
.task-detail .btn { display: inline-flex; align-items: center; justify-content: center; gap: 6px; }
.task-detail .btn--secondary { background: #18181b; border-color: #29292e; }
.task-detail .btn--secondary:hover:not(:disabled) { background: #242429; border-color: #42424a; }
.task-detail .task-attachments { gap: 14px; }
.task-detail .task-attachments__dropzone { min-height: 110px; padding: 16px; border-radius: 12px; background: #151517; }
.task-detail .task-attachments__dropzone .btn { height: auto; min-height: 52px; flex-direction: column; width: 100%; gap: 10px; padding: 3px; border: 0; background: transparent; }
.task-detail .task-attachments__dropzone .btn svg { flex-shrink: 0; width: 22px; height: 22px; color: var(--muted); }
.task-detail .task-attachments > [role='status']:empty { display: none; }
.task-detail__status-controls { display: flex; flex-direction: column; align-items: flex-start; gap: 12px; }
.task-detail__status { border: 1px solid currentColor; border-radius: 999px; gap: 6px; }
.task-detail__status-dot { display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.task-detail__status-actions { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); width: 100%; gap: 8px; }
.task-detail__status-actions .btn { min-width: 0; padding: 8px 6px; font-size: 12px; border-radius: 9px; }
.task-detail__progress-heading { display: flex; align-items: center; justify-content: space-between; }
.task-detail__progress-value { font-size: 12px; color: var(--muted); }
.task-detail__slider {
  appearance: none; width: 100%; height: 6px; margin: 12px 0 8px;
  border-radius: 999px; cursor: pointer;
  background: linear-gradient(to right, #3b82f6 var(--progress, 0%), #29292c var(--progress, 0%));
}
.task-detail__slider::-webkit-slider-thumb {
  appearance: none; width: 16px; height: 16px; border-radius: 50%;
  background: #3b82f6; border: 0; box-shadow: 0 0 0 4px #263955;
}
.task-detail__slider::-moz-range-thumb { width: 16px; height: 16px; border-radius: 50%; background: #3b82f6; border: 0; box-shadow: 0 0 0 4px #263955; }
.task-detail__slider:disabled { opacity: 0.5; cursor: default; }
.task-detail__assignee { display: flex; align-items: center; gap: 12px; }
.task-detail__assignee .select { min-width: 0; flex: 1; border-radius: 9px; }
.task-detail__assignee .assignee-picker { flex: 1; }
.task-detail__assignee .assignee-picker .select { width: 100%; }
.task-detail__assign { flex-shrink: 0; min-height: 38px; }
.task-detail__unassigned { display: grid; place-items: center; width: 36px; height: 36px; flex: 0 0 36px; border-radius: 50%; color: var(--muted); background: #242429; }
.task-detail__edit { width: 100%; min-height: 42px; border-radius: 9px; }
.task-detail__comment-form { display: flex; flex-direction: column; gap: 14px; }
.task-detail .textarea { min-height: 86px; border-radius: 12px; background: #18181b; resize: vertical; }
.task-detail__post { width: 100%; min-height: 40px; border-radius: 8px; }
.task-detail .task-detail__post:disabled { opacity: 1; background: #646469; color: #1e1e22; border-color: transparent; }
.task-entry-list {
  max-height: var(--visible-entries-height, none); overflow-y: auto; overflow-x: hidden;
  overscroll-behavior-y: contain; scrollbar-width: thin; scrollbar-color: rgba(255, 255, 255, 0.16) transparent;
  scrollbar-gutter: stable;
}
.task-entry-list__items { display: flex; flex-direction: column; }
.task-comments .comment-row { padding: 12px 0; border-bottom: 1px solid var(--line); }
.task-comments .comment-row:first-child { padding-top: 0; }
.task-comments .comment-row__body { overflow-wrap: anywhere; }
.task-comments .comment-row__body > p:nth-child(2) { white-space: pre-wrap; margin-top: 6px; }
.task-comments .comment-row__body > .btn { padding-left: 0; margin-top: 4px; }
.task-comments .comment-row--reply { margin-left: 18px; padding-left: 10px; }
.task-history__entry { position: relative; margin-left: 4px; border-left: 1px solid #29292e; padding: 0 8px 16px 20px; overflow-wrap: anywhere; }
.task-history__entry::before { content: ''; position: absolute; left: -4px; top: 5px; width: 8px; height: 8px; border-radius: 50%; background: #29292e; border: 1px solid #45454c; }
.task-history__entry time { display: block; margin-top: 2px; }
@media (max-width: 420px) {
  .task-drawer .drawer__header, .task-drawer .drawer__body { padding-left: 16px; padding-right: 16px; }
  .task-detail__status-actions { grid-template-columns: 1fr; }
  .task-detail__assignee { gap: 8px; }
}
