/* ==========================================================================
   Components - Reusable UI Components
   ========================================================================== */

.component-playground-page {
  min-height: 100vh;
  background: var(--color-app-shell-bg);
}

/* Panel - Generic container */
.panel {
  background: var(--color-component-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
}

.panel--shadow {
  border: none;
  box-shadow: var(--shadow-lg);
}

/* Card - Content container */
.card {
  background: var(--color-component-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  overflow: hidden;
}

.card__header {
  padding: var(--space-4) var(--space-6);
  border-bottom: 1px solid var(--color-border);
}

.card__body {
  padding: var(--space-6);
}

.card__body:has(> table) {
  overflow-x: auto;
}

.card__footer {
  padding: var(--space-4) var(--space-6);
  border-top: 1px solid var(--color-border);
  background: var(--color-tinted-surface);
}

/* Alert - Flash messages */
.alert {
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
  margin-bottom: var(--space-4);
}

.alert--success {
  color: var(--color-success-text);
  background-color: var(--color-success-bg);
  border: 1px solid var(--color-success-border);
}

.alert--error {
  color: var(--color-danger-text);
  background-color: var(--color-danger-bg);
  border: 1px solid var(--color-danger-border);
}

.alert--warning {
  color: var(--color-warning-text);
  background-color: var(--color-warning-bg);
  border: 1px solid var(--color-warning-border);
}

.alert--info {
  color: var(--color-primary-text);
  background-color: var(--color-primary-bg);
  border: 1px solid var(--color-primary-border);
}

/* Auth Layout - Centered login/signup pages */
.auth-layout {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-6);
  padding: var(--space-8) var(--space-4);
  background: var(--color-tinted-surface);
}

.auth-panel {
  width: 100%;
  max-width: 24rem;
  background: var(--color-component-surface);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg);
  padding: var(--space-8);
}

.auth-panel__header {
  text-align: center;
  margin-bottom: var(--space-6);
}

.auth-panel__logo {
  height: 64px;
  width: auto;
  display: block;
  margin: 0 auto var(--space-3);
}

.auth-panel__logos {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
}

.auth-panel__logos .auth-panel__logo {
  margin: 0;
}

.auth-panel__logo--school {
  border-radius: var(--radius-lg);
  object-fit: contain;
}

.auth-panel__logo-sep {
  color: var(--color-ink-light);
  font-size: var(--text-xl);
  font-weight: var(--font-bold);
}

.auth-panel__title {
  font-size: var(--text-2xl);
  font-weight: var(--font-bold);
  margin-bottom: var(--space-2);
}

.auth-panel__subtitle {
  color: var(--color-ink-light);
  font-size: var(--text-sm);
}

.auth-panel__marketing-link {
  text-align: center;
  font-size: var(--text-sm);
  color: var(--color-ink-light);
  margin: 0 0 var(--space-4);
}

/* Dev quick-login picker (development only) */
.auth-dev-picker {
  width: 100%;
  max-width: 48rem;
  background: var(--color-component-surface);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg);
  padding: var(--space-6);
  border: 2px dashed var(--color-warning-400);
}

.auth-dev-picker__label {
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-warning-600);
  margin-bottom: var(--space-4);
}

/* Combobox — filtering single-select (see shared/_combobox) */
.combobox {
  position: relative;
  flex: 1;
  min-width: 0;
}

/* .card clips to its rounded corners, which would slice the menu off at the
   card's edge. Nothing paints into a card's corners but its own border, so
   opting the ones containing a combobox out of the clip costs nothing. */
.card:has(.combobox) {
  overflow: visible;
}

.combobox__input {
  width: 100%;
}

.combobox__menu {
  position: absolute;
  z-index: 50;
  top: calc(100% + var(--space-1));
  left: 0;
  right: 0;
  max-height: 18rem;
  overflow-y: auto;
  background: var(--color-component-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
}

.combobox__group-label {
  position: sticky;
  top: 0;
  padding: var(--space-1) var(--space-3);
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  color: var(--color-ink-light);
  background: var(--color-tinted-surface);
  border-bottom: 1px solid var(--color-border);
}

.combobox__option {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  width: 100%;
  padding: var(--space-2) var(--space-3);
  font-family: inherit;
  text-align: left;
  background: none;
  border: none;
  color: var(--color-ink);
  cursor: pointer;
}

/* display:flex above would otherwise beat the UA's [hidden] rule. */
.combobox__option[hidden] {
  display: none;
}

.combobox__option:hover,
.combobox__option--active {
  background: var(--color-primary-bg);
  color: var(--color-primary-text);
}

.combobox__option-label {
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
}

.combobox__option-meta {
  font-size: var(--text-xs);
  color: var(--color-ink-light);
  margin-left: auto;
  text-align: right;
}

.combobox__empty {
  padding: var(--space-3);
  font-size: var(--text-sm);
  color: var(--color-ink-light);
  text-align: center;
}

/* The box and its submit button. The label belongs above the whole row so the
   button can stretch to the input's height instead of guessing at it — .btn is
   a smaller font than an input, so bottom-aligning the two (the old
   `flex items-end`) left the button visibly short. */
.combobox-field {
  display: flex;
  align-items: stretch;
  gap: var(--space-2);
}

.combobox-field > .btn {
  flex: none;
  white-space: nowrap;
}

/* Badge */
.badge {
  display: inline-flex;
  align-items: center;
  padding: var(--space-1) var(--space-2);
  font-size: var(--text-xs);
  font-weight: var(--font-normal);
  border-radius: var(--radius-full);
  background: var(--color-gray-100);
  color: var(--color-ink-light);
  border: 1px solid transparent;
}

.badge--primary {
  background: var(--color-primary-100);
  color: var(--color-primary-700);
}

.badge--secondary {
  background: var(--color-secondary-100);
  color: var(--color-secondary-700);
}

.badge--warning {
  background: var(--color-warning-bg);
  color: var(--color-warning-700, #a16207);
  border-color: var(--color-warning-border);
}

.badge--success {
  background: var(--color-success-bg);
  color: var(--color-success-700);
}

.badge--danger {
  background: var(--color-danger-bg);
  color: var(--color-danger-700);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-color-scheme="light"]) .badge {
    background: transparent;
    border-color: var(--color-gray-600);
    color: var(--color-gray-300);
  }
  :root:not([data-color-scheme="light"]) .badge--primary {
    background: transparent;
    border-color: var(--color-primary-400);
    color: var(--color-primary-300);
  }
  :root:not([data-color-scheme="light"]) .badge--secondary {
    background: transparent;
    border-color: var(--color-secondary-600);
    color: color-mix(in srgb, var(--theme-secondary) 60%, white);
  }
  :root:not([data-color-scheme="light"]) .badge--success {
    background: transparent;
    border-color: var(--color-success-600);
    color: var(--color-success-500);
  }
  :root:not([data-color-scheme="light"]) .badge--danger {
    background: transparent;
    border-color: color-mix(in srgb, var(--color-danger-600) 60%, transparent);
    color: color-mix(in srgb, var(--color-danger-600) 80%, white);
  }
  :root:not([data-color-scheme="light"]) .badge--warning {
    background: transparent;
    border-color: color-mix(in srgb, var(--color-warning-500) 60%, transparent);
    color: color-mix(in srgb, var(--color-warning-500) 80%, white);
  }
  :root:not([data-color-scheme="light"]) .feed-filter__count {
    background: var(--color-gray-700);
    color: var(--color-gray-200);
  }
}

:root[data-color-scheme="dark"] .badge {
  background: transparent;
  border-color: var(--color-gray-600);
  color: var(--color-gray-300);
}
:root[data-color-scheme="dark"] .badge--primary {
  background: transparent;
  border-color: var(--color-primary-400);
  color: var(--color-primary-300);
}
:root[data-color-scheme="dark"] .badge--secondary {
  background: transparent;
  border-color: var(--color-secondary-600);
  color: color-mix(in srgb, var(--theme-secondary) 60%, white);
}
:root[data-color-scheme="dark"] .badge--success {
  background: transparent;
  border-color: var(--color-success-600);
  color: var(--color-success-500);
}
:root[data-color-scheme="dark"] .badge--danger {
  background: transparent;
  border-color: color-mix(in srgb, var(--color-danger-600) 60%, transparent);
  color: color-mix(in srgb, var(--color-danger-600) 80%, white);
}
:root[data-color-scheme="dark"] .badge--warning {
  background: transparent;
  border-color: color-mix(in srgb, var(--color-warning-500) 60%, transparent);
  color: color-mix(in srgb, var(--color-warning-500) 80%, white);
}
:root[data-color-scheme="dark"] .feed-filter__count {
  background: var(--color-gray-700);
  color: var(--color-gray-200);
}

/* Avatar */
.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: var(--radius-full);
  background: var(--color-primary-100);
  color: var(--color-primary-700);
  font-weight: var(--font-semibold);
  font-size: var(--text-sm);
}

/* Avatar group (iMessage-style stacked avatars) */
.avatar-group {
  position: relative;
  flex-shrink: 0;
  width: 3.5rem;
  height: 3.5rem;
}

.avatar-group__item {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--color-primary-600);
  color: white;
  font-weight: var(--font-semibold);
  box-shadow: 0 0 0 2px var(--color-surface);
  overflow: hidden;
}

.avatar-group__item--img {
  object-fit: cover;
  border-radius: 50%;
  box-shadow: 0 0 0 2px var(--color-surface);
}

.avatar-group__item--more {
  background: var(--color-gray-400);
  color: white;
  font-size: 0.75rem;
}

/* 1 avatar: centered, full size */
.avatar-group--1 .avatar-group__item,
.avatar-group--1 .avatar-group__item--img {
  width: 3.5rem;
  height: 3.5rem;
  font-size: var(--text-base);
  top: 0;
  left: 0;
}

/* 2 avatars: diagonal overlap */
.avatar-group--2 .avatar-group__item,
.avatar-group--2 .avatar-group__item--img {
  width: 2.25rem;
  height: 2.25rem;
  font-size: 0.75rem;
}
.avatar-group--2 .avatar-group__item:nth-child(1),
.avatar-group--2 .avatar-group__item--img:nth-child(1) { top: 0; left: 0; }
.avatar-group--2 .avatar-group__item:nth-child(2),
.avatar-group--2 .avatar-group__item--img:nth-child(2) { bottom: 0; right: 0; }

/* 3 avatars: 2 on top, 1 bottom center */
.avatar-group--3 .avatar-group__item,
.avatar-group--3 .avatar-group__item--img {
  width: 2rem;
  height: 2rem;
  font-size: 0.7rem;
}
.avatar-group--3 .avatar-group__item:nth-child(1),
.avatar-group--3 .avatar-group__item--img:nth-child(1) { top: 0; left: 0.125rem; }
.avatar-group--3 .avatar-group__item:nth-child(2),
.avatar-group--3 .avatar-group__item--img:nth-child(2) { top: 0; right: 0.125rem; }
.avatar-group--3 .avatar-group__item:nth-child(3),
.avatar-group--3 .avatar-group__item--img:nth-child(3) { bottom: 0; left: 50%; transform: translateX(-50%); }

/* 4+ avatars: 2x2 grid */
.avatar-group--4 .avatar-group__item,
.avatar-group--4 .avatar-group__item--img {
  width: 1.625rem;
  height: 1.625rem;
  font-size: 0.625rem;
}
.avatar-group--4 .avatar-group__item:nth-child(1),
.avatar-group--4 .avatar-group__item--img:nth-child(1) { top: 0; left: 0; }
.avatar-group--4 .avatar-group__item:nth-child(2),
.avatar-group--4 .avatar-group__item--img:nth-child(2) { top: 0; right: 0; }
.avatar-group--4 .avatar-group__item:nth-child(3),
.avatar-group--4 .avatar-group__item--img:nth-child(3) { bottom: 0; left: 0; }
.avatar-group--4 .avatar-group__item:nth-child(4),
.avatar-group--4 .avatar-group__item--img:nth-child(4) { bottom: 0; right: 0; }

/* Sidebar */
.app-shell {
  height: calc(100vh - var(--masquerade-banner-height, 0px));
  display: flex;
  background: var(--color-app-shell-bg);
  overflow: hidden;
}

.app-shell__content {
  flex: 1;
  min-width: 0;
  overflow-y: auto;
  z-index: 1;
}

.app-shell--demo {
  min-height: 26rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  overflow: hidden;
}

.sidebar {
  position: relative;
  z-index: 2;
  width: 18rem;
  background: var(--color-component-surface);
  border-right: 1px solid var(--color-border);
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  transition: width var(--transition-normal), transform var(--transition-normal);
}

.sidebar__scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overflow-anchor: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.sidebar::after {
  display: none;
}

.sidebar.is-collapsed {
  width: 5rem;
  overflow: hidden;
}

.sidebar.is-collapsed:hover,
.sidebar.is-collapsed:focus-within {
  overflow: visible;
}

.sidebar.is-collapsed .sidebar-label,
.sidebar.is-collapsed .sidebar-group-toggle,
.sidebar.is-collapsed .sidebar-subnav {
  display: none;
}

/* Hiding the labels leaves each item with one visible child, and
   `space-between` parks it against the left padding edge rather than in the
   middle of the rail. The notification bell centres itself, so it read as the
   misaligned one when its unread badge drew the eye to it. Centre them all. */
.sidebar.is-collapsed .sidebar-item {
  justify-content: center;
}

.sidebar__header {
  display: flex;
  align-items: center;
  justify-content: flex-start;
}

.sidebar__brand {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-weight: var(--font-semibold);
}

.sidebar__brand-mark {
  width: 5rem;
  height: 5rem;
  border-radius: var(--radius-md);
  background: linear-gradient(135deg, var(--brand-primary, var(--theme-primary)), var(--brand-secondary, var(--theme-secondary)));
  color: var(--color-white);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  flex: 0 0 auto;
}

.sidebar__brand-logo {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.sidebar__brand-name {
  text-align: left;
  font-size: 1.1rem;
  line-height: 1.5;
  font-family: var(--font-sans);
  font-weight: 500;
  color: var(--color-ink);
  padding-left: 5px;
}

.sidebar__brand-name--fallback {
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.sidebar.is-collapsed .sidebar__brand-mark {
  width: 2.5rem;
  height: 2.5rem;
}

.sidebar__collapse {
  position: absolute;
  top: 2rem;
  right: -0.875rem;
  z-index: 1;
  border: 1px solid var(--color-sidebar-handle-border);
  background: var(--color-sidebar-handle-bg);
  color: var(--color-white);
  width: 1.75rem;
  height: 3rem;
  border-radius: 0 var(--radius-lg) var(--radius-lg) 0;
  border-left: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-shadow: var(--sidebar-handle-shadow);
  cursor: pointer;
  transition: right var(--transition-normal), opacity var(--transition-fast), color var(--transition-fast), background-color var(--transition-fast);
}

.sidebar__collapse::before {
  content: "";
  display: block;
  width: 0.625rem;
  height: 1.75rem;
  border-radius: var(--radius-sm);
  background-image:
    repeating-linear-gradient(
      to bottom,
      color-mix(in srgb, var(--color-white) 55%, transparent) 0 2px,
      transparent 2px 5px
    );
  opacity: 1;
}

.sidebar__collapse::after {
  content: "";
  position: absolute;
  left: -0.75rem;
  top: 0;
  bottom: 0;
  width: 0.75rem;
}

.sidebar__collapse:hover {
  color: var(--color-white);
  background: var(--color-sidebar-handle-hover);
}

.sidebar__collapse svg {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 0.9rem;
  height: 0.9rem;
  transition: transform var(--transition-fast);
}

.sidebar.is-collapsed .sidebar__collapse {
  right: 0;
  opacity: 0;
  pointer-events: none;
}

.sidebar.is-collapsed .sidebar__collapse svg {
  transform: translate(-50%, -50%) rotate(180deg);
}

.sidebar.is-collapsed:hover .sidebar__collapse,
.sidebar.is-collapsed:focus-within .sidebar__collapse {
  opacity: 1;
  pointer-events: auto;
  right: -1.45rem;
}

.sidebar__collapse svg,
.sidebar-mobile-trigger svg,
.sidebar-item svg {
  width: 1rem;
  height: 1rem;
}

.sidebar__nav {
  display: grid;
  gap: var(--space-2);
}

.sidebar__footer {
  margin-top: auto;
  padding-top: var(--space-3);
  border-top: 1px solid var(--color-border);
}

.sidebar-admin {
  border: 1px solid color-mix(in srgb, var(--theme-primary) 30%, var(--color-component-surface));
  background: color-mix(in srgb, var(--theme-primary) 8%, var(--color-component-surface));
  border-radius: var(--radius-md);
  padding: var(--space-2);
}

.sidebar-admin__label {
  margin: 0 0 var(--space-2);
  font-size: var(--text-xs);
  color: var(--color-ink-light);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.sidebar-theme {
  margin-bottom: var(--space-2);
}

.sidebar-theme__label {
  margin: 0 0 var(--space-1);
  font-size: var(--text-xs);
  color: var(--color-ink-light);
}

.sidebar-theme__select {
  width: 100%;
  min-height: 2rem;
  padding: var(--space-1) var(--space-2);
  font-size: var(--text-xs);
}

.sidebar-admin__link {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  color: var(--color-primary-700);
  text-decoration: none;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
}

.sidebar-admin__link:hover {
  background: color-mix(in srgb, var(--theme-primary) 14%, var(--color-component-surface));
  text-decoration: none;
}

.sidebar__group {
  display: grid;
  gap: var(--space-1);
}

.sidebar-item {
  width: 100%;
  border: 0;
  background: transparent;
  color: var(--color-ink);
  text-decoration: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
}

.sidebar-item:focus {
  outline: none;
  box-shadow: none;
  -webkit-appearance: none;
}

.sidebar-item:hover {
  background: color-mix(in srgb, var(--theme-primary) 10%, var(--color-component-surface));
}

.sidebar-item__left {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

.sidebar-item__chevron {
  transition: transform var(--transition-fast);
  color: var(--color-ink-light);
}

.sidebar-group-toggle[aria-expanded="true"] .sidebar-item__chevron {
  transform: rotate(90deg);
}

.sidebar-item--parent {
  font-weight: var(--font-medium);
}

.sidebar-parent-row {
  display: flex;
  align-items: center;
  gap: var(--space-1);
}

.sidebar-parent-row > .sidebar-item--parent {
  flex: 1 1 auto;
  min-width: 0;
}

.sidebar-group-toggle {
  flex: 0 0 auto;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--color-ink-light);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background-color var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);
}

.sidebar-group-toggle:hover,
button.sidebar-feed-row__bell:hover {
  border-color: color-mix(in srgb, var(--theme-primary) 40%, var(--color-border));
  background: color-mix(in srgb, var(--theme-primary) 14%, var(--color-component-surface));
  color: var(--color-ink);
}

.sidebar-group-toggle:focus-visible,
button.sidebar-feed-row__bell:focus-visible {
  border-color: color-mix(in srgb, var(--theme-primary) 40%, var(--color-border));
  background: color-mix(in srgb, var(--theme-primary) 14%, var(--color-component-surface));
  color: var(--color-ink);
  outline: 2px solid var(--color-accent, var(--theme-primary));
  outline-offset: 2px;
}

.sidebar-group-toggle .sidebar-item__chevron {
  font-size: 1.25rem;
  line-height: 1;
}

/* Expand/collapse-all divider. Sits in the nav flow just under the school row,
   drawn as a centred label between two rules so it reads as a separator acting
   on everything below it rather than as another nav destination. */
.sidebar__bulk-toggle {
  display: flex;
}

/* Beats the `display: flex` above, which would otherwise defeat the `hidden`
   attribute the controller uses to drop this row for single-group navs. */
.sidebar__bulk-toggle[hidden] {
  display: none;
}

.sidebar-bulk-toggle {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  padding: var(--space-1) var(--space-2);
  border: 0;
  background: transparent;
  color: var(--color-ink-light);
  font-size: var(--text-xs);
  font-weight: var(--font-medium);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color var(--transition-fast);
}

/* The rules. They flex, so the label stays centred whatever its length — and it
   changes length, "Expand All" vs "Collapse All". */
.sidebar-bulk-toggle::before,
.sidebar-bulk-toggle::after {
  content: "";
  flex: 1 1 auto;
  height: 1px;
  background: var(--color-border);
  transition: background-color var(--transition-fast);
}

.sidebar-bulk-toggle:hover {
  color: var(--color-ink);
}

.sidebar-bulk-toggle:hover::before,
.sidebar-bulk-toggle:hover::after {
  background: color-mix(in srgb, var(--theme-primary) 40%, var(--color-border));
}

.sidebar-bulk-toggle:focus-visible {
  color: var(--color-ink);
  outline: 2px solid var(--color-accent, var(--theme-primary));
  outline-offset: 2px;
  border-radius: var(--radius-md);
}

/* The rail has no room for it, and there are no visible subnavs to fold. */
.sidebar.is-collapsed .sidebar__bulk-toggle {
  display: none;
}

/* Feed row: the "Feed" link plus a compact notifications bell on the right. */
.sidebar-feed-row {
  display: flex;
  align-items: center;
  gap: var(--space-1);
}
.sidebar-feed-row__feed {
  flex: 1 1 auto;
}
.sidebar-feed-row__bell {
  position: relative;
  flex: 0 0 auto;
  width: auto;
}
.sidebar-feed-row__bell.has-unread {
  color: var(--color-danger-600);
}

/* The badge always renders so the bell's JS can toggle it; the class rule below
   would otherwise beat the UA's [hidden] { display: none }. */
.sidebar-unread-badge[hidden] {
  display: none;
}

.sidebar-unread-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.25rem;
  height: 1.25rem;
  padding: 0 0.375rem;
  font-size: 0.6875rem;
  font-weight: 700;
  line-height: 1;
  color: var(--color-white);
  background: var(--color-danger-600);
  border-radius: var(--radius-full);
}

.sidebar.is-collapsed .sidebar-unread-badge {
  position: absolute;
  top: 0.25rem;
  right: 0.25rem;
  min-width: 0.5rem;
  height: 0.5rem;
  padding: 0;
  font-size: 0;
}

.sidebar-item--child {
  color: var(--color-ink-light);
}

.sidebar-item--grandchild {
  padding-left: calc(var(--space-6) + var(--space-2));
  color: var(--color-ink-light);
}

.sidebar-subnav {
  display: grid;
  gap: var(--space-1);
  padding-left: var(--space-2);
  border-left: 1px solid var(--color-border);
  margin-left: var(--space-2);
}

.sidebar-subnav.is-folding {
  overflow: hidden;
  will-change: height, opacity;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-color-scheme="light"]) .sidebar-item {
    color: var(--color-gray-200);
  }

  :root:not([data-color-scheme="light"]) .sidebar-item--child,
  :root:not([data-color-scheme="light"]) .sidebar-item--grandchild {
    color: var(--color-gray-300);
  }

  :root:not([data-color-scheme="light"]) .sidebar-item__chevron {
    color: var(--color-gray-400);
  }

  :root:not([data-color-scheme="light"]) .sidebar-admin__label,
  :root:not([data-color-scheme="light"]) .sidebar-theme__label {
    color: var(--color-gray-400);
  }

  :root:not([data-color-scheme="light"]) .sidebar-admin__link {
    color: var(--color-gray-300);
  }

  :root:not([data-color-scheme="light"]) .sidebar__brand-name {
    color: var(--color-gray-100);
  }

  :root:not([data-color-scheme="light"]) .sidebar-subnav {
    border-left-color: var(--color-gray-600);
  }
}

:root[data-color-scheme="dark"] .sidebar-item {
  color: var(--color-gray-200);
}

:root[data-color-scheme="dark"] .sidebar-item--child,
:root[data-color-scheme="dark"] .sidebar-item--grandchild {
  color: var(--color-gray-300);
}

:root[data-color-scheme="dark"] .sidebar-item__chevron {
  color: var(--color-gray-400);
}

:root[data-color-scheme="dark"] .sidebar-admin__label,
:root[data-color-scheme="dark"] .sidebar-theme__label {
  color: var(--color-gray-400);
}

:root[data-color-scheme="dark"] .sidebar-admin__link {
  color: var(--color-gray-300);
}

:root[data-color-scheme="dark"] .sidebar__brand-name {
  color: var(--color-gray-100);
}

:root[data-color-scheme="dark"] .sidebar-subnav {
  border-left-color: var(--color-gray-600);
}

.sidebar-subnav[hidden] {
  display: none;
}

.sidebar-mobile-trigger {
  display: none;
}

.sidebar-overlay {
  display: none;
}

body.has-mobile-sidebar {
  overflow: hidden;
}

.toast-stack {
  position: fixed;
  bottom: var(--space-4);
  right: var(--space-4);
  width: min(24rem, calc(100vw - var(--space-8)));
  z-index: 1000;
  display: grid;
  gap: var(--space-2);
}

.toast {
  margin-bottom: 0;
  box-shadow: var(--shadow-lg);
  animation: toast-fade-in 240ms ease-out;
  transition: opacity 220ms ease, transform 220ms ease;
}

.toast.is-dismissing {
  opacity: 0;
  transform: translateY(8px);
}

@keyframes toast-fade-in {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@media (max-width: 640px) {
  .toast-stack {
    bottom: var(--space-3);
    left: var(--space-3);
    right: var(--space-3);
    width: auto;
  }
}

/* Admin-only floating environment switcher. The panel is tinted per
   environment so the current one is obvious at a glance: purple local,
   red dev, green production. */
.env-switcher {
  position: fixed;
  bottom: var(--space-4);
  left: 50%;
  transform: translateX(-50%);
  z-index: 2000;
  display: flex;
  gap: var(--space-2);
  padding: var(--space-2);
  border-radius: var(--radius-xl);
  background: var(--env-bg);
  box-shadow: var(--shadow-lg);
  backdrop-filter: blur(6px);
  opacity: 0.75;
  transition: opacity 0.15s ease;
}

.env-switcher:hover,
.env-switcher:focus-within {
  opacity: 1;
}

.env-switcher--local {
  --env-bg: rgba(168, 85, 247, 0.55);
  --env-fg: #fff;
}

.env-switcher--dev {
  --env-bg: rgba(220, 38, 38, 0.45);
  --env-fg: #fff;
}

.env-switcher--prod {
  --env-bg: rgba(163, 230, 53, 0.6);
  --env-fg: #111;
}

.env-switcher__item {
  padding: var(--space-1) var(--space-4);
  border: 1px solid color-mix(in srgb, var(--env-fg) 35%, transparent);
  border-radius: var(--radius-lg);
  color: color-mix(in srgb, var(--env-fg) 60%, transparent);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  line-height: 1.6;
  white-space: nowrap;
}

.env-switcher__item:hover {
  border-color: color-mix(in srgb, var(--env-fg) 70%, transparent);
  color: var(--env-fg);
  text-decoration: none;
}

.env-switcher__item--current {
  border-color: var(--env-fg);
  color: var(--env-fg);
}

.env-switcher__item--disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

@media print {
  .env-switcher {
    display: none;
  }
}

@media (max-width: 768px) {
  .app-shell--demo .sidebar-mobile-trigger,
  .app-shell--demo .sidebar-overlay {
    display: none;
  }

  .app-shell--demo .sidebar {
    position: relative;
    inset: auto;
    width: 18rem;
    transform: none;
    border-right: 1px solid var(--color-border);
    box-shadow: none;
  }

  .app-shell--demo.is-mobile-open .sidebar {
    transform: none;
  }

  .sidebar-mobile-trigger {
    position: fixed;
    top: var(--space-4);
    left: var(--space-4);
    z-index: 1300;
    display: inline-flex;
    width: 2.5rem;
    height: 2.5rem;
    border-radius: var(--radius-md);
    border: 1px solid var(--color-border);
    background: var(--color-component-surface);
    color: var(--color-ink);
    align-items: center;
    justify-content: center;
    box-shadow: var(--shadow-md);
  }

  .sidebar-overlay {
    position: fixed;
    inset: 0;
    background: rgb(0 0 0 / 0.35);
    border: 0;
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--transition-normal);
    z-index: 1200;
  }

  .app-shell.is-mobile-open .sidebar-overlay {
    display: block;
    opacity: 1;
    pointer-events: auto;
  }

  .sidebar {
    position: fixed;
    inset: 0;
    z-index: 1250;
    width: 100vw;
    transform: translateX(-100%);
    border-right: 0;
    box-shadow: var(--shadow-lg);
  }

  .app-shell.is-mobile-open .sidebar {
    transform: translateX(0);
  }

  .sidebar__collapse {
    display: none;
  }
}

.theme-preview {
  background: var(--color-component-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  overflow: hidden;
}

.theme-preview__swatches {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  min-height: 4rem;
}

.theme-preview__swatch--primary { background: var(--theme-primary); }
.theme-preview__swatch--secondary { background: var(--theme-secondary); }
.theme-preview__swatch--surface { background: var(--theme-surface-tint); }

.theme-preview__body {
  padding: var(--space-3);
  background: var(--theme-surface-tint);
}

.theme-preview__chip {
  display: inline-block;
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-full);
  font-size: var(--text-xs);
  color: var(--color-white);
  background: var(--theme-primary);
}

.avatar--sm {
  width: 2rem;
  height: 2rem;
  font-size: var(--text-xs);
}

.avatar--lg {
  width: 3rem;
  height: 3rem;
  font-size: var(--text-base);
}

/* Toggle Switch */
.switch {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  cursor: pointer;
  width: fit-content;
}

.switch__input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
  pointer-events: none;
}

.switch__track {
  width: 2.75rem;
  height: 1.5rem;
  border-radius: var(--radius-full);
  background: var(--color-switch-track-off);
  border: 1px solid var(--color-border-dark);
  display: inline-flex;
  align-items: center;
  padding: 0.125rem;
  transition: background-color var(--transition-fast), border-color var(--transition-fast);
}

.switch__thumb {
  width: 1.125rem;
  height: 1.125rem;
  border-radius: var(--radius-full);
  background: var(--color-switch-thumb);
  box-shadow: var(--shadow-sm);
  transform: translateX(0);
  transition: transform var(--transition-fast);
}

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

.switch__input:checked + .switch__track {
  background: var(--color-primary-600);
  border-color: var(--color-primary-700);
}

.switch__input:checked + .switch__track .switch__thumb {
  transform: translateX(1.25rem);
}

.switch__input:focus-visible + .switch__track {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--theme-primary) 35%, transparent);
}

.switch__input:disabled + .switch__track {
  opacity: 0.6;
}

.switch__input:disabled ~ .switch__label {
  color: var(--color-ink-light);
}

.switch:has(.switch__input:disabled) {
  cursor: not-allowed;
}

/* Masquerade Banner */
.masquerade-shell {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 2000;
}

.masquerade-banner {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-4);
  background: var(--color-warning-600);
  color: var(--color-white);
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
}

.masquerade-banner__stop {
  padding: var(--space-1) var(--space-3);
  font-size: var(--text-xs);
  background: rgba(255, 255, 255, 0.2);
  border: 1px solid rgba(255, 255, 255, 0.4);
  color: var(--color-white);
  border-radius: var(--radius-md);
  cursor: pointer;
}

.masquerade-banner__stop:hover {
  background: rgba(255, 255, 255, 0.35);
}

.masquerade-banner__switch {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}

.masquerade-banner__switch svg {
  width: 0.875rem;
  height: 0.875rem;
  transition: transform var(--transition-normal);
}

.masquerade-shell.is-open .masquerade-banner__switch svg {
  transform: rotate(180deg);
}

.persona-drawer {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  display: grid;
  grid-template-rows: 0fr;
  pointer-events: none;
  transition: grid-template-rows var(--transition-normal);
}

.masquerade-shell.is-open .persona-drawer {
  grid-template-rows: 1fr;
  pointer-events: auto;
}

.persona-drawer__clip {
  min-height: 0;
  overflow: hidden;
}

.persona-drawer__panel {
  width: min(680px, calc(100vw - 2rem));
  max-height: calc(100vh - var(--masquerade-banner-height));
  margin: 0 auto;
  padding: var(--space-5);
  overflow-y: auto;
  color: var(--color-ink);
  background: var(--color-component-surface);
  border: 2px solid var(--color-warning-600);
  border-top: 0;
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
  box-shadow: var(--shadow-lg);
  transform: translateY(-0.75rem);
  opacity: 0;
  transition: transform var(--transition-normal), opacity var(--transition-fast);
}

.masquerade-shell.is-open .persona-drawer__panel {
  transform: translateY(0);
  opacity: 1;
}

.persona-drawer__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-4);
}

.persona-drawer__header h2 {
  margin: 0;
  font-size: var(--text-xl);
}

.persona-drawer__header p {
  margin: var(--space-1) 0 0;
  color: var(--color-ink-light);
  font-size: var(--text-sm);
}

.persona-drawer__close {
  border: 0;
  padding: 0;
  background: transparent;
  color: var(--color-ink-light);
  font-size: var(--text-2xl);
  line-height: 1;
  cursor: pointer;
}

.persona-options {
  display: grid;
  gap: var(--space-4);
}

.persona-option__body {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
}

.persona-option__label {
  margin: 0;
  font-size: var(--text-lg);
  font-weight: var(--font-semibold);
}

.persona-option__name {
  margin: 0;
  color: var(--color-ink-light);
}

.persona-option__status {
  color: var(--color-ink-light);
  font-weight: var(--font-medium);
}

/* The already-selected persona pairs its label with a way into the app — every
   other row gets there by switching. */
.persona-option__actions {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex: 0 0 auto;
}

.persona-options--drawer {
  gap: var(--space-2);
}

.persona-options--drawer .persona-option__body {
  padding: var(--space-3) var(--space-4);
}

.persona-options--drawer .persona-option__label {
  font-size: var(--text-base);
}

.persona-options--drawer .persona-option__name,
.persona-options--drawer .persona-option__status {
  font-size: var(--text-sm);
}

body:has(.masquerade-shell) {
  padding-top: 2.5rem;
  --masquerade-banner-height: 2.5rem;
}

@media (prefers-reduced-motion: reduce) {
  .persona-drawer,
  .persona-drawer__panel,
  .masquerade-banner__switch svg {
    transition: none;
  }
}

/* Masquerade Picker */
.masquerade-picker__wrapper {
  position: relative;
}

.masquerade-picker__input {
  width: 100%;
  min-height: 2rem;
  padding: var(--space-1) var(--space-2);
  font-size: var(--text-xs);
}

.masquerade-picker__dropdown {
  position: absolute;
  bottom: 100%;
  left: 0;
  right: 0;
  max-height: 15rem;
  overflow-y: auto;
  background: var(--color-component-surface);
  border: 1px solid var(--color-border-dark);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  margin-bottom: var(--space-1);
  z-index: 100;
}

.masquerade-picker__result {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0;
  padding: var(--space-2);
  border: 0;
  background: transparent;
  color: var(--color-ink);
  cursor: pointer;
  text-align: left;
  font-size: var(--text-xs);
  border-radius: 0;
}

.masquerade-picker__result:hover {
  background: var(--color-primary-bg);
}

.masquerade-picker__result + .masquerade-picker__result {
  border-top: 1px solid var(--color-border);
}

.masquerade-picker__result-name {
  font-weight: var(--font-medium);
  color: var(--color-ink);
}

.masquerade-picker__result-email {
  color: var(--color-ink-light);
  font-size: var(--text-xs);
}

.masquerade-picker__empty {
  padding: var(--space-3);
  text-align: center;
  color: var(--color-ink-light);
  font-size: var(--text-xs);
}

.masquerade-picker__active {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-2);
  background: color-mix(in srgb, var(--color-warning-600) 15%, var(--color-component-surface));
  border: 1px solid color-mix(in srgb, var(--color-warning-600) 30%, var(--color-border));
  border-radius: var(--radius-md);
  min-height: 2rem;
}

.masquerade-picker__active-name {
  font-size: var(--text-xs);
  font-weight: var(--font-medium);
  color: var(--color-ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.masquerade-picker__stop-btn {
  padding: 0.125rem var(--space-2);
  font-size: 0.625rem;
  background: var(--color-danger-600);
  color: var(--color-white);
  border: 0;
  border-radius: var(--radius-md);
  cursor: pointer;
  white-space: nowrap;
}

.masquerade-picker__stop-btn:hover {
  background: var(--color-danger-700);
}

/* Activity Feed */
.feed-page {
  max-width: 64rem;
  margin: 0 auto;
  padding: var(--space-6);
}

@media (min-width: 1600px) {
  .feed-page {
    max-width: 80rem;
  }
}

@media (min-width: 2000px) {
  .feed-page {
    max-width: 96rem;
  }
}

.feed-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}

.feed-header__title {
  font-family: var(--font-heading);
  font-size: var(--text-2xl);
  font-weight: var(--font-bold);
  margin: 0;
}

.feed-header__subtitle {
  font-size: var(--text-sm);
  color: var(--color-ink-light);
  margin: var(--space-1) 0 0;
}

/* The sources feeding a combined feed (each class/group), as linked chips
   under the title. Wraps rather than scrolls — the list is short and stable. */
.feed-header__badges {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-2);
}

.feed-badge {
  text-decoration: none;
  transition: background 0.15s ease, color 0.15s ease;
}

.feed-badge:hover,
.feed-badge:focus-visible {
  background: var(--color-primary-100);
  color: var(--color-primary-700);
}

.feed-filters {
  display: flex;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
  border-bottom: 1px solid var(--color-border);
  padding-bottom: var(--space-3);
  overflow-x: auto;
  flex-wrap: nowrap;
  scrollbar-width: thin;
  -webkit-overflow-scrolling: touch;
}

.feed-search {
  display: flex;
  gap: var(--space-2);
  align-items: center;
  margin-bottom: var(--space-4);
}

.feed-search__input {
  flex: 1;
  min-width: 0;
}

.feed-search__clear {
  font-size: var(--text-sm);
  color: var(--color-ink-light);
}

.feed-filter {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-3);
  font-size: var(--text-sm);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  background: var(--color-component-surface);
  color: var(--color-ink-light);
  cursor: pointer;
  transition: all var(--transition-fast);
  white-space: nowrap;
  flex-shrink: 0;
}

.feed-filter:hover {
  border-color: var(--color-primary-300);
  color: var(--color-ink);
  background: color-mix(in srgb, var(--theme-primary) 10%, var(--color-component-surface));
}

.feed-filter--active {
  background: var(--theme-primary);
  border-color: var(--theme-primary);
  color: var(--color-white);
  font-weight: var(--font-medium);
  cursor: default;
}

.feed-filter__count {
  font-size: var(--text-xs);
  background: var(--color-gray-100);
  padding: 0 var(--space-1);
  border-radius: var(--radius-full);
  min-width: 1.25rem;
  text-align: center;
  flex-shrink: 0;
}

.feed-filter--active .feed-filter__count {
  background: rgba(255, 255, 255, 0.25);
  color: var(--color-white);
}

/* Store cart button + dropdown panel */
.store-cart {
  position: relative;
  display: inline-block;
}
.store-cart__trigger {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3.25rem;
  height: 3.25rem;
  background: var(--color-component-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  cursor: pointer;
  color: var(--color-ink);
  transition: border-color var(--transition-fast), background var(--transition-fast);
}
.store-cart__trigger:hover {
  border-color: var(--color-primary-400);
  background: color-mix(in srgb, var(--theme-primary) 8%, var(--color-component-surface));
}
.store-cart__trigger svg {
  width: 2rem;
  height: 2rem;
  stroke-width: 2;
}
.store-cart__badge {
  position: absolute;
  top: -4px;
  right: -4px;
  min-width: 1.4rem;
  height: 1.4rem;
  padding: 0 5px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.75rem;
  font-weight: var(--font-semibold);
  color: var(--color-white);
  background: var(--theme-primary);
  border-radius: var(--radius-full);
  box-shadow: 0 0 0 2px var(--color-component-surface);
  transform-origin: center;
}
@keyframes storeCartBadgeBump {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.5); }
  60%  { transform: scale(0.9); }
  100% { transform: scale(1); }
}
.store-cart__badge--bump {
  animation: storeCartBadgeBump 0.4s ease-out;
}
@media (prefers-reduced-motion: reduce) {
  .store-cart__badge--bump { animation: none; }
}

.store-cart__panel {
  position: absolute;
  top: calc(100% + 0.5rem);
  right: 0;
  width: 360px;
  max-width: calc(100vw - 2rem);
  max-height: 70vh;
  background: var(--color-component-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.18);
  z-index: 50;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.store-cart__panel[hidden] { display: none; }
.store-cart__panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-border);
}
.store-cart__close {
  background: none;
  border: none;
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  color: var(--color-ink-light);
}
.store-cart__panel-body {
  flex: 1;
  overflow-y: auto;
  padding: var(--space-3) var(--space-4);
}
.store-cart__panel-footer {
  padding: var(--space-3) var(--space-4);
  border-top: 1px solid var(--color-border);
}
.store-cart__item {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: var(--space-3);
  align-items: center;
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--color-border);
}
.store-cart__item:last-child { border-bottom: none; }
.store-cart__item-img {
  width: 48px;
  height: 48px;
  object-fit: cover;
  border-radius: var(--radius-sm);
}
.store-cart__item-img--placeholder {
  background: var(--color-surface-subtle);
}
.store-cart__item-info { min-width: 0; }
.store-cart__item-price { white-space: nowrap; }

.store-thumb {
  border: 2px solid transparent;
  transition: border-color 0.15s;
}
.store-thumb:not(.store-thumb--active):hover {
  border-color: var(--color-border);
}
.store-thumb--active {
  border-color: var(--theme-primary);
}

/* Product pricing grid (manage/store/products/_form) — one set of inputs shown
   two ways. Simple mode hides the option columns and the per-row controls, so a
   product that comes exactly one way reads as three plain fields. */
.store-variant-row {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--space-2);
  align-items: end;
  margin-bottom: var(--space-2);
  max-width: 34rem;
}

.product-pricing--advanced .store-variant-row {
  grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr auto;
  max-width: none;
}

.store-variant-row--header {
  align-items: center;
  margin-bottom: var(--space-1);
  font-size: var(--text-xs);
  font-weight: var(--font-medium);
  color: var(--color-ink-light);
}

.product-pricing:not(.product-pricing--advanced) .product-pricing__advanced-only,
.product-pricing:not(.product-pricing--advanced) [data-variant-only],
.product-pricing--advanced .product-pricing__simple-only {
  display: none;
}

.product-pricing__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-3);
}

/* Small "i" that opens an explanatory popover next to a field label. */
.info-popover {
  position: relative;
  display: inline-block;
  vertical-align: middle;
}

.info-popover__trigger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.125rem;
  height: 1.125rem;
  padding: 0;
  border: 1px solid var(--color-border-dark);
  border-radius: var(--radius-full);
  background: transparent;
  color: var(--color-ink-light);
  font-size: var(--text-xs);
  font-style: italic;
  font-weight: var(--font-bold);
  line-height: 1;
  cursor: help;
}

.info-popover__trigger:hover {
  border-color: var(--theme-primary);
  background: transparent;
  color: var(--theme-primary);
}

@keyframes feedFiltersSlideDown {
  from {
    opacity: 0;
    transform: translateY(-12px);
    max-height: 0;
    margin-bottom: 0;
    padding-bottom: 0;
    border-bottom-color: transparent;
  }
  to {
    opacity: 1;
    transform: translateY(0);
    max-height: 200px;
    margin-bottom: var(--space-4);
    padding-bottom: var(--space-3);
    border-bottom-color: var(--color-border);
  }
}

.feed-filters--sub-animate {
  overflow: hidden;
  animation: feedFiltersSlideDown 0.25s ease-out;
  transform-origin: top;
}

@keyframes feedFiltersSlideUp {
  from {
    opacity: 1;
    transform: translateY(0);
    max-height: 200px;
    margin-bottom: var(--space-4);
    padding-bottom: var(--space-3);
    border-bottom-color: var(--color-border);
  }
  to {
    opacity: 0;
    transform: translateY(-12px);
    max-height: 0;
    margin-bottom: 0;
    padding-bottom: 0;
    border-bottom-color: transparent;
  }
}

.feed-filters--sub-closing {
  overflow: hidden;
  animation: feedFiltersSlideUp 0.25s ease-in forwards;
  transform-origin: top;
}

@media (prefers-reduced-motion: reduce) {
  .feed-filters--sub-animate,
  .feed-filters--sub-closing {
    animation: none;
  }
}

.feed-list {
  display: grid;
  gap: 1px;
  background: var(--color-border);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  overflow: hidden;
}

.feed-item {
  display: grid;
  grid-template-columns: 1.5rem 2.5rem 1fr;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-4);
  background: var(--color-component-surface);
  align-items: start;
}

.feed-item--unread {
  background: color-mix(in srgb, var(--theme-surface-tint) var(--feed-unread-tint, 50%), var(--color-component-surface));
}

.feed-item--urgent.feed-item--unread {
  background: color-mix(in srgb, var(--color-danger-600) var(--feed-urgent-tint, 8%), var(--color-component-surface));
}

.feed-item__indicator {
  display: flex;
  align-items: center;
  justify-content: center;
  padding-top: var(--space-2);
}

.feed-item__dot {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: var(--radius-full);
  background: var(--color-primary-600);
}

.feed-item__dot--urgent {
  background: var(--color-danger-600);
}

.feed-item__dot--low {
  background: var(--color-gray-400);
}

.feed-item__avatar {
  padding-top: 0.125rem;
}

.feed-item__content {
  min-width: 0;
}

.feed-item__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-2);
  margin-bottom: var(--space-1);
}

.feed-item__title {
  font-weight: var(--font-semibold);
  font-size: var(--text-sm);
  color: var(--color-ink);
}

.feed-item--unread .feed-item__title {
  font-weight: var(--font-bold);
}

.feed-item__meta {
  display: flex;
  gap: var(--space-1);
  flex-shrink: 0;
}

.feed-item__sender {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-xs);
  color: var(--color-ink);
  margin-bottom: var(--space-2);
}

.feed-item__time {
  color: var(--color-ink-lighter);
}

.feed-item__time::before {
  content: "\00b7";
  margin-right: var(--space-1);
}

.feed-item__time:first-child::before {
  content: none;
}

.feed-item__body {
  font-size: var(--text-sm);
  color: var(--color-ink);
  line-height: 1.5;
}

.feed-item__body p {
  margin: 0;
}

.feed-item__actions {
  display: flex;
  gap: var(--space-2);
  margin-top: var(--space-3);
}

.feed-item__expires {
  margin-top: var(--space-2);
  font-size: var(--text-xs);
  color: var(--color-warning-600);
  font-weight: var(--font-medium);
}

.feed-empty {
  padding: var(--space-8);
  text-align: center;
  color: var(--color-ink-light);
  background: var(--color-component-surface);
}

.feed-empty svg {
  color: var(--color-gray-300);
  margin-bottom: var(--space-3);
}

.feed-empty p {
  margin: 0;
  font-size: var(--text-sm);
}

/* ==========================================================================
   Calendar
   ========================================================================== */

/* 56rem is a comfortable column for the narrow, list-led view. The month grid
   wants far more — see the width ladder further down, which widens it in steps
   so the square cells grow with the window instead of stranding it in a column
   with empty space either side. */
.cal-page {
  max-width: 56rem;
  margin: 0 auto;
  padding: var(--space-6);
}

/* Header */
.cal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--space-4);
  flex-wrap: wrap;
  gap: var(--space-3);
}

.cal-header__title {
  font-size: var(--text-2xl);
  font-weight: var(--font-bold);
  margin: 0;
}

/* Month navigation and the calendar pills on one line, below the page title.
   row-gap so that when it wraps on a narrow window the two groups stay legible
   rather than colliding. */
.cal-toolbar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}

.cal-toolbar__months {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.cal-header__month {
  font-size: var(--text-lg);
  font-weight: var(--font-semibold);
  min-width: 10rem;
  text-align: center;
  color: var(--color-ink);
}

.cal-nav-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-component-surface);
  color: var(--color-ink);
  cursor: pointer;
  transition: all var(--transition-fast);
}

.cal-nav-btn:hover {
  background: color-mix(in srgb, var(--theme-primary) 10%, var(--color-component-surface));
  border-color: var(--color-primary-300);
}

.cal-nav-btn svg {
  width: 1rem;
  height: 1rem;
  overflow: visible;
  flex-shrink: 0;
}

.cal-today-btn {
  padding: var(--space-1) var(--space-3);
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-component-surface);
  color: var(--color-ink);
  cursor: pointer;
  transition: all var(--transition-fast);
}

.cal-today-btn:hover {
  background: color-mix(in srgb, var(--theme-primary) 10%, var(--color-component-surface));
  border-color: var(--color-primary-300);
}

/* Pending event invitations */
.cal-pending {
  margin-bottom: var(--space-4);
  border: 1px solid var(--color-primary-border);
  border-radius: var(--radius-lg);
  background: color-mix(in srgb, var(--color-primary-600) 4%, var(--color-component-surface));
}

.cal-pending__toggle {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-primary-700);
  cursor: pointer;
  list-style: none;
}

.cal-pending__toggle::-webkit-details-marker { display: none; }

.cal-pending__toggle svg {
  flex-shrink: 0;
  color: var(--color-primary-600);
}

.cal-pending__count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.25rem;
  height: 1.25rem;
  padding: 0 0.375rem;
  font-size: 0.6875rem;
  font-weight: 700;
  color: var(--color-white);
  background: var(--color-primary-600);
  border-radius: var(--radius-full);
}

.cal-pending__list {
  padding: 0 var(--space-4) var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  animation: cal-pending-open 0.25s ease-out;
  transform-origin: top;
}

@keyframes cal-pending-open {
  from {
    opacity: 0;
    max-height: 0;
    padding-bottom: 0;
    overflow: hidden;
  }
  to {
    opacity: 1;
    max-height: 50rem;
    padding-bottom: var(--space-4);
  }
}

.cal-pending__toggle::before {
  content: "";
  display: inline-block;
  width: 0.375rem;
  height: 0.375rem;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(-45deg);
  transition: transform 0.2s ease;
  flex-shrink: 0;
}

.cal-pending[open] > .cal-pending__toggle::before {
  transform: rotate(45deg);
}

.cal-pending__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--color-component-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
}

.cal-pending__content {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  min-width: 0;
}

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

.cal-pending__meta {
  font-size: var(--text-xs);
  color: var(--color-ink-light);
}

.cal-pending__actions {
  display: flex;
  gap: var(--space-2);
  flex-shrink: 0;
}

/* Grid */
.cal-grid {
  background: var(--color-component-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  margin-bottom: var(--space-6);
}

/* minmax(0, 1fr), not 1fr: a bare 1fr floors each column at its content's
   min-content width, so one long event title in a cell widens that whole column
   and the week stops being even. Zero minimum keeps all seven identical and lets
   the titles ellipsis instead. */
.cal-weekdays {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  border-bottom: 1px solid var(--color-border);
}

.cal-weekday {
  padding: var(--space-2) var(--space-1);
  text-align: center;
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  color: var(--color-ink-light);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.cal-days {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
}

/* Square, and every day the same size: the height follows the column width, so
   the grid stays even however much (or little) is on any given day. Content that
   doesn't fit is clipped rather than stretching its row. */
.cal-day {
  position: relative;
  aspect-ratio: 1;
  /* A grid item defaults to min-height: auto, which lets content push the cell
     taller than its square. That isn't just a cosmetic slip: the cell growing
     resizes the grid, which re-runs calendar#fitDays, which changes the content
     again — a ResizeObserver loop that locks the tab. Zero pins the square and
     lets overflow do the clipping. */
  min-height: 0;
  min-width: 0;
  overflow: hidden;
  padding: var(--space-1);
  border: 0;
  border-right: 1px solid var(--color-border);
  border-bottom: 1px solid var(--color-border);
  background: transparent;
  cursor: pointer;
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 2px;
  transition: background var(--transition-fast);
}

.cal-day:nth-child(7n) {
  border-right: 0;
}

.cal-days > .cal-day:nth-last-child(-n+7) {
  border-bottom: 0;
}

.cal-day:hover {
  background: color-mix(in srgb, var(--theme-primary) 6%, transparent);
}

.cal-day--selected {
  background: color-mix(in srgb, var(--theme-primary) 12%, transparent);
}

.cal-day--selected:hover {
  background: color-mix(in srgb, var(--theme-primary) 16%, transparent);
}

/* Centred in the compact view. The dot is centred in the cell either way, but
   with the date pinned top-left the eye takes the number as the anchor and reads
   the dot as pushed right — geometrically centred, optically off. Centring the
   number too makes the cell one balanced column. The roomy view puts it back to
   the left, where the event chips line up under it. */
.cal-day__number {
  display: inline-flex;
  align-self: center;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: var(--radius-full);
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  color: var(--color-ink);
  line-height: 1;
}

.cal-day--other-month .cal-day__number {
  color: var(--color-ink-lighter);
}

.cal-day--today .cal-day__number {
  background: var(--theme-primary);
  color: var(--color-white);
  font-weight: var(--font-bold);
}

/* Compact view: one dot per calendar with something on that day, centred in the
   space under the date rather than tucked into the top-left corner. flex: 1 is
   what claims that space — the cell is a square column, so the dots take
   whatever the date number leaves and sit in the middle of it. */
.cal-day__dots {
  display: flex;
  flex: 1;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 0 2px 2px;
  flex-wrap: wrap;
}

/* Coloured by its calendar, passed in as --cal-color, falling back to the school
   theme if a calendar somehow has none.

   The halo and glow are box-shadows rather than a border or an ::after: shadows
   are outside the box model, so the ring can be wider than the gap between dots
   without pushing them apart or changing where they centre. */
.cal-day__dot {
  width: 9px;
  height: 9px;
  border-radius: var(--radius-full);
  background: var(--cal-color, var(--theme-primary));
  box-shadow:
    0 0 0 3px color-mix(in srgb, var(--cal-color, var(--theme-primary)) 22%, transparent),
    0 1px 5px color-mix(in srgb, var(--cal-color, var(--theme-primary)) 55%, transparent);
  transition: transform var(--transition-fast), box-shadow var(--transition-fast);
}

/* The halo opens up under the cursor, so a day reads as touchable before it's
   clicked. */
.cal-day:hover .cal-day__dot {
  transform: scale(1.12);
  box-shadow:
    0 0 0 5px color-mix(in srgb, var(--cal-color, var(--theme-primary)) 26%, transparent),
    0 1px 6px color-mix(in srgb, var(--cal-color, var(--theme-primary)) 65%, transparent);
}

/* Following the house pattern of opting out per component — there's no global
   reduced-motion reset. The halo still widens on hover, it just doesn't animate
   or scale. */
@media (prefers-reduced-motion: reduce) {
  .cal-day__dot {
    transition: none;
  }

  .cal-day:hover .cal-day__dot {
    transform: none;
  }
}

/* Rides the same line as the dots, so it takes their size rather than the old
   6px one it was matched to. */
.cal-day__more {
  font-size: 0.625rem;
  font-weight: var(--font-medium);
  color: var(--color-ink-lighter);
  line-height: 1;
}

/* Events list */
.cal-events {
  margin-top: var(--space-2);
}

.cal-events__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--space-4);
}

.cal-events__heading {
  font-size: var(--text-lg);
  font-weight: var(--font-semibold);
  margin: 0;
  color: var(--color-ink);
}

.cal-events__list {
  display: grid;
  gap: var(--space-3);
}

.cal-events__empty {
  padding: var(--space-8);
  text-align: center;
  color: var(--color-ink-light);
  background: var(--color-component-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
}

.cal-events__empty svg {
  color: var(--color-gray-300);
  margin-bottom: var(--space-3);
}

.cal-events__empty p {
  margin: 0;
  font-size: var(--text-sm);
}

/* Event card */
.cal-event-card {
  display: flex;
  width: 100%;
  text-align: left;
  font: inherit;
  padding: 0;
  background: var(--color-component-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  cursor: pointer;
  transition: box-shadow var(--transition-fast), border-color var(--transition-fast);
}

.cal-event-card:hover {
  box-shadow: var(--shadow-sm);
  border-color: var(--color-primary-300);
}

.cal-event-card__accent {
  width: 4px;
  flex-shrink: 0;
  background: var(--theme-primary);
}

/* align-self: stretch because the card centres its children, which left this
   strip at height 0 — invisible. That went unnoticed while the colour was
   decorative; it's how you tell calendars apart now. */
.cal-event-card__accent {
  align-self: stretch;
  background: var(--cal-accent, var(--theme-primary));
}

.cal-event-card__body {
  flex: 1;
  padding: var(--space-3) var(--space-4);
  min-width: 0;
}

.cal-event-card__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  margin-bottom: var(--space-1);
}

.cal-event-card__time {
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  color: var(--theme-primary);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.cal-event--secondary .cal-event-card__time {
  color: var(--theme-secondary);
}

.cal-event--accent .cal-event-card__time {
  color: var(--color-warning-600);
}

.cal-event-card__title {
  font-family: var(--font-sans);
  font-size: var(--text-base);
  font-weight: var(--font-semibold);
  text-transform: none;
  margin: 0 0 var(--space-2);
  color: var(--color-ink);
}

.cal-event-card__meta {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  font-size: var(--text-xs);
  color: var(--color-ink-light);
  margin-bottom: var(--space-2);
}

.cal-event-card__date,
.cal-event-card__duration {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}

.cal-event-card__desc {
  font-size: var(--text-sm);
  color: var(--color-ink-light);
  line-height: var(--leading-relaxed);
}

.cal-event-card__links {
  display: flex;
  gap: var(--space-2);
  margin-top: var(--space-2);
  flex-wrap: wrap;
}

.cal-event-card__link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--text-xs);
  font-weight: var(--font-medium);
  color: var(--theme-primary);
  text-decoration: none;
  padding: var(--space-1) var(--space-2);
  border: 1px solid var(--color-primary-border);
  border-radius: var(--radius-md);
  transition: all var(--transition-fast);
}

.cal-event-card__link:hover {
  background: color-mix(in srgb, var(--theme-primary) 8%, var(--color-component-surface));
  border-color: var(--color-primary-300);
  text-decoration: none;
}

/* ==========================================================================
   Popover - Apple-style popover / Bootstrap modal hybrid
   ========================================================================== */

/* Backdrop */
.popover-backdrop {
  position: fixed;
  inset: 0;
  background: rgb(0 0 0 / 0.35);
  z-index: 1400;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--transition-normal);
}

.popover-backdrop--visible {
  opacity: 1;
  pointer-events: auto;
}

/* Popover container */
.popover {
  position: fixed;
  z-index: 1500;
  width: min(28rem, calc(100vw - 2rem));
  max-height: calc(100vh - var(--space-8));
  background: var(--color-component-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg), 0 0 0 1px rgb(0 0 0 / 0.03);
  overflow: hidden;
  display: flex;
  flex-direction: column;

  opacity: 0;
  transform: scale(0.95) translateY(4px);
  pointer-events: none;
  transition: opacity var(--transition-normal), transform var(--transition-normal);
}

.popover--visible {
  opacity: 1;
  transform: scale(1) translateY(0);
  pointer-events: auto;
}

/* Arrow (points toward the trigger) */
.popover__arrow {
  position: absolute;
  width: 12px;
  height: 12px;
  background: var(--color-component-surface);
  border: 1px solid var(--color-border);
  transform: rotate(45deg);
  z-index: -1;
}

.popover__arrow--top {
  top: -7px;
  border-right: none;
  border-bottom: none;
}

.popover__arrow--bottom {
  bottom: -7px;
  border-left: none;
  border-top: none;
}

.popover__arrow--right {
  right: -7px;
  border-left: none;
  border-bottom: none;
}

.popover__arrow--left {
  left: -7px;
  border-right: none;
  border-top: none;
}

/* Header */
.popover__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--color-border);
  flex-shrink: 0;
}

.popover__title {
  font-family: var(--font-sans);
  font-size: var(--text-base);
  font-weight: var(--font-semibold);
  text-transform: none;
  color: var(--color-ink);
  margin: 0;
  line-height: var(--leading-tight);
}

.popover__close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  border: none;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--color-ink-light);
  cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast);
  flex-shrink: 0;
}

.popover__close:hover {
  background: var(--color-hover-surface);
  color: var(--color-ink);
}

.popover__close svg {
  width: 1rem;
  height: 1rem;
}

/* Body */
.popover__body {
  padding: var(--space-5);
  overflow-y: auto;
  flex: 1;
}

/* Footer */
.popover__footer {
  padding: var(--space-3) var(--space-5);
  border-top: 1px solid var(--color-border);
  background: var(--color-tinted-surface);
  flex-shrink: 0;
}

/* Popover event detail layout */
.popover-event-meta {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.popover-event-links {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
}

/* Responsive */
@media (max-width: 768px) {
  .cal-page {
    padding: var(--space-4);
  }

  /* Title and "Manage calendars" stay on one line, opposite each other. This
     used to stack, from when the header also carried the month controls and they
     needed a line of their own — they live in the toolbar below now, so there's
     nothing left to stack. */
  .cal-header {
    flex-wrap: nowrap;
    gap: var(--space-2);
  }

  .cal-header__manage {
    white-space: nowrap;
  }

  .cal-header__actions {
    gap: var(--space-2);
  }

  /* Centred on a narrow screen: the month controls and the calendar switches each
     wrap onto their own line here, and a centred line sits better under a
     full-width grid than one hugging the left edge. */
  .cal-toolbar {
    justify-content: center;
  }

  .cal-legend {
    justify-content: center;
  }

  /* No min-height: the cells are square (aspect-ratio: 1), and a floor here
     would make the narrow columns taller than they are wide. */
  .cal-day {
    padding: 2px;
  }

  .cal-day__number {
    width: 1.5rem;
    height: 1.5rem;
    font-size: var(--text-xs);
  }

  .cal-event-card__meta {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-1);
  }
}

/* ==========================================================================
   Date/Time Picker
   ========================================================================== */

.dtpicker {
  position: relative;
}

/* Trigger — single input-like button showing "Mar 18, 2026 at 9:00 AM" */
.dtpicker__trigger {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-sm);
  font-family: var(--font-sans);
  font-weight: var(--font-medium);
  color: var(--color-ink);
  background: var(--color-component-surface);
  border: 1px solid var(--color-border-dark);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
  text-align: left;
}

.dtpicker__trigger:hover {
  border-color: var(--color-primary-300);
}

.dtpicker__trigger:focus-visible {
  outline: none;
  border-color: var(--color-primary-400);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--theme-primary) 35%, transparent);
}

.dtpicker__trigger svg {
  width: 1rem;
  height: 1rem;
  color: var(--color-ink-light);
  flex-shrink: 0;
}

/* Dropdown */
.dtpicker__dropdown {
  position: absolute;
  top: calc(100% + var(--space-2));
  left: 0;
  z-index: 100;
  width: 18rem;
  background: var(--color-component-surface);
  border: 1px solid var(--color-border-dark);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: var(--space-3);
  display: none;
}

.dtpicker__dropdown--open {
  display: block;
}

/* Calendar header */
.dtpicker__cal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--space-2);
}

.dtpicker__month-label {
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
  color: var(--color-ink);
}

.dtpicker__nav {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--color-ink);
  cursor: pointer;
  transition: all var(--transition-fast);
  font-size: var(--text-lg);
  line-height: 1;
}

.dtpicker__nav:hover {
  background: color-mix(in srgb, var(--theme-primary) 10%, var(--color-component-surface));
  border-color: var(--color-primary-300);
}

/* Weekday labels */
.dtpicker__weekdays {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  margin-bottom: var(--space-1);
}

.dtpicker__weekdays span {
  text-align: center;
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  color: var(--color-ink-light);
  padding: var(--space-1) 0;
}

/* Day grid */
.dtpicker__days {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2px;
}

.dtpicker__day {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  margin: 0 auto;
  border: none;
  border-radius: var(--radius-full);
  background: transparent;
  color: var(--color-ink);
  font-size: var(--text-sm);
  font-family: var(--font-sans);
  cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast);
}

.dtpicker__day:hover {
  background: color-mix(in srgb, var(--theme-primary) 12%, var(--color-component-surface));
}

.dtpicker__day--other {
  color: var(--color-ink-lighter);
}

.dtpicker__day--today {
  font-weight: var(--font-bold);
  background: color-mix(in srgb, var(--theme-primary) 10%, var(--color-component-surface));
  color: var(--theme-primary);
}

.dtpicker__day--selected {
  background: var(--theme-primary);
  color: var(--color-white);
  font-weight: var(--font-semibold);
}

.dtpicker__day--selected:hover {
  background: color-mix(in srgb, var(--theme-primary) 85%, black);
}

.dtpicker__day--today.dtpicker__day--selected {
  background: var(--theme-primary);
  color: var(--color-white);
}

/* Time bar — sits below calendar inside dropdown */
.dtpicker__time-bar {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid var(--color-border);
}

.dtpicker__time-label {
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  color: var(--color-ink-light);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.dtpicker__time-bar select {
  padding: var(--space-1) var(--space-2);
  font-size: var(--text-sm);
  font-family: var(--font-sans);
  min-height: auto;
  border: 1px solid var(--color-border-dark);
  border-radius: var(--radius-md);
  background: var(--color-component-surface);
  color: var(--color-ink);
}

.dtpicker__time-sep {
  font-weight: var(--font-semibold);
  color: var(--color-ink-light);
  line-height: 1;
}

/* =========================================================
   Chat Room
   ========================================================= */

.chat-room {
  position: relative;
  display: flex;
  flex-direction: column;
  height: calc(100vh - var(--masquerade-banner-height, 0px));
  max-height: calc(100vh - var(--masquerade-banner-height, 0px));
  overflow: hidden;
}

.chat-room__header {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-border);
  background: var(--color-component-surface);
}

.chat-room__header-left,
.chat-room__header-right {
  flex: 1;
}

.chat-room__header-right {
  display: flex;
  justify-content: flex-end;
}

.chat-room__header-center {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

/* Direct-message header: the other participant's avatar beside their name. */
.chat-room__header-dm {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.chat-room__header-dm .chat-message__avatar {
  margin-bottom: 0;
}

.chat-room__member-list {
  list-style: none;
  margin: 0;
  padding: 0;
  overflow-y: auto;
}

.chat-room__member-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--color-border);
}

.chat-room__member-item:last-child {
  border-bottom: none;
}

.chat-room__member-avatar {
  flex-shrink: 0;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 50%;
  background: var(--color-primary-600);
  color: white;
  font-size: 0.65rem;
  font-weight: var(--font-semibold);
  display: flex;
  align-items: center;
  justify-content: center;
}

.chat-room__member-avatar--img {
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 50%;
  object-fit: cover;
}

.chat-room__messages {
  flex: 1;
  overflow-y: auto;
  padding: var(--space-4) 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  opacity: 0;
  transition: opacity 180ms ease;
}
.chat-room__messages--ready {
  opacity: 1;
}

.chat-room__empty {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 1;
  color: var(--color-ink-light);
  font-size: var(--text-sm);
  text-align: center;
  padding: var(--space-8);
}

.chat-room__empty:not(:only-child) {
  display: none;
}

button.chat-room__new-messages {
  display: none;
  position: absolute;
  bottom: 5rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 10;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  background: var(--color-primary-600);
  color: var(--color-white);
  border: none;
  border-radius: var(--radius-full);
  font-size: var(--text-xs);
  font-weight: 600;
  cursor: pointer;
  box-shadow: var(--shadow-md);
}

button.chat-room__new-messages.chat-room__new-messages--visible {
  display: inline-flex;
}

.chat-room-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4);
  border-bottom: 1px solid var(--color-border);
  transition: background-color var(--transition-fast);
}

.chat-room-row:hover {
  background: var(--color-surface-hover, rgba(0, 0, 0, 0.03));
}

.chat-room-row--unread {
  border-left: 3px solid var(--color-primary-600);
  background: color-mix(in srgb, var(--color-primary-600) 4%, transparent);
}

.chat-room-row__unread-label {
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--color-primary-600);
  flex-shrink: 0;
}

.chat-room-logo {
  width: 3.5rem;
  height: 3.5rem;
  flex-shrink: 0;
  border-radius: var(--radius-lg);
  object-fit: cover;
}

.chat-room__input {
  flex-shrink: 0;
  border-top: 1px solid var(--color-border);
  padding: var(--space-3) var(--space-4);
  background: var(--color-component-surface);
}

.chat-room__input-row {
  display: flex;
  gap: var(--space-2);
  align-items: center;
}

.chat-room__input-field {
  flex: 1;
  min-height: auto;
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-sm);
}

/* Chat Message */

.chat-message {
  display: flex;
  gap: var(--space-2);
  align-items: flex-end;
  padding: var(--space-1) var(--space-4);
}

.chat-message__avatar {
  flex-shrink: 0;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  background: var(--color-primary-600);
  color: white;
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: var(--space-1);
}

.chat-message__content {
  max-width: 68%;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

.chat-message__meta {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  margin-bottom: var(--space-1);
}

.chat-message__author {
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  color: var(--color-ink);
}

.chat-message__time {
  font-size: var(--text-xs);
  color: var(--color-ink-light);
}

/* Role badge (Teacher, Principal, …) next to the author name. The color is
   pushed from the server via --badge-color. */
.chat-message__badge {
  font-size: 0.625rem;
  font-weight: var(--font-semibold);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  line-height: 1.4;
  color: var(--badge-color);
  background: color-mix(in srgb, var(--badge-color) 14%, transparent);
  padding: 0.05rem 0.4rem;
  border-radius: 999px;
  white-space: nowrap;
}

.chat-message__body {
  background: var(--color-border);
  padding: var(--space-2) var(--space-3);
  border-radius: 1.1rem;
  border-bottom-left-radius: 0.25rem;
  font-size: var(--text-sm);
  color: var(--color-ink);
  word-break: break-word;
  white-space: pre-wrap;
  line-height: 1.45;
}

/* Meta variants — theirs visible by default, mine hidden */
.chat-message__meta--mine {
  display: none;
}

/* Mine — right-aligned bubble */
.chat-message--mine {
  flex-direction: row-reverse;
}

.chat-message--mine .chat-message__avatar-slot {
  display: none;
}

.chat-message--mine .chat-message__meta--theirs {
  display: none;
}

.chat-message--mine .chat-message__meta--mine {
  display: flex;
}

.chat-message--mine .chat-message__content {
  align-items: flex-end;
}

.chat-message--mine .chat-message__meta {
  flex-direction: row-reverse;
  margin-bottom: 0;
  margin-top: var(--space-1);
}

.chat-message--mine .chat-message__body {
  background: var(--color-primary-600);
  color: white;
  border-radius: 1.1rem;
  border-bottom-right-radius: 0.25rem;
}

.chat-message--mine .chat-message__body a {
  color: rgba(255, 255, 255, 0.85);
  text-decoration: underline;
}

/* Avatar image (when user has uploaded a photo) */
.chat-message__avatar--img {
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  object-fit: cover;
  display: block;
  margin-bottom: var(--space-1);
}

/* Link preview card */
.link-preview {
  display: flex;
  flex-direction: column;
  margin-top: var(--space-2);
  max-width: 280px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  background: var(--color-component-surface);
  transition: box-shadow var(--transition-fast);
}

.link-preview:hover {
  box-shadow: var(--shadow-sm);
}

.link-preview__image {
  width: 100%;
  max-height: 140px;
  overflow: hidden;
  background: var(--color-border);
}

.link-preview__image img {
  width: 100%;
  height: 140px;
  object-fit: cover;
  display: block;
}

.link-preview__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-2) var(--space-3);
}

.link-preview__domain {
  font-size: var(--text-xs);
  color: var(--color-ink-light);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.link-preview__title {
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
  color: var(--color-ink);
  line-height: 1.3;
}

.link-preview__desc {
  font-size: var(--text-xs);
  color: var(--color-ink-light);
  line-height: 1.4;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Mine messages: link preview card uses muted colors */
.chat-message--mine .link-preview {
  border-color: color-mix(in srgb, white 20%, var(--color-primary-600));
  background: color-mix(in srgb, white 15%, var(--color-primary-600));
}

.chat-message--mine .link-preview__domain,
.chat-message--mine .link-preview__title,
.chat-message--mine .link-preview__desc {
  color: rgba(255, 255, 255, 0.9);
}

.chat-message--mine .link-preview__domain {
  color: rgba(255, 255, 255, 0.7);
}

/* Settings avatar row */
.settings-avatar-row {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

.settings-avatar-preview {
  flex-shrink: 0;
  width: 5rem;
  height: 5rem;
  border-radius: 50%;
  overflow: hidden;
  background: var(--color-primary-100);
}

.settings-avatar-preview__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.settings-avatar-preview__initials {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--text-xl);
  font-weight: var(--font-semibold);
  color: var(--color-primary-700);
}

.settings-avatar-actions {
  flex: 1;
  min-width: 0;
}

/* Sidebar settings link pinned to bottom */
.sidebar__group--bottom {
  margin-top: auto;
  padding-top: var(--space-2);
  border-top: 1px solid var(--color-border);
}

/* Admin Tools wrapper — let its children participate in the parent grid */
.admin-tools {
  display: contents;
}

/* Admin Tools modal */
.admin-tools-dialog {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
}

.admin-tools-dialog[hidden] {
  display: none;
}

.admin-tools-dialog__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
}

.admin-tools-dialog__panel {
  position: relative;
  z-index: 1;
  width: min(420px, calc(100vw - 2rem));
  max-height: calc(100vh - 4rem);
  overflow-y: auto;
}

.admin-tools-dialog__panel--overflow-visible {
  overflow: visible;
}

.admin-tools-dialog__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--space-4);
}

.admin-tools-dialog__field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}

.admin-tools-dialog__field:last-child {
  margin-bottom: 0;
}

.admin-tools-dialog__label {
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
  color: var(--color-ink);
}

/* Sidebar account menu (email + log out popover) — pinned to extreme bottom */
.account-menu {
  position: relative;
  margin-top: auto;
  padding-top: var(--space-2);
  border-top: 1px solid var(--color-border);
}
.account-menu__trigger {
  width: 100%;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-2);
  background: transparent;
  border: 0;
  border-radius: var(--radius-sm);
  text-align: left;
  font: inherit;
  color: var(--color-ink-light);
  cursor: pointer;
}
.account-menu__trigger:hover,
.account-menu--open .account-menu__trigger {
  background: color-mix(in srgb, var(--theme-primary) 6%, transparent);
  color: var(--color-ink);
}
.account-menu__mohawk {
  transition: fill var(--transition-fast), stroke var(--transition-fast);
}
.account-menu__trigger:hover .account-menu__mohawk,
.account-menu--open .account-menu__mohawk {
  fill: #f97316;
  stroke: #f97316;
}
.account-menu__icon {
  display: inline-flex;
  flex-shrink: 0;
}
.account-menu__icon svg {
  width: 1.1rem;
  height: 1.1rem;
}
.account-menu__logo {
  display: block;
  height: 1.1rem;
  width: auto;
  object-fit: contain;
}
.account-menu__email {
  font-size: 0.95em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.account-menu__menu {
  position: absolute;
  bottom: calc(100% + 4px);
  left: 0;
  right: 0;
  background: var(--color-component-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
  padding: var(--space-1);
  z-index: 20;
}
.account-menu__menu form {
  margin: 0;
}
.account-menu__item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  padding: var(--space-2) var(--space-3);
  background: transparent;
  border: 0;
  border-radius: var(--radius-sm);
  color: var(--color-ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.account-menu__item:hover {
  background: color-mix(in srgb, var(--theme-primary) 8%, transparent);
}
.account-menu__item svg {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}
.sidebar.is-collapsed .account-menu__email {
  display: none;
}
.sidebar.is-collapsed .account-menu__trigger {
  justify-content: center;
}

/* ── Chat: submit progress bar ───────────────────────────────── */
.chat-room__progress-bar {
  height: 3px;
  background: transparent;
  flex-shrink: 0;
}
.chat-room__progress-bar--active {
  background: linear-gradient(
    90deg,
    var(--color-border) 0%,
    var(--brand-primary, var(--color-accent)) 40%,
    var(--color-border) 100%
  );
  background-size: 200% 100%;
  animation: chat-progress-shimmer 1.3s ease-in-out infinite;
}
@keyframes chat-progress-shimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* ── Chat: file preview strip ─────────────────────────────────── */
.chat-room__file-previews {
  display: none;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  border-bottom: 1px solid var(--color-border);
  overflow-x: auto;
}
.chat-room__file-previews--visible { display: flex; }

.file-preview-thumb {
  position: relative;
  flex-shrink: 0;
  width: 64px;
  height: 64px;
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--color-tinted-surface);
}
.file-preview-thumb img,
.file-preview-thumb video { width: 100%; height: 100%; object-fit: cover; }

.file-preview-thumb__play {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgb(0 0 0 / 0.35);
  color: white;
}
.file-preview-thumb__play svg { width: 1.25rem; height: 1.25rem; }

/* ── Chat: attach button ──────────────────────────────────────── */
.chat-room__attach-btn {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: var(--radius-md);
  color: var(--color-ink-light);
  cursor: pointer;
  transition: color var(--transition-fast), background var(--transition-fast);
}
.chat-room__attach-btn:hover { background: var(--color-hover-surface); color: var(--color-ink); }
.chat-room__attach-btn svg { width: 1.25rem; height: 1.25rem; }

/* ── Chat: inline attachment thumbnails ──────────────────────── */
.message-attachments {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-top: var(--space-1);
  overflow: hidden;
  border-radius: 1rem;
  max-width: 280px;
}
.message-attachments--grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
}

.message-attachment {
  position: relative;
  overflow: hidden;
  cursor: pointer;
  background: var(--color-tinted-surface);
  aspect-ratio: 4 / 3;
}
.message-attachment__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: opacity var(--transition-fast);
}
.message-attachment:hover .message-attachment__img { opacity: 0.9; }

.message-attachment__video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  pointer-events: none;
}
.message-attachment__play-btn {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgb(0 0 0 / 0.25);
  color: white;
  transition: background var(--transition-fast);
}
.message-attachment--video:hover .message-attachment__play-btn { background: rgb(0 0 0 / 0.4); }
.message-attachment__play-btn svg { filter: drop-shadow(0 1px 3px rgb(0 0 0 / 0.5)); }

/* ── Media viewer lightbox ────────────────────────────────────── */
.media-viewer {
  position: fixed;
  top: var(--media-viewer-top, 0);
  right: var(--media-viewer-right, 0);
  bottom: var(--media-viewer-bottom, 0);
  left: var(--media-viewer-left, 0);
  z-index: 2000;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--transition-normal);
}
.media-viewer--open { opacity: 1; pointer-events: auto; }

.media-viewer__backdrop {
  position: absolute;
  inset: 0;
  background: rgb(0 0 0 / 0.85);
}
.media-viewer__shell {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  width: min(calc(100% - var(--space-8)), 1200px);
  max-height: calc(100% - var(--space-8));
}
.media-viewer__toolbar {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
}
.media-viewer__download { text-decoration: none; }
.media-viewer__stage {
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  overflow: hidden;
}
.media-viewer__content {
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  will-change: transform, opacity;
}
.media-viewer__img {
  max-width: 100%;
  max-height: calc(100dvh - var(--media-viewer-top, 0px) - var(--media-viewer-bottom, 0px) - 5rem);
  border-radius: var(--radius-lg);
  object-fit: contain;
  display: block;
}
.media-viewer__img--placeholder {
  filter: blur(10px);
  position: absolute;
}
.media-viewer__img--loading {
  opacity: 0;
}
.media-viewer__video {
  max-width: 100%;
  max-height: calc(100dvh - var(--media-viewer-top, 0px) - var(--media-viewer-bottom, 0px) - 5rem);
  border-radius: var(--radius-lg);
}
.media-viewer__prev,
.media-viewer__next {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border: none;
  border-radius: 50%;
  background: rgba(255,255,255,0.15);
  color: white;
  cursor: pointer;
  flex-shrink: 0;
  transition: background 0.15s;
}
.media-viewer__prev:hover,
.media-viewer__next:hover {
  background: rgba(255,255,255,0.3);
}
.media-viewer__counter {
  color: rgba(255,255,255,0.8);
  margin-right: auto;
}

/* ── Chat: react button ───────────────────────────────────────── */
.chat-message__actions {
  position: relative;
  flex-shrink: 0;
  align-self: center;
  display: flex;
  align-items: center;
}
.chat-message__actions {
  gap: var(--space-1);
}
.chat-message__react {
  position: relative;
  display: flex;
  align-items: center;
}
.chat-message__react-btn,
.chat-message__menu-btn {
  display: flex;
  flex-shrink: 0;
  align-self: center;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  min-width: 1.5rem;
  height: 1.5rem;
  min-height: 1.5rem;
  border-radius: 50%;
  background: transparent;
  border: 1.5px solid var(--color-border);
  color: var(--color-ink-light);
  cursor: pointer;
  opacity: 0.5;
  padding: 0;
  transition: opacity var(--transition-fast), background var(--transition-fast), border-color var(--transition-fast);
}
.chat-message__react-btn:hover,
.chat-message__menu-btn:hover {
  opacity: 1;
  background: var(--color-hover-surface);
  border-color: var(--color-ink-light);
}

/* ── Message moderation menu (report / block) ─────────────────── */
.chat-message__menu {
  position: relative;
  align-self: center;
}
.chat-message__menu-btn {
  list-style: none;
}
.chat-message__menu-btn::-webkit-details-marker { display: none; }
.chat-message[open] .chat-message__menu-btn,
.chat-message__menu[open] .chat-message__menu-btn {
  opacity: 1;
}
.chat-message__menu-panel {
  position: absolute;
  top: calc(100% + var(--space-1));
  right: 0;
  z-index: 200;
  width: 15rem;
  max-width: 90vw;
  background: var(--color-component-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: 0 4px 20px rgb(0 0 0 / 0.12);
  padding: var(--space-3);
  display: grid;
  gap: var(--space-2);
}
.chat-message--mine .chat-message__menu-panel { right: auto; left: 0; }
.chat-message__report {
  display: grid;
  gap: var(--space-2);
}
.chat-message__menu-label {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--color-ink-light);
}
.chat-message__menu-select {
  width: 100%;
}
.chat-message__menu-submit { width: 100%; }
/* Report stays disabled until a real reason is picked (the chat-moderation
   controller toggles the button's disabled attribute on change). */
.chat-message__menu-submit:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.chat-message__menu-divider {
  height: 1px;
  background: var(--color-border);
  margin: var(--space-1) 0;
}
.chat-message__menu-block {
  width: 100%;
  text-align: left;
  background: transparent;
  border: none;
  color: var(--color-danger-600);
  cursor: pointer;
  padding: var(--space-1) 0;
  font-size: 0.875rem;
}
.chat-message__menu-block:hover { text-decoration: underline; }
.chat-room__popover-footer {
  margin-top: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid var(--color-border);
  text-align: center;
}

/* ── Blocked (muted) author's message ─────────────────────────── */
/* Kept in the thread but blurred behind a tap-to-reveal, matching iOS. */
.chat-message--blocked .chat-message__blurable {
  filter: blur(8px);
  pointer-events: none;
  user-select: none;
  transition: filter 0.15s ease;
}
.chat-message--blocked.chat-message--revealed .chat-message__blurable {
  filter: none;
  pointer-events: auto;
  user-select: auto;
}
.chat-message__reveal {
  align-self: flex-start;
  margin-bottom: var(--space-1);
  padding: 2px 10px;
  border-radius: 9999px;
  border: 1px solid var(--color-border);
  background: var(--color-component-surface);
  color: var(--color-ink-light);
  font-size: 0.75rem;
  cursor: pointer;
}
.chat-message__reveal:hover { text-decoration: underline; }
.chat-message--revealed .chat-message__reveal-show { display: none; }
.chat-message:not(.chat-message--revealed) .chat-message__reveal-hide { display: none; }

/* ── Emoji picker ─────────────────────────────────────────────── */
.emoji-picker {
  display: none;
  position: absolute;
  top: calc(100% + var(--space-1));
  right: 0;
  z-index: 200;
  background: var(--color-component-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: 0 4px 20px rgb(0 0 0 / 0.12);
  padding: var(--space-2);
  overflow-x: auto;
  overflow-y: hidden;
  white-space: nowrap;
  max-width: min(320px, 90vw);
  scrollbar-width: none;
}
.emoji-picker::-webkit-scrollbar { display: none; }
.emoji-picker--open { display: flex; gap: 2px; }
/* "mine" messages are row-reversed — flip the picker so it opens left */
.chat-message--mine .emoji-picker {
  right: auto;
  left: 0;
}
/* "theirs" messages — picker opens to the right of the button */
.chat-message:not(.chat-message--mine) .emoji-picker {
  left: 0;
  right: auto;
}
.emoji-picker__emoji {
  flex-shrink: 0;
  font-size: 1.375rem;
  line-height: 1;
  width: 2.25rem;
  height: 2.25rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-md);
  cursor: pointer;
  background: transparent;
  border: none;
  padding: 0;
  transition: background var(--transition-fast), transform var(--transition-fast);
}
.emoji-picker__emoji:hover {
  background: var(--color-hover-surface);
  transform: scale(1.2);
}

/* ── Reaction badges on messages ─────────────────────────────── */
.message-reactions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  margin-top: var(--space-1);
  min-height: 0;
}
.reaction-badge {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 2px 8px 2px 6px;
  border-radius: 9999px;
  border: 1px solid var(--color-border);
  background: var(--color-component-surface);
  font-size: 0.8125rem;
  cursor: pointer;
  transition: background var(--transition-fast), border-color var(--transition-fast);
  user-select: none;
}
/* not-mine hover → green tint (will ADD) */
.reaction-badge:not(.reaction-badge--mine):hover {
  background: color-mix(in srgb, #22c55e 15%, transparent);
  border-color: #22c55e;
}
.reaction-badge--mine {
  background: color-mix(in srgb, var(--brand-primary, var(--color-accent)) 12%, transparent);
  border-color: var(--brand-primary, var(--color-accent));
}
/* mine hover → red tint (will REMOVE) */
.reaction-badge--mine:hover {
  background: color-mix(in srgb, #ef4444 15%, transparent);
  border-color: #ef4444;
}
.reaction-badge__emoji { font-size: 0.9375rem; line-height: 1; }
.reaction-badge__count { color: var(--color-ink-light); font-size: 0.75rem; }

/* ==========================================================================
   Classroom Page
   ========================================================================== */

.classroom-page {
  max-width: 680px;
  margin: 0 auto;
  padding: var(--space-6);
}

@media (min-width: 1024px) {
  .classroom-page { max-width: 800px; }
}

@media (min-width: 1440px) {
  .classroom-page { max-width: 920px; }
}

.classroom-page__header {
  margin-bottom: var(--space-6);
}

.classroom-teacher-card {
  display: inline-flex;
  align-items: center;
  /* These sit in an inline row, and an inline-flex box aligns on the baseline of
     its first item — which is text for an initials avatar but the bottom edge
     for a photo. Left to `baseline`, whether someone uploaded a picture decides
     where their card sits. The cards are all one height, so centring them lines
     them up whichever avatar they have. */
  vertical-align: middle;
  gap: var(--space-2);
  margin-top: var(--space-2);
  padding: var(--space-2) var(--space-3);
  background: var(--color-component-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
}

.classroom-teacher-card__avatar {
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  background: var(--color-primary-600);
  color: white;
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.classroom-teacher-card__avatar--img {
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  object-fit: cover;
}

.classroom-teacher-card__name {
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  color: var(--color-ink);
}

/* Composer */
.classroom-composer {
  margin-bottom: var(--space-6);
}

.classroom-composer__field {
  width: 100%;
  border: none;
  resize: none;
  overflow: hidden;
  min-height: 3rem;
  font-size: var(--text-sm);
  background: var(--color-white);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
  outline: none;
}

.classroom-composer__editor {
  width: 100%;
  font-size: var(--text-sm);
}

.classroom-composer__actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-top: 1px solid var(--color-border);
  padding-top: var(--space-3);
  margin-top: var(--space-2);
}

.classroom-composer__attach-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  cursor: pointer;
  color: var(--color-ink-light);
  padding: var(--space-1);
  border-radius: var(--radius-md);
  transition: color 0.15s, background 0.15s;
}

.classroom-composer__attach-btn:hover {
  color: var(--color-ink);
  background: var(--color-surface-subtle);
}

.classroom-composer__previews {
  display: none;
}

.classroom-composer__previews--visible {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  padding-bottom: var(--space-3);
}

/* Post Card */
.classroom-post {
  margin-bottom: var(--space-4);
}

.classroom-post__header {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
}

.classroom-post__meta {
  display: flex;
  flex-direction: column;
  flex: 1;
}

.classroom-post__actions {
  margin-left: auto;
}

.classroom-post__body {
  font-size: var(--text-sm);
  line-height: 1.6;
  white-space: pre-wrap;
  word-break: break-word;
  margin-bottom: var(--space-3);
}

.classroom-post .card__body:not(:has(.message-attachments)):not(:has(.link-preview)) .classroom-post__body {
  margin-bottom: 0;
}

.classroom-post .card__body:not(:has(.message-attachments)):not(:has(.link-preview)) {
  padding-block: var(--space-4);
}

.classroom-post__body a {
  color: var(--color-primary-600);
  text-decoration: underline;
}

.classroom-post .message-attachments {
  margin-top: var(--space-2);
  max-width: 100%;
  display: flex;
  flex-wrap: wrap;
  flex-direction: row;
  gap: var(--space-2);
  border-radius: 0;
}

.classroom-post .message-attachments .message-attachment {
  width: 120px;
  height: 90px;
  border-radius: var(--radius-md);
  aspect-ratio: 4 / 3;
}

/* Edit attachments grid */
.edit-attachments {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}

.edit-attachment {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  width: 120px;
  transition: opacity 0.2s;
}

.edit-attachment--removed {
  opacity: 0.35;
}

.edit-attachment__preview {
  position: relative;
}

.edit-attachment__thumb {
  width: 120px;
  height: 90px;
  border-radius: var(--radius-md);
  overflow: hidden;
  cursor: pointer;
  background: var(--color-tinted-surface);
  display: flex;
  align-items: center;
  justify-content: center;
}

.edit-attachment__thumb--video {
  position: relative;
}

.edit-attachment__thumb--file {
  cursor: default;
  color: var(--color-ink-light);
}

.edit-attachment__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.edit-attachment__play {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  background: rgba(0,0,0,0.3);
  pointer-events: none;
}

.edit-attachment__name {
  max-width: 120px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--color-ink-light);
  text-align: center;
}

.edit-attachment__remove {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  font-size: var(--text-xs);
  color: var(--color-danger-600);
  cursor: pointer;
  padding: 2px var(--space-1);
  border-radius: var(--radius-sm);
  transition: background 0.15s;
}

.edit-attachment__remove:hover {
  background: var(--color-danger-50);
}

.edit-attachment__drag-handle {
  cursor: grab;
  color: var(--color-ink-lighter);
  padding: 2px;
  border-radius: var(--radius-sm);
  transition: color 0.15s;
}
.edit-attachment__drag-handle:hover {
  color: var(--color-ink);
}
.edit-attachment__drag-handle:active {
  cursor: grabbing;
}

/* Drag-sort shared styles */
.drag-sort--dragging {
  opacity: 0.4;
}

/* Sortable form rows (phone numbers, addresses, etc.) */
.sortable-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.sortable-row--block {
  align-items: stretch;
}

.sortable-row__handle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: grab;
  color: var(--color-ink-light);
  padding: var(--space-1);
  border-radius: var(--radius-sm);
  flex-shrink: 0;
}

.sortable-row__handle:hover {
  color: var(--color-ink);
  background: var(--color-surface-subtle);
}

.sortable-row__handle:active {
  cursor: grabbing;
}

.sortable-row--block .sortable-row__handle {
  align-self: center;
  margin-left: var(--space-2);
}

.sortable-row__primary {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--text-xs);
  color: var(--color-ink-light);
  margin-bottom: 0;
  cursor: pointer;
  white-space: nowrap;
}

/* Bulk-actions toolbar */
.bulk-toolbar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  background: var(--color-surface-subtle);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
  margin-bottom: var(--space-3);
}

.bulk-toolbar--hidden {
  visibility: hidden;
}

.bulk-toolbar__count {
  color: var(--color-ink);
  font-weight: 500;
}

.bulk-toolbar__menu-wrap {
  position: relative;
  margin-left: auto;
}

.bulk-toolbar__menu {
  position: absolute;
  top: calc(100% + var(--space-1));
  right: 0;
  z-index: 20;
  min-width: 180px;
  background: var(--color-canvas);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md, 0 4px 12px rgba(0, 0, 0, 0.12));
  padding: var(--space-1) 0;
}

.bulk-toolbar__menu[hidden] {
  display: none;
}

.bulk-toolbar__menu-item {
  display: block;
  width: 100%;
  padding: var(--space-2) var(--space-3);
  background: transparent;
  border: 0;
  text-align: left;
  font-size: var(--text-sm);
  color: var(--color-ink);
  cursor: pointer;
}

.bulk-toolbar__menu-item:hover {
  background: var(--color-surface-subtle);
}

.bulk-toolbar__menu-empty {
  display: block;
  padding: var(--space-3);
  text-align: center;
  font-size: var(--text-xs);
  color: var(--color-ink-light);
}

/* Class-assign dialog */
.class-assign-dialog {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
}

.class-assign-dialog[hidden] {
  display: none;
}

.class-assign-dialog__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
}

.class-assign-dialog__panel {
  position: relative;
  z-index: 1;
  min-width: 340px;
  max-width: 480px;
}

/* Bulk-selectable table rows */
.bulk-checkbox-cell {
  cursor: pointer;
  user-select: none;
}

.bulk-checkbox {
  width: 18px;
  height: 18px;
  cursor: pointer;
  accent-color: var(--color-accent, var(--color-ink));
  pointer-events: none;
}

tr:has(.bulk-checkbox:checked) {
  background: color-mix(in srgb, var(--color-accent, var(--color-primary-600)) 6%, transparent);
}

/* Filter input (paired with filterable-list controller) */
.filter-input {
  position: relative;
  display: flex;
  align-items: center;
}

.filter-input__icon {
  position: absolute;
  left: var(--space-3);
  display: inline-flex;
  color: var(--color-ink-light);
  pointer-events: none;
}

input[type="search"].filter-input__field {
  padding: var(--space-2) var(--space-8) var(--space-2) calc(var(--space-3) + 18px);
  font-size: var(--text-sm);
}

.filter-input__field::placeholder {
  color: var(--color-ink-light);
}

.filter-input__field:focus {
  outline: 2px solid var(--color-accent, var(--color-ink));
  outline-offset: -1px;
  border-color: transparent;
}

/* Hide the native search clear button so we can show our own */
.filter-input__field::-webkit-search-cancel-button {
  -webkit-appearance: none;
  appearance: none;
}

.filter-input__clear {
  position: absolute;
  right: var(--space-2);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  background: transparent;
  border: 0;
  border-radius: var(--radius-sm);
  cursor: pointer;
  color: var(--color-ink-light);
}

.filter-input__clear:hover {
  background: var(--color-surface-subtle);
  color: var(--color-ink);
}

.filter-input__clear[hidden] {
  display: none;
}

/* Inline SVGs collapse to width:0 inside a fixed-width flex button unless given
   an explicit CSS size, so the × glyph was invisible (only the hover bg showed). */
.filter-input__clear svg {
  width: 14px;
  height: 14px;
  flex: none;
}

/* Sortable table header (paired with sortable-table controller) */
.sort-header {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 0;
  background: transparent;
  border: 0;
  color: inherit;
  font: inherit;
  font-weight: inherit;
  cursor: pointer;
  text-align: left;
  width: 100%;
}

.sort-header--right {
  justify-content: flex-end;
}

.sort-header--center {
  justify-content: center;
}

.sort-header:hover {
  color: var(--color-ink);
  background: transparent;
}

.sort-header__icon {
  display: inline-flex;
  color: var(--color-ink-lighter);
  transition: transform 0.15s, color 0.15s;
}

.sort-header[data-sort-direction] .sort-header__icon {
  color: var(--color-ink);
}

.sort-header[data-sort-direction="asc"] .sort-header__icon {
  transform: rotate(180deg);
}

/* Breadcrumbs */
.breadcrumbs {
  margin-bottom: var(--space-4);
}

.breadcrumbs__list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-1);
  font-size: var(--text-sm);
}

.breadcrumbs__item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  color: var(--color-ink-light);
}

.breadcrumbs__link {
  color: var(--color-ink-light);
  text-decoration: none;
}

.breadcrumbs__link:hover {
  color: var(--color-ink);
  text-decoration: underline;
}

.breadcrumbs__current {
  color: var(--color-ink);
  font-weight: 500;
}

.breadcrumbs__sep {
  display: inline-flex;
  color: var(--color-ink-lighter);
}

.file-preview-thumb {
  cursor: grab;
}
.file-preview-thumb:active {
  cursor: grabbing;
}

/* File attachment link (PDF etc) */
.message-attachment--file {
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  display: inline-block;
}

.message-attachment__file-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--color-ink);
  text-decoration: none;
  font-size: var(--text-sm);
}

.message-attachment__file-link:hover {
  color: var(--color-primary-600);
}

/* Download all */
.classroom-post__download-all {
  margin-top: var(--space-3);
}

.classroom-post__download-all .btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}

/* Feed empty state */
.classroom-feed-empty {
  text-align: center;
  padding: var(--space-8) var(--space-4);
}

/* Two-column feeds — keep combined and scoped feeds aligned */
.classroom-page--with-gallery,
.feed-page--with-sidebar {
  max-width: 1100px;
}

@media (min-width: 1280px) {
  .classroom-page--with-gallery,
  .feed-page--with-sidebar {
    max-width: 1240px;
  }
}

.classroom-page__layout {
  display: grid;
  gap: var(--space-6);
  grid-template-columns: 1fr;
}

@media (min-width: 1024px) {
  .classroom-page__layout {
    grid-template-columns: minmax(0, 1fr) 280px;
    align-items: start;
  }
}

.classroom-page__main {
  min-width: 0;
}

/* Classroom show sidebar (reminders + gallery) */
.classroom-page__sidebar {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  position: sticky;
  top: var(--space-4);
}

/* Pinned Reminders panel */
.pinned-reminders-panel__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin-top: var(--space-3);
}

.pinned-reminders-panel__item {
  display: flex;
  gap: var(--space-2);
  align-items: flex-start;
}

.pinned-reminders-panel__icon {
  flex-shrink: 0;
  margin-top: 2px;
  color: var(--color-primary-600);
}

.pinned-reminders-panel__text {
  font-size: var(--text-sm);
  line-height: 1.5;
  color: var(--color-ink);
  margin: 0;
}

.pinned-reminders-panel__body {
  min-width: 0;
}

/* On a unified feed the items come from several classes/groups, so each names
   (and links to) the one that owns it. */
.pinned-reminders-panel__source {
  display: inline-block;
  margin-top: 2px;
  font-size: var(--text-xs);
  color: var(--color-ink-light);
  text-decoration: none;
}

.pinned-reminders-panel__source:hover {
  color: var(--color-primary-600);
  text-decoration: underline;
}

/* "View all N reminders" — opens the rest in the modal below. */
.pinned-reminders-panel__view-all {
  display: block;
  width: 100%;
  margin-top: var(--space-3);
  padding: var(--space-2) 0 0;
  font: inherit;
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  text-align: left;
  color: var(--color-primary-600);
  background: none;
  border: 0;
  border-top: 1px solid var(--color-border);
  cursor: pointer;
}

.pinned-reminders-panel__view-all:hover {
  text-decoration: underline;
}

.pinned-reminders-panel__view-all[hidden] {
  display: none;
}

/* Full pinned-reminders list, opened from the panel. */
.reminders-dialog {
  width: min(32rem, calc(100vw - 2rem));
  max-height: min(36rem, 80vh);
  padding: 0;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-component-surface);
  color: var(--color-ink);
  overflow: hidden;
}

.reminders-dialog::backdrop {
  background: rgba(0, 0, 0, 0.5);
}

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

.reminders-dialog__close {
  background: transparent;
  border: 0;
  font-size: 1.5rem;
  line-height: 1;
  color: var(--color-ink-light);
  cursor: pointer;
  padding: 0 var(--space-1);
}

.reminders-dialog__close:hover {
  color: var(--color-ink);
}

/* The list scrolls, not the dialog, so the header stays put. */
.reminders-dialog__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-5);
  max-height: calc(min(36rem, 80vh) - 4.5rem);
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* Pinned Reminders dialog */
.pinned-reminders-dialog {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
}

.pinned-reminders-dialog[hidden] {
  display: none;
}

.pinned-reminders-dialog__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
}

.pinned-reminders-dialog__panel {
  position: relative;
  z-index: 1;
  width: min(480px, calc(100vw - 2rem));
  max-height: calc(100vh - 4rem);
  overflow-y: auto;
}

.pinned-reminders-dialog__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--space-4);
}

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

.pinned-reminders-dialog__item {
  padding-bottom: var(--space-3);
  border-bottom: 1px solid var(--color-border);
}

.pinned-reminders-dialog__item:last-child {
  border-bottom: none;
  padding-bottom: 0;
}

.pinned-reminders-dialog__edit-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  flex: 1;
  min-width: 0;
}

.pinned-reminders-dialog__item-top {
  display: flex;
  gap: var(--space-2);
  align-items: flex-start;
}

.pinned-reminders-dialog__item-bottom {
  display: flex;
  gap: var(--space-2);
  align-items: center;
  justify-content: flex-end;
  padding-left: calc(16px + var(--space-2));
  padding-top: 5px;
}

.pinned-reminders-dialog__drag-handle {
  flex-shrink: 0;
  cursor: grab;
  color: var(--color-ink-lighter);
  padding: var(--space-2) 0;
}

.pinned-reminders-dialog__drag-handle:active {
  cursor: grabbing;
}

.pinned-reminders-dialog__item.drag-sort--dragging {
  opacity: 0.5;
}

.pinned-reminders-dialog__input {
  width: 100%;
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-sm);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-canvas);
  color: var(--color-ink);
  resize: none;
  overflow: hidden;
}

.pinned-reminders-dialog__item-actions {
  display: flex;
  gap: var(--space-2);
  align-items: center;
  justify-content: flex-end;
}

.pinned-reminders-dialog__item-bottom .btn {
  font-size: var(--text-xs);
  padding: var(--space-1) var(--space-3);
}

.pinned-reminders-dialog__item-bottom form {
  display: inline;
}

.pinned-reminders-dialog__new {
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-border);
}

.pinned-reminders-dialog__new-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.btn--danger-text {
  color: var(--color-danger-600, #dc2626);
}

.btn--danger-text:hover {
  color: var(--color-danger-700, #b91c1c);
}

/* Gallery preview panel (classroom show sidebar) */
.gallery-panel {
}

.gallery-panel__header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: var(--space-3);
}

.gallery-panel__title {
  font-size: var(--text-base);
  font-weight: 600;
  margin: 0;
}

.gallery-panel__view-all {
  color: var(--color-accent, var(--color-ink));
  text-decoration: none;
}

.gallery-panel__view-all:hover {
  text-decoration: underline;
}

.gallery-panel__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-2);
}

.gallery-panel__item {
  cursor: pointer;
}

/* Gallery thumb (presentational) */
.gallery-thumb {
  position: relative;
  aspect-ratio: 1;
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--color-surface-subtle, #f3f3f3);
}

.gallery-thumb__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.gallery-thumb__play {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  background: rgba(0, 0, 0, 0.25);
  pointer-events: none;
}

/* Full gallery index page */
.gallery-toolbar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  margin-bottom: var(--space-3);
  background: var(--color-surface-subtle);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  position: sticky;
  top: var(--space-2);
  z-index: 10;
}

.gallery-toolbar__select-all {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: 0;
  cursor: pointer;
  font-size: var(--text-sm);
}

.gallery-toolbar__select-all input {
  width: 18px;
  height: 18px;
  cursor: pointer;
  accent-color: var(--color-accent, var(--color-ink));
}

.gallery-toolbar__count {
  margin-left: auto;
}

.gallery-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: var(--space-3);
}

.gallery-cell {
  position: relative;
  display: block;
  cursor: pointer;
  border-radius: var(--radius-md);
  overflow: hidden;
  outline: 2px solid transparent;
  outline-offset: 2px;
  transition: outline-color 0.15s;
}

.gallery-cell:has(.gallery-cell__checkbox:checked) {
  outline-color: var(--color-accent, var(--color-ink));
}

.gallery-cell__checkbox {
  position: absolute;
  top: var(--space-2);
  left: var(--space-2);
  width: 20px;
  height: 20px;
  z-index: 2;
  cursor: pointer;
  accent-color: var(--color-accent, var(--color-ink));
}

.gallery-cell:has(.gallery-cell__checkbox:checked) .gallery-thumb__img {
  opacity: 0.85;
}

.gallery-pagination {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-6);
}

/* Download status (background zip prep) */
.download-status-card {
  max-width: 480px;
  margin: var(--space-6) auto 0;
}

.download-status {
  text-align: center;
  padding: var(--space-6) var(--space-4);
}

.download-status__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 64px;
  border-radius: 50%;
  margin-bottom: var(--space-4);
}

.download-status__icon--spinner {
  background: var(--color-surface-subtle, #f3f3f3);
  color: var(--color-ink-light);
  animation: download-status-spin 1.2s linear infinite;
}

.download-status__icon--ready {
  background: rgba(34, 197, 94, 0.12);
  color: rgb(22, 163, 74);
}

.download-status__icon--failed {
  background: rgba(239, 68, 68, 0.12);
  color: rgb(220, 38, 38);
}

.download-status__title {
  font-size: var(--text-lg);
  font-weight: 600;
  margin: 0 0 var(--space-2);
}

.download-status__msg {
  margin: 0;
}

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

/* ==========================================================================
   Lunch Calendar (Admin)
   ========================================================================== */

.lunch-calendar__header {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 1px;
  margin: 0 auto 1px;
  max-width: 720px;
}

.lunch-calendar__day-name {
  text-align: center;
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  color: var(--color-ink-light);
  padding: var(--space-2);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.lunch-calendar__grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 1px;
  background: var(--color-border);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  overflow: hidden;
}

.lunch-calendar__cell {
  background: var(--color-canvas);
  padding: var(--space-3);
  min-height: 140px;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.lunch-calendar__cell--empty {
  background: var(--color-surface-subtle);
}

.lunch-calendar__cell--off {
  background: color-mix(in srgb, var(--color-warning-500) 8%, var(--color-canvas));
}

.lunch-calendar__cell--has-menu {
  background: color-mix(in srgb, var(--color-success-500) 6%, var(--color-canvas));
}

.lunch-calendar__date {
  display: flex;
  align-items: baseline;
  gap: var(--space-1);
}

.lunch-calendar__date-num {
  font-weight: var(--font-semibold);
  font-size: var(--text-sm);
}

.lunch-calendar__date-day {
  font-size: var(--text-xs);
  color: var(--color-ink-light);
}

.lunch-calendar__label {
  font-size: var(--text-xs);
  color: var(--color-warning-700, #a16207);
  font-style: italic;
  margin: 0;
}

.lunch-calendar__meals {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 1;
}

.lunch-calendar__meal {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-2);
}

.lunch-calendar__actions {
  display: flex;
  gap: var(--space-1);
  flex-wrap: wrap;
  margin-top: auto;
}

.lunch-calendar__actions .btn {
  font-size: 0.65rem;
  padding: 2px 6px;
}

/* Lunch Meal Row (nested fields in menu form) */

.lunch-meal-row {
  display: flex;
  gap: var(--space-2);
  align-items: center;
  margin-bottom: var(--space-2);
}

.lunch-meal-row .form-group {
  margin-bottom: 0;
}

/* ==========================================================================
   Lunch Order Form (Parent-facing)
   ========================================================================== */

.lunch-order-table {
  width: 100%;
  border-collapse: collapse;
}

.lunch-order-table th {
  text-align: left;
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  color: var(--color-ink-light);
  text-transform: uppercase;
  border-bottom: 2px solid var(--color-border);
}

.lunch-order-table td {
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--color-border);
  font-size: var(--text-sm);
  vertical-align: middle;
}

.lunch-order-table tr.lunch-order-table__off-day td {
  color: var(--color-ink-lighter);
  font-style: italic;
}

.lunch-order-table tr.lunch-order-table__row--selected {
  background: color-mix(in srgb, var(--color-primary-600) 10%, transparent);
}

.lunch-order-table tr.lunch-order-table__row--selected td:first-child {
  border-left: 3px solid var(--color-primary-600);
}

.lunch-order-layout {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin-bottom: var(--space-4);
}

@media (min-width: 1024px) {
  .lunch-order-layout {
    flex-direction: row;
    align-items: flex-start;
  }

  .lunch-order-layout__calendar {
    flex: 0 0 auto;
    position: sticky;
    top: var(--space-4);
  }

  .lunch-order-layout__table {
    flex: 1;
    min-width: 0;
  }

  .lunch-order-layout .lunch-menu-calendar,
  .lunch-order-layout .lunch-selection-calendar,
  .lunch-order-layout .lunch-selection-calendar .lunch-calendar__header {
    margin: 0;
  }
}

/* Lunch Order Selection Calendar */

.lunch-selection-calendar__cell {
  transition: background var(--transition-fast);
}

.lunch-selection-calendar__cell--selected {
  background: color-mix(in srgb, var(--color-primary-600) 12%, var(--color-canvas)) !important;
  border: 1px solid color-mix(in srgb, var(--color-primary-600) 40%, transparent);
}

.lunch-selection-calendar__cell--skipped {
  background: color-mix(in srgb, var(--color-ink-light) 12%, var(--color-component-surface)) !important;
  border: 1px solid var(--color-ink-light);
}

.lunch-selection-calendar__selection {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-top: var(--space-1);
}

.lunch-selection-calendar__meal {
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  color: var(--color-ink);
}

.lunch-selection-calendar__price {
  font-size: 0.65rem;
  color: var(--color-ink-light);
}

.lunch-selection-calendar__skip {
  font-size: var(--text-xs);
  font-style: italic;
  color: var(--color-ink-lighter);
}

.lunch-selection-calendar__empty {
  font-size: var(--text-xs);
  color: var(--color-ink-lighter);
}

.lunch-order-choices {
  display: grid;
  grid-auto-columns: 1fr;
  grid-auto-flow: column;
  gap: var(--space-2);
}

.lunch-order-choice {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: var(--space-2) var(--space-3);
  min-height: 3.25rem;
  text-align: center;
  background: var(--color-component-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: background var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);
  margin: 0;
}

.lunch-order-choice:hover {
  background: color-mix(in srgb, var(--color-primary-600) 6%, var(--color-component-surface));
  border-color: color-mix(in srgb, var(--color-primary-600) 30%, var(--color-border));
}

.lunch-order-choice input[type="radio"] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.lunch-order-choice__title {
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  color: var(--color-ink);
}

.lunch-order-choice__price {
  font-size: var(--text-xs);
  color: var(--color-ink-light);
}

.lunch-order-choice--active {
  background: color-mix(in srgb, var(--color-primary-600) 15%, var(--color-component-surface));
  border-color: var(--color-primary-600);
}

.lunch-order-choice--active .lunch-order-choice__title {
  color: var(--color-primary-600);
  font-weight: var(--font-semibold);
}

.lunch-order-choice--active .lunch-order-choice__price {
  color: var(--color-primary-600);
}

.lunch-order-choice--skip.lunch-order-choice--active {
  background: color-mix(in srgb, var(--color-ink-light) 12%, var(--color-component-surface));
  border-color: var(--color-ink-light);
}

.lunch-order-choice--skip.lunch-order-choice--active .lunch-order-choice__title {
  color: var(--color-ink);
}

.lunch-order-choice--unavailable {
  opacity: 0.4;
  cursor: not-allowed;
  text-decoration: line-through;
}
.lunch-order-choice--unavailable:hover {
  background: var(--color-component-surface);
  border-color: var(--color-border);
}

@media (max-width: 640px) {
  .lunch-order-choices {
    grid-auto-flow: row;
    grid-auto-columns: auto;
  }
}

.lunch-order-total {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4);
  font-size: var(--text-lg);
  font-weight: var(--font-semibold);
}

/* Lunch month show (parent-facing calendar) */

.lunch-menu-calendar {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 1px;
  background: var(--color-border);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  overflow: hidden;
  max-width: 720px;
  margin: 0 auto;
}

.lunch-month-nav {
  min-width: 28px;
  padding-left: var(--space-2);
  padding-right: var(--space-2);
  font-weight: var(--font-semibold);
  line-height: 1;
}

.lunch-month-nav:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.lunch-month-deadline-slot {
  display: inline-flex;
  align-items: center;
  min-width: 13rem;
  min-height: 1.75rem;
}

/* Bulk order layout (menu on left, per-student panels on right) */
.lunch-bulk__layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr);
  gap: var(--space-4);
  align-items: start;
}

@media (max-width: 1100px) {
  .lunch-bulk__layout {
    grid-template-columns: 1fr;
  }
}

.lunch-bulk__menu {
  position: sticky;
  top: var(--space-4);
}

.lunch-bulk__students {
  min-width: 0;
}

.lunch-bulk__student .lunch-order-table {
  width: 100%;
}

.lunch-bulk__row--missing > td {
  background: color-mix(in srgb, var(--color-warning-500) 18%, transparent);
  border-left: 3px solid var(--color-warning-500);
}

.lunch-bulk__row--missing > td:first-child {
  position: relative;
}

/* Lunch order dropdown (Submit Orders ▾) */
.lunch-order-dropdown {
  position: relative;
  display: inline-flex;
}

.lunch-order-dropdown__trigger {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}

.lunch-order-dropdown__caret {
  font-size: 0.65rem;
}

.lunch-order-dropdown__menu {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  min-width: 200px;
  background: var(--color-component-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
  padding: var(--space-1);
  z-index: 30;
}

.lunch-order-dropdown__item {
  display: block;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--color-ink);
  text-decoration: none;
  font-size: var(--text-sm);
}

.lunch-order-dropdown__item:hover {
  background: color-mix(in srgb, var(--theme-primary) 8%, transparent);
}

.lunch-order-dropdown__item--strong {
  font-weight: var(--font-semibold);
}

.lunch-order-dropdown__divider {
  height: 1px;
  margin: var(--space-1) 0;
  background: var(--color-border);
}

/* Public fundraiser shell */
.public-body {
  background: var(--color-canvas);
  color: var(--color-ink);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

.public-shell {
  width: 100%;
  max-width: 960px;
  margin: 0 auto;
  padding: var(--space-6) var(--space-4);
  flex: 1;
}

.public-shell__header {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding-bottom: var(--space-4);
  margin-bottom: var(--space-6);
  border-bottom: 1px solid var(--color-border);
}

.public-shell__header-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  text-decoration: none;
  color: inherit;
}

.public-shell__header-link:hover .public-shell__school-name {
  text-decoration: underline;
}

.public-shell__logo {
  width: 48px;
  height: 48px;
  border-radius: var(--radius-md);
  object-fit: contain;
}

.public-shell__school-name {
  font-size: var(--text-lg);
  font-weight: var(--font-semibold);
  color: var(--color-ink);
}

.public-shell__content {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

/* Error pages (app/views/errors) — rendered inside .public-shell, so they pick
   up the school's --brand-primary when there is one. */
.error-page {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-4);
  padding: var(--space-12) var(--space-4);
  max-width: 34rem;
  margin: 0 auto;
}

.error-page__code {
  font-family: var(--font-heading);
  font-size: clamp(4rem, 18vw, 7rem);
  line-height: var(--leading-none);
  letter-spacing: -0.02em;
  color: color-mix(in srgb, var(--brand-primary, var(--theme-primary)) 22%, transparent);
  margin: 0;
}

.error-page__heading {
  font-size: var(--text-3xl);
  font-weight: var(--font-semibold);
  line-height: var(--leading-tight);
  color: var(--color-ink);
  margin: 0;
}

.error-page__message {
  font-size: var(--text-base);
  line-height: var(--leading-relaxed);
  color: var(--color-ink-light);
  margin: 0;
}

.error-page__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-3);
  margin-top: var(--space-2);
}

.error-page__reference {
  font-size: var(--text-xs);
  color: var(--color-ink-lighter);
  margin: var(--space-4) 0 0;
}

.error-page__reference code {
  font-family: var(--font-mono);
  background: var(--color-code-bg);
  border-radius: var(--radius-sm);
  padding: 0 var(--space-1);
}

.fundraiser-hero-image {
  border-radius: var(--radius-lg);
  overflow: hidden;
  aspect-ratio: 16 / 7;
  background: var(--color-component-surface);
}

.fundraiser-hero-image__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.fundraiser-hero {
  text-align: center;
  padding: var(--space-6) var(--space-4);
  background: color-mix(in srgb, var(--brand-primary, var(--color-primary-500)) 6%, transparent);
  border-radius: var(--radius-lg);
}

.fundraiser-hero--with-image {
  border-top-left-radius: 0;
  border-top-right-radius: 0;
  margin-top: calc(-1 * var(--space-6));
}

.fundraiser-gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: var(--space-3);
}

.fundraiser-gallery__item {
  display: block;
  padding: 0;
  margin: 0;
  border: 0;
  background: transparent;
  cursor: zoom-in;
  border-radius: var(--radius-md);
  overflow: hidden;
  transition: transform var(--transition-fast), box-shadow var(--transition-fast);
}

.fundraiser-gallery__item:hover {
  transform: scale(1.02);
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.25);
}

.fundraiser-gallery__img {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: var(--radius-md);
  display: block;
}

/* Manage fundraiser edit form: stacks on narrow screens, two columns
   (details | hero+gallery) once there's room. */
.fundraiser-form-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-4);
  align-items: start;
  max-width: 800px;
}

.fundraiser-form-grid__side {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  min-width: 0;
}

@media (min-width: 1200px) {
  .fundraiser-form-grid {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    max-width: 1640px;
  }
}

/* Existing images shown below the upload picker, set off by a divider. */
.gallery-section__current {
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-border);
}

.gallery-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: var(--space-2);
}

.gallery-tile {
  position: relative;
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--color-component-surface);
  border: 1px solid var(--color-border);
}

.gallery-tile__order {
  position: absolute;
  top: var(--space-1);
  left: var(--space-1);
  display: flex;
  flex-direction: column;
  gap: 2px;
  z-index: 2;
}

.gallery-tile__order-btn {
  width: 26px;
  height: 26px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.6);
  color: white;
  border: 0;
  border-radius: var(--radius-sm);
  cursor: pointer;
  padding: 0;
}

.gallery-tile__order-btn:hover {
  background: rgba(0, 0, 0, 0.85);
}

.gallery-tile.dragging {
  opacity: 0.5;
}

.gallery-tile.dragover {
  outline: 2px dashed var(--brand-primary, var(--color-primary-500));
  outline-offset: -2px;
}

.gallery-tile__img {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  display: block;
}

/* Hero preview reuses the gallery-tile remove toggle + red-tint treatment
   but keeps the banner's 2:1 aspect ratio instead of a square tile. */
.gallery-tile--hero {
  width: 100%;
  max-width: 480px;
}

.gallery-tile__img--hero {
  aspect-ratio: 2 / 1;
}

/* ==========================================================================
   Fundraiser registration — optional merchandise
   ========================================================================== */

.registration-add-on {
  display: grid;
  grid-template-columns: 104px minmax(0, 1fr);
  gap: var(--space-4);
  align-items: start;
  padding: var(--space-4);
  margin-bottom: var(--space-3);
  background: var(--color-component-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}

/* In the basket: a quiet ring rather than a fill, so the photo stays the focus. */
.registration-add-on--selected {
  border-color: var(--brand-primary, var(--theme-primary));
  box-shadow: 0 0 0 1px var(--brand-primary, var(--theme-primary));
}

.registration-add-on__media {
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--color-white);
  border: 1px solid var(--color-border);
}

.registration-add-on__image {
  display: block;
  width: 100%;
  aspect-ratio: 1;
  object-fit: contain;
}

.registration-add-on__image--empty {
  background: var(--color-surface-subtle);
}

.registration-add-on__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
}

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

.registration-add-on__name {
  margin: 0;
  font-size: var(--text-base);
  font-weight: var(--font-semibold);
  line-height: var(--leading-snug);
  color: var(--color-ink);
  min-width: 0;
}

.registration-add-on__price {
  flex-shrink: 0;
  font-size: var(--text-base);
  font-weight: var(--font-semibold);
  color: var(--color-ink);
  font-variant-numeric: tabular-nums;
}

/* Pill rather than a plain line — it reads as metadata, not instructions. */
.registration-add-on__fulfillment {
  align-self: start;
  margin: 0;
  padding: 2px var(--space-2);
  border-radius: var(--radius-full);
  background: var(--color-surface-subtle);
  color: var(--color-ink-light);
  font-size: var(--text-xs);
  white-space: nowrap;
}

.registration-add-on__details {
  margin: 0;
  font-size: var(--text-sm);
}

/* inline-flex + gap keeps the chevron off the label; rotating it in place (rather
   than as trailing text) stops it colliding with the panel once it's open. */
.registration-add-on__details summary {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  width: fit-content;
  cursor: pointer;
  color: var(--color-link);
  font-size: var(--text-sm);
  list-style: none;
}

.registration-add-on__details summary::-webkit-details-marker { display: none; }

.registration-add-on__details summary::after {
  content: "›";
  display: block;
  width: 0.5rem;
  font-size: var(--text-base);
  line-height: 1;
  text-align: center;
  transition: transform var(--transition-fast);
}

.registration-add-on__details[open] summary::after {
  transform: rotate(90deg);
}

.registration-add-on__details[open] > :not(summary) {
  margin-top: var(--space-2);
}

.registration-add-on__controls {
  display: flex;
  align-items: end;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-top: var(--space-1);
}

/* Pushed to the right edge so the stepper lands in the same place on every card,
   whether or not the item has a variant select to its left. */
.registration-add-on__qty {
  margin-left: auto;
}

.registration-add-on__qty label {
  text-align: right;
}

@media (max-width: 30rem) {
  .registration-add-on {
    grid-template-columns: 72px minmax(0, 1fr);
    gap: var(--space-3);
  }

  .registration-add-on__heading {
    flex-direction: column;
    align-items: start;
    gap: var(--space-1);
  }
}

/* Quantity stepper — bigger tap targets than a bare number spinner. */
.qty-stepper {
  display: inline-flex;
  align-items: stretch;
  border: 1px solid var(--color-border-dark);
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--color-canvas);
}

.qty-stepper__btn {
  width: 2.25rem;
  padding: 0;
  border: none;
  border-radius: 0;
  background: transparent;
  color: var(--color-ink);
  font-size: var(--text-lg);
  line-height: 1;
  cursor: pointer;
}

.qty-stepper__btn:hover:not(:disabled) {
  background: var(--color-surface-subtle);
}

.qty-stepper__btn:disabled {
  color: var(--color-ink-lighter);
  cursor: default;
  opacity: 1;
}

.qty-stepper__input.qty-stepper__input {
  width: 3rem;
  border: none;
  border-left: 1px solid var(--color-border);
  border-right: 1px solid var(--color-border);
  border-radius: 0;
  background: transparent;
  text-align: center;
  font-variant-numeric: tabular-nums;
  -moz-appearance: textfield;
}

.qty-stepper__input::-webkit-outer-spin-button,
.qty-stepper__input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.qty-stepper:focus-within {
  border-color: var(--theme-primary);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--theme-primary) 25%, transparent);
}

.qty-stepper__input:focus {
  outline: none;
  box-shadow: none;
}

/* Marks the image shoppers see first (product form). */
.gallery-tile__badge {
  position: absolute;
  bottom: var(--space-1);
  left: var(--space-1);
  z-index: 2;
  padding: 2px 6px;
  border-radius: var(--radius-sm);
  background: rgba(0, 0, 0, 0.6);
  color: white;
  font-size: var(--text-xs);
  font-weight: var(--font-medium);
  letter-spacing: 0.02em;
}

.gallery-tile:has(input:checked) .gallery-tile__badge {
  display: none;
}

.gallery-tile__remove {
  position: absolute;
  top: var(--space-1);
  right: var(--space-1);
  background: rgba(0, 0, 0, 0.6);
  color: white;
  border-radius: var(--radius-sm);
  font-size: var(--text-xs);
  padding: 4px 8px;
  cursor: pointer;
  user-select: none;
}

.gallery-tile__remove:hover {
  background: var(--color-danger-500, #dc2626);
}

/* Red tint overlay shown when this tile is marked for removal */
.gallery-tile:has(input:checked)::before {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(220, 38, 38, 0.55);
  z-index: 1;
  pointer-events: none;
  border-radius: inherit;
}

/* Hide the processed/processing status badge when marked for removal */
.gallery-tile:has(input:checked) .gallery-tile__status {
  display: none;
}

.gallery-tile:has(input:checked) .gallery-tile__remove {
  background: var(--color-danger-500, #dc2626);
  z-index: 2;
}

.gallery-tile:has(input:checked) .gallery-tile__order {
  z-index: 2;
}

/* "Will be removed" label centered over the red tint */
.gallery-tile:has(input:checked)::after {
  content: "Will be removed";
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  color: white;
  font-size: var(--text-sm);
  font-weight: var(--font-bold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.55);
  z-index: 2;
  pointer-events: none;
  padding: 0 var(--space-2);
}

.qr-share {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  flex-wrap: wrap;
}

.qr-share__code {
  background: white;
  padding: var(--space-2);
  border-radius: var(--radius-md);
  flex-shrink: 0;
  width: 200px;
  height: 200px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.qr-share__code svg {
  width: 100%;
  height: 100%;
  display: block;
}

.qr-share__body {
  flex: 1;
  min-width: 220px;
}

.qr-share__url {
  display: inline-block;
  word-break: break-all;
  background: var(--color-component-surface);
  border: 1px solid var(--color-border);
  padding: var(--space-2);
  border-radius: var(--radius-sm);
  font-size: var(--text-xs);
  color: var(--color-ink);
}

.fundraiser-rank {
  margin: var(--space-3) 0 0;
  font-size: var(--text-sm);
  color: var(--color-ink-light);
}

.fundraiser-rank strong {
  color: var(--brand-primary, var(--color-primary-600));
  font-weight: var(--font-semibold);
}

.qr-dialog {
  max-width: 360px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  background: var(--color-component-surface);
  color: var(--color-ink);
}

.qr-dialog::backdrop {
  background: rgba(0, 0, 0, 0.5);
}

.qr-dialog__close {
  position: absolute;
  top: var(--space-2);
  right: var(--space-2);
  background: transparent;
  border: 0;
  font-size: 1.25rem;
  line-height: 1;
  color: var(--color-ink-light);
  cursor: pointer;
  padding: 4px 8px;
}

.qr-dialog__close:hover {
  color: var(--color-ink);
}

.qr-dialog__img {
  display: block;
  width: 280px;
  height: 280px;
  margin: 0 auto var(--space-3);
  background: white;
  padding: var(--space-2);
  border-radius: var(--radius-md);
}

.qr-dialog__url {
  display: block;
  word-break: break-all;
  font-size: var(--text-xs);
  color: var(--color-ink-light);
  text-align: center;
}

.import-result-dialog {
  position: relative;
  max-width: 420px;
  width: calc(100vw - var(--space-8));
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  background: var(--color-component-surface);
  color: var(--color-ink);
}

.import-result-dialog::backdrop {
  background: rgba(0, 0, 0, 0.5);
}

.import-result-dialog__list {
  margin: 0;
  padding-left: var(--space-4);
  display: grid;
  gap: var(--space-1);
}

.import-result-dialog__list li {
  font-size: var(--text-sm);
}

.fundraiser-hero__eyebrow {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-ink-light);
  margin-bottom: var(--space-2);
}

.fundraiser-hero__title {
  font-size: 2rem;
  font-weight: var(--font-bold);
  margin: 0 0 var(--space-2);
}

.fundraiser-hero__countdown,
.fundraiser-hero__meta {
  color: var(--color-ink-light);
  margin: 0 0 var(--space-4);
}

.fundraiser-hero__cta {
  margin-top: var(--space-4);
}

.fundraiser-hero__actions {
  display: flex;
  gap: var(--space-2);
  justify-content: center;
  flex-wrap: wrap;
  margin-top: var(--space-4);
}

/* When the sponsorship grid collapses to one column on narrow screens,
   center the card content so it doesn't read as an awkward left-aligned column. */
@media (max-width: 640px) {
  .fundraiser-sponsor-tier .card__body {
    text-align: center;
  }
  .fundraiser-sponsor-tier .card__body .lexxy-content ul,
  .fundraiser-sponsor-tier .card__body .lexxy-content ol {
    text-align: left;
    display: inline-block;
    margin-left: auto;
    margin-right: auto;
  }
  .fundraiser-section__title {
    text-align: center;
  }
}

.fundraiser-progress {
  max-width: 480px;
  margin: var(--space-4) auto;
}

.fundraiser-progress__amounts {
  display: flex;
  justify-content: center;
  align-items: baseline;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}

.fundraiser-progress__raised {
  font-size: 1.75rem;
  font-weight: var(--font-bold);
  color: var(--brand-primary, var(--color-primary-600));
}

.fundraiser-progress__goal {
  color: var(--color-ink-light);
  font-size: var(--text-sm);
}

.fundraiser-progress__bar {
  height: 12px;
  background: var(--color-component-surface);
  border-radius: var(--radius-full);
  overflow: hidden;
  border: 1px solid var(--color-border);
}

.fundraiser-progress__fill {
  height: 100%;
  background: var(--brand-primary, var(--color-primary-500));
  transition: width var(--transition-normal);
}

.fundraiser-progress__percent {
  text-align: center;
  font-size: var(--text-xs);
  color: var(--color-ink-light);
  margin-top: var(--space-2);
}

/* Thermometer goal bar — milestone marks at 25/50/75/100 are prize levels */
.thermometer {
  --thermometer-tube-height: 30px;
  --thermometer-bulb-size: 50px;
  --thermometer-bulb-overlap: -15px;
  --thermometer-mercury: var(--brand-primary, var(--color-primary-500));
  display: flex;
  align-items: center;
  padding: var(--space-2) var(--space-4) 1.75rem;
}

/* The thermometer variant is the hero moment — give it room to breathe */
.fundraiser-progress:not(.fundraiser-progress--compact) {
  max-width: 600px;
}

.fundraiser-progress:not(.fundraiser-progress--compact) .fundraiser-progress__raised {
  font-size: 2.25rem;
}

.fundraiser-progress:not(.fundraiser-progress--compact) .fundraiser-progress__goal {
  font-size: var(--text-base);
}

.fundraiser-progress:not(.fundraiser-progress--compact) .fundraiser-progress__percent {
  font-size: var(--text-sm);
}

.thermometer__bulb {
  position: relative;
  z-index: 1; /* sits on top of the tube so the two read as one vessel */
  flex: none;
  width: var(--thermometer-bulb-size);
  height: var(--thermometer-bulb-size);
  margin-right: var(--thermometer-bulb-overlap);
  border: 1px solid var(--color-border-dark);
  border-radius: var(--radius-full);
  background: var(--color-component-surface);
  box-shadow: inset 0 2px 3px rgb(0 0 0 / 12%);
}

.thermometer__bulb.is-filled {
  background: var(--thermometer-mercury);
  border-color: var(--thermometer-mercury);
}

.thermometer__tube {
  position: relative;
  flex: 1;
  height: var(--thermometer-tube-height);
  border: 1px solid var(--color-border-dark);
  border-radius: var(--radius-full);
  background: var(--color-component-surface);
  box-shadow: inset 0 1px 2px rgb(0 0 0 / 12%);
}

.thermometer__mercury {
  height: 100%;
  border-radius: var(--radius-full);
  background: linear-gradient(
    to right,
    color-mix(in srgb, var(--thermometer-mercury) 75%, white),
    var(--thermometer-mercury)
  );
  transition: width var(--transition-normal);
}

.thermometer__mark {
  position: absolute;
  top: 0;
  bottom: 0;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  pointer-events: none;
}

.thermometer__tick {
  width: 3px;
  height: 100%;
  border-radius: 2px;
  background: var(--color-border-dark);
}

/* The 100% tick sits on the tube's rounded cap — pull it just inside */
.thermometer__mark[style*="left: 100%"] {
  transform: translateX(-100%);
}

.thermometer__mark[style*="left: 100%"] .thermometer__label {
  transform: translateX(-30%);
}

.thermometer__mark.is-reached .thermometer__tick {
  background: var(--color-canvas);
  opacity: 0.65;
}

.thermometer__label {
  position: absolute;
  top: calc(100% + var(--space-2));
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
  line-height: var(--leading-none);
  color: var(--color-ink-lighter);
  white-space: nowrap;
}

.thermometer__mark.is-reached .thermometer__label {
  color: var(--thermometer-mercury);
}

@media (max-width: 480px) {
  .thermometer {
    --thermometer-tube-height: 22px;
    --thermometer-bulb-size: 36px;
    --thermometer-bulb-overlap: -11px;
    padding-inline: var(--space-2);
  }

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

  .fundraiser-progress:not(.fundraiser-progress--compact) .fundraiser-progress__raised {
    font-size: 1.75rem;
  }

  .fundraiser-progress:not(.fundraiser-progress--compact) .fundraiser-progress__goal {
    font-size: var(--text-sm);
  }
}

/* Leaderboard tiles are ~250px wide — step the hero sizing back down there,
   or the 75% and 100% labels collide. */
.fundraiser-tile .thermometer {
  --thermometer-tube-height: 16px;
  --thermometer-bulb-size: 26px;
  --thermometer-bulb-overlap: -8px;
  padding: 0 var(--space-1) 1.15rem;
}

.fundraiser-tile .thermometer__label {
  font-size: var(--text-xs);
}

.fundraiser-tile .fundraiser-progress:not(.fundraiser-progress--compact) .fundraiser-progress__raised {
  font-size: 1.5rem;
}

.fundraiser-tile .fundraiser-progress:not(.fundraiser-progress--compact) .fundraiser-progress__goal {
  font-size: var(--text-sm);
}

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

.fundraiser-section {
  background: var(--color-component-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
}

.fundraiser-section__title {
  font-size: 1.25rem;
  font-weight: var(--font-semibold);
  margin: 0 0 var(--space-3);
}

.fundraiser-section__body {
  color: var(--color-ink);
  line-height: 1.6;
}

/* Prize artwork (homework coupons, reward certificates) is uploaded at print
   resolution, and lexxy-content.css lets it span the whole column via
   `max-inline-size: 100%` — which swamps the copy above it. Narrow it to 60%
   across all three tiers.

   Sized on the <figure>, not the <img>: lexxy-content.css gives .attachment
   `inline-size: fit-content`, so a percentage on the image would resolve against
   the figure's own shrink-to-fit width rather than the section. The figure keeps
   its `margin-inline: auto`, so it stays centered. */
.fundraiser-section--prizes .fundraiser-section__body .attachment--preview {
  inline-size: 60%;
}

/* 60% of a phone screen is unreadably small for a coupon, so give it the column. */
@media (max-width: 640px) {
  .fundraiser-section--prizes .fundraiser-section__body .attachment--preview {
    inline-size: 100%;
  }
}

/* Main show view only: the three prize tiers run as columns on desktop rather
   than three stacked full-width panels. The gap matches .public-shell__content
   so the stacked layout below the breakpoint is indistinguishable from the
   sections being direct children. auto-fit (not auto-fill) collapses the empty
   track when a fundraiser only describes one or two tiers, so the panels that
   do render still fill the row. */
.fundraiser-prizes {
  display: grid;
  gap: var(--space-6);
}

@media (min-width: 1024px) {
  .fundraiser-prizes {
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  }

  /* A third of the column is already narrow — the 60% cap above would leave the
     artwork too small to read, so let it fill its column. */
  .fundraiser-prizes .fundraiser-section--prizes .fundraiser-section__body .attachment--preview {
    inline-size: 100%;
  }
}

/* Section heading + subtitle pair (the tabbed index pages) */
.fundraiser-section__heading {
  margin-bottom: var(--space-4);
}

.fundraiser-section__heading .fundraiser-section__title {
  margin-bottom: var(--space-1);
}

/* Public fundraiser tab bar: Main | Classes | Students. Sticks to the top of
   the viewport so the sections stay one tap away while scrolling. */
.fundraiser-tabs {
  position: sticky;
  top: var(--space-2);
  z-index: 20;
  display: flex;
  gap: var(--space-1);
  padding: 4px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  background: color-mix(in srgb, var(--color-canvas) 82%, transparent);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  box-shadow: var(--shadow-sm);
}

/* The highlight behind the current tab. JS sizes it and slides it into place;
   until then the active tab paints its own background (see --ready below). */
.fundraiser-tabs__thumb {
  position: absolute;
  top: 4px;
  bottom: 4px;
  left: 0;
  z-index: 0;
  width: 0;
  border-radius: var(--radius-full);
  background: var(--brand-primary, var(--theme-primary));
  box-shadow: var(--shadow-sm);
  pointer-events: none;
  transition: transform 0.24s ease, width 0.24s ease;
}

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

.fundraiser-tabs__tab {
  flex: 1;
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-full);
  text-decoration: none;
  white-space: nowrap;
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
  color: var(--color-ink-light);
  transition: background var(--transition-fast), color var(--transition-fast);
}

.fundraiser-tabs__icon {
  flex: none;
  width: 16px;
  height: 16px;
}

/* Icon + label + three tabs runs out of room on the narrowest phones. */
@media (max-width: 420px) {
  .fundraiser-tabs__tab {
    gap: var(--space-1);
    padding: var(--space-2) var(--space-2);
  }
}

.fundraiser-tabs__tab:hover {
  background: color-mix(in srgb, var(--brand-primary, var(--theme-primary)) 8%, transparent);
  color: var(--color-ink);
}

.fundraiser-tabs__tab--active,
.fundraiser-tabs__tab--active:hover {
  background: transparent;
  color: var(--color-white);
}

/* No JS, no sliding thumb — fall back to a flat highlight on the active tab. */
.fundraiser-tabs:not(.fundraiser-tabs--ready) .fundraiser-tabs__tab--active {
  background: var(--brand-primary, var(--theme-primary));
  box-shadow: var(--shadow-sm);
}

/* Tile grids for the Classes and Students tabs */
.fundraiser-tile-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: var(--space-3);
}

.fundraiser-tile {
  display: block;
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-canvas);
  text-decoration: none;
  color: inherit;
  transition: transform var(--transition-fast), box-shadow var(--transition-fast), border-color var(--transition-fast);
}

.fundraiser-tile:hover {
  transform: translateY(-2px);
  border-color: color-mix(in srgb, var(--brand-primary, var(--theme-primary)) 35%, transparent);
  box-shadow: var(--shadow-md);
}

.fundraiser-tile__header {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
}

.fundraiser-tile__rank {
  flex: none;
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: var(--radius-full);
  font-size: var(--text-sm);
  font-weight: var(--font-bold);
  font-variant-numeric: tabular-nums;
  background: color-mix(in srgb, var(--brand-primary, var(--color-primary-500)) 12%, transparent);
  color: var(--brand-primary, var(--color-primary-600));
}

/* Podium colors for the top three, so a glance reads the leaders. */
.fundraiser-tile__rank--1 { background: #f5c542; color: #4a3708; }
.fundraiser-tile__rank--2 { background: #cbd2d9; color: #333a41; }
.fundraiser-tile__rank--3 { background: #dda37a; color: #4a2c14; }

.fundraiser-tile__identity {
  min-width: 0;
}

.fundraiser-tile__name {
  margin: 0;
  font-weight: var(--font-semibold);
  color: var(--color-ink);
  overflow-wrap: anywhere;
}

.fundraiser-tile__meta {
  margin: 0;
  font-size: var(--text-xs);
  color: var(--color-ink-light);
  overflow-wrap: anywhere;
}

/* The shared progress block is sized for a full-width hero. Inside a tile it
   needs to sit left-aligned and a couple of steps smaller. */
.fundraiser-tile .fundraiser-progress {
  margin: 0;
}

.fundraiser-tile .fundraiser-progress__amounts {
  justify-content: flex-start;
  flex-wrap: wrap;
  gap: var(--space-1);
}

.fundraiser-tile .fundraiser-progress__raised {
  font-size: var(--text-xl);
}

.fundraiser-tile .fundraiser-progress__goal {
  font-size: var(--text-xs);
}

.fundraiser-tile .fundraiser-progress__bar {
  height: 8px;
}

.fundraiser-tile .fundraiser-progress__percent {
  text-align: left;
}

/* Students tab filter row */
.fundraiser-filters {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}

.fundraiser-filters__search {
  flex: 1 1 220px;
}

/* Sizing only — forms.css already paints the border, background and the
   custom dropdown chevron, and a `background` shorthand here would erase it. */
.fundraiser-filters__select {
  flex: 0 1 200px;
  font-size: var(--text-sm);
}

.fundraiser-filters__count {
  margin: 0 0 var(--space-3);
  text-align: left;
}

/* Pagy centers its info tag; align it with the section heading instead.
   Needs to out-specify `.pagy.info` in application.css, which loads later. */
.fundraiser-filters__count .pagy.info {
  text-align: left;
}

.fundraiser-leaderboards {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-5);
}

@media (max-width: 720px) {
  .fundraiser-leaderboards {
    grid-template-columns: 1fr;
  }
}

/* Donation target: selected-student chips */
.donation-target__chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.donation-target__chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0.25rem 0.25rem 0.25rem 0.625rem;
  background: var(--color-component-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full, 999px);
  font-size: var(--text-sm, 0.875rem);
}

.donation-target__chip button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.25rem;
  height: 1.25rem;
  border: none;
  border-radius: 999px;
  background: var(--color-border);
  color: var(--color-ink);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
}

.donation-target__chip button:hover {
  background: var(--color-ink-light);
  color: var(--color-component-surface);
}

/* Public multi-student registration form */
.registration-students {
  counter-reset: registration-student;
}

.registration-student {
  counter-increment: registration-student;
}

.registration-student__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}

.registration-student__label {
  font-weight: var(--font-semibold);
}

.registration-student__label::before {
  content: "Student " counter(registration-student);
}

.currency-input {
  position: relative;
  display: block;
}

.currency-input__prefix {
  position: absolute;
  left: 0.75rem;
  top: 50%;
  transform: translateY(-50%);
  color: var(--color-ink-light);
  font-weight: var(--font-medium);
  pointer-events: none;
  font-size: var(--text-base);
  line-height: 1;
}

.currency-input input,
.currency-input input[type="text"],
.currency-input input[type="number"] {
  padding-left: 1.75rem;
}

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

.fundraiser-leaderboard__row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--color-border);
}

.fundraiser-leaderboard__row:last-child {
  border-bottom: 0;
}

.fundraiser-leaderboard__rank {
  width: 1.75rem;
  height: 1.75rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--brand-primary, var(--color-primary-500)) 12%, transparent);
  color: var(--brand-primary, var(--color-primary-600));
  border-radius: var(--radius-full);
  font-weight: var(--font-semibold);
  font-size: var(--text-sm);
}

.fundraiser-leaderboard__name {
  color: var(--color-ink);
  text-decoration: none;
}

.fundraiser-leaderboard__amount {
  font-weight: var(--font-semibold);
  color: var(--color-ink);
}

/* In dark mode, the school's brand color (often a deep blue) is too low-contrast
   against the dark canvas. Lift it toward white for these accent uses. */
@media (prefers-color-scheme: dark) {
  :root:not([data-color-scheme="light"]) .fundraiser-rank strong,
  :root:not([data-color-scheme="light"]) .fundraiser-leaderboard__rank,
  :root:not([data-color-scheme="light"]) .fundraiser-tile__rank--plain {
    color: color-mix(in srgb, var(--brand-primary, var(--color-primary-500)) 35%, white);
  }
  :root:not([data-color-scheme="light"]) .fundraiser-leaderboard__rank,
  :root:not([data-color-scheme="light"]) .fundraiser-tile__rank--plain {
    background: color-mix(in srgb, var(--brand-primary, var(--color-primary-500)) 22%, transparent);
  }
}

:root[data-color-scheme="dark"] .fundraiser-rank strong,
:root[data-color-scheme="dark"] .fundraiser-leaderboard__rank,
:root[data-color-scheme="dark"] .fundraiser-tile__rank--plain {
  color: color-mix(in srgb, var(--brand-primary, var(--color-primary-500)) 35%, white);
}
:root[data-color-scheme="dark"] .fundraiser-leaderboard__rank,
:root[data-color-scheme="dark"] .fundraiser-tile__rank--plain {
  background: color-mix(in srgb, var(--brand-primary, var(--color-primary-500)) 22%, transparent);
}

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

.fundraiser-message {
  border-left: 3px solid var(--brand-primary, var(--color-primary-500));
  padding: var(--space-2) var(--space-3);
  background: color-mix(in srgb, var(--brand-primary, var(--color-primary-500)) 4%, transparent);
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
}

.fundraiser-message__body {
  font-style: italic;
  margin: 0 0 var(--space-1);
}

.fundraiser-message__meta {
  font-size: var(--text-xs);
  color: var(--color-ink-light);
  margin: 0;
}

.donation-amount__chips {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
}

.donation-amount__chip {
  flex: 1 1 80px;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-component-surface);
  color: var(--color-ink);
  font-weight: var(--font-semibold);
  cursor: pointer;
  transition: background var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);
}

.donation-amount__chip:hover {
  background: color-mix(in srgb, var(--brand-primary, var(--color-primary-500)) 8%, var(--color-component-surface));
  border-color: color-mix(in srgb, var(--brand-primary, var(--color-primary-500)) 30%, var(--color-border));
}

.donation-amount__chip--active {
  background: color-mix(in srgb, var(--brand-primary, var(--color-primary-500)) 18%, var(--color-component-surface));
  border-color: var(--brand-primary, var(--color-primary-500));
  color: var(--brand-primary, var(--color-primary-600));
}

.donation-amount__custom {
  margin-top: var(--space-2);
}

.donation-target__modes {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
  margin-top: var(--space-1);
}

.donation-target__mode {
  flex: 1 1 180px;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-component-surface);
  cursor: pointer;
  transition: background var(--transition-fast), border-color var(--transition-fast);
}

.donation-target__mode:has(input:checked) {
  background: color-mix(in srgb, var(--brand-primary, var(--color-primary-500)) 12%, var(--color-component-surface));
  border-color: var(--brand-primary, var(--color-primary-500));
}

.donation-target__picker {
  padding: var(--space-3);
  border: 1px dashed var(--color-border);
  border-radius: var(--radius-md);
}

/* Sticky bottom CTA on public fundraiser show page */
.fundraiser-cta-bar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 30;
  padding: var(--space-3) var(--space-4) calc(var(--space-3) + env(safe-area-inset-bottom));
  background: color-mix(in srgb, var(--color-surface) 92%, transparent);
  backdrop-filter: saturate(140%) blur(12px);
  -webkit-backdrop-filter: saturate(140%) blur(12px);
  border-top: 1px solid var(--color-border);
  text-align: center;
}

.fundraiser-cta-bar__btn {
  min-width: 240px;
}

/* When the fixed CTA bar is present, reserve room at the bottom of the page
   so the brand footer can scroll into view above it. ~72px = btn--large + bar padding. */
body:has(.fundraiser-cta-bar) {
  padding-bottom: calc(5rem + env(safe-area-inset-bottom));
}

.countdown {
  margin: var(--space-3) auto var(--space-4);
  text-align: center;
}

.countdown__date {
  color: var(--color-ink-light);
  font-size: var(--text-sm);
  margin: 0 0 var(--space-3);
}

.countdown__cells {
  display: inline-flex;
  gap: var(--space-3);
  justify-content: center;
  flex-wrap: wrap;
}

.countdown__cell {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 4rem;
  padding: var(--space-2) var(--space-3);
  background: var(--color-component-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
}

.countdown__value {
  font-size: 1.75rem;
  font-weight: var(--font-bold);
  font-variant-numeric: tabular-nums;
  color: var(--brand-primary, var(--color-primary-600));
  line-height: 1;
}

.countdown__unit {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-ink-light);
  margin-top: var(--space-1);
}

.countdown--ended .countdown__cells {
  display: none;
}

.countdown__ended-message {
  margin: var(--space-3) 0 0;
  color: var(--color-ink-light);
  font-size: var(--text-sm);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-color-scheme="light"]) .countdown__value,
  :root:not([data-color-scheme="light"]) .fundraiser-progress__raised {
    color: color-mix(in srgb, var(--brand-primary, var(--color-primary-500)) 45%, white);
  }
}

:root[data-color-scheme="dark"] .countdown__value,
:root[data-color-scheme="dark"] .fundraiser-progress__raised {
  color: color-mix(in srgb, var(--brand-primary, var(--color-primary-500)) 45%, white);
}

/* Billing */
.billing-tabs {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
  border-bottom: 1px solid var(--color-border);
  padding-bottom: var(--space-2);
}

.billing-tab {
  display: inline-flex;
  align-items: center;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
  color: var(--color-ink-light);
  text-decoration: none;
  border: 1px solid transparent;
}

.billing-tab:hover {
  background: color-mix(in srgb, var(--theme-primary) 6%, transparent);
  color: var(--color-ink);
}

.billing-tab--active {
  background: color-mix(in srgb, var(--theme-primary) 10%, transparent);
  color: var(--color-ink);
  border-color: color-mix(in srgb, var(--theme-primary) 25%, transparent);
}

.billing-table tbody tr:hover {
  background: color-mix(in srgb, var(--theme-primary) 4%, transparent);
}

/* Personalized lunch calendar (per-student colored chips) */
.lunch-personal-calendar {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 1px;
  background: var(--color-border);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  overflow: hidden;
  max-width: 720px;
  margin: 0 auto;
}

.lunch-personal-calendar__cell {
  background: var(--color-canvas);
  padding: var(--space-2);
  min-height: 110px;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.lunch-personal-calendar__cell--empty {
  background: var(--color-surface-subtle);
}

.lunch-personal-calendar__cell--off {
  background: color-mix(in srgb, var(--color-warning-500) 8%, var(--color-canvas));
}

.lunch-personal-calendar__date {
  font-weight: var(--font-semibold);
  font-size: var(--text-sm);
}

.lunch-personal-calendar__off-label {
  font-size: var(--text-xs);
  color: var(--color-warning-700, #a16207);
  font-style: italic;
}

.lunch-personal-calendar__chip {
  display: flex;
  flex-direction: column;
  padding: 2px 6px;
  border-radius: var(--radius-sm);
  border-left: 3px solid var(--student-color, var(--color-primary-500));
  background: color-mix(in srgb, var(--student-color, var(--color-primary-500)) 12%, var(--color-canvas));
  font-size: var(--text-xs);
  line-height: 1.3;
  min-width: 0;
}

.lunch-personal-calendar__chip-name {
  font-weight: var(--font-semibold);
  color: var(--student-color, var(--color-primary-600));
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.lunch-personal-calendar__chip-meal {
  color: var(--color-ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.lunch-personal-calendar__legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
  font-size: var(--text-sm);
}

.lunch-personal-calendar__legend-item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--color-ink);
}

.lunch-personal-calendar__swatch {
  display: inline-block;
  width: 12px;
  height: 12px;
  border-radius: var(--radius-sm);
  background: var(--student-color, var(--color-primary-500));
}

.lunch-selection-calendar {
  max-width: 720px;
  margin: 0 auto;
}

.lunch-selection-calendar .lunch-calendar__header {
  max-width: 720px;
  margin: 0 auto;
}

.lunch-menu-calendar__cell {
  background: var(--color-canvas);
  padding: var(--space-3);
  aspect-ratio: 1 / 1;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.lunch-menu-calendar__cell--off {
  background: color-mix(in srgb, var(--color-warning-500) 8%, var(--color-canvas));
}

.lunch-menu-calendar__date {
  font-weight: var(--font-semibold);
  font-size: var(--text-sm);
  margin-bottom: var(--space-1);
}

.lunch-menu-calendar__meal {
  font-size: var(--text-xs);
  color: var(--color-ink);
  display: flex;
  justify-content: space-between;
}

.lunch-menu-calendar__label {
  font-size: var(--text-xs);
  color: var(--color-warning-700, #a16207);
  font-style: italic;
}

/* Admin calendar cells */

.lunch-admin-cell__meals {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 1;
  min-height: 0;
  overflow: hidden;
  margin-bottom: var(--space-1);
}

.lunch-admin-cell__actions {
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
  margin-top: auto;
}

.lunch-admin-cell__actions .btn,
.lunch-admin-cell__actions button,
.lunch-admin-cell__actions a.btn,
.lunch-admin-cell__actions form button,
.lunch-admin-cell__actions form .btn {
  font-size: 0.65rem !important;
  padding: 2px 6px !important;
  line-height: 1.2 !important;
  min-height: 0 !important;
  height: auto !important;
}

.lunch-admin-cell__actions form {
  display: inline;
  margin: 0;
}

.lunch-admin-cell__actions--empty {
  justify-content: center;
  align-items: center;
  flex: 1;
}

/* Row action dropdown (gear menu) */
.row-actions {
  position: relative;
  display: inline-block;
}

.row-actions__trigger {
  padding: var(--space-1) var(--space-2);
  min-width: 0;
}

.row-actions__menu.popover {
  width: min(13rem, calc(100vw - 2rem));
}

.row-actions__menu .popover__body {
  padding: var(--space-1);
}

.row-actions__menu .row-actions-menu__item {
  display: block;
  width: 100%;
  text-align: left;
  padding: var(--space-2) var(--space-3);
  background: transparent;
  border: 0;
  border-radius: var(--radius-sm);
  color: var(--color-ink);
  font-size: var(--text-sm);
  font-weight: var(--font-normal);
  line-height: 1.4;
  cursor: pointer;
  text-decoration: none;
  box-shadow: none;
  font-family: inherit;
}

.row-actions__menu .row-actions-menu__item:hover {
  background: color-mix(in srgb, var(--color-ink) 8%, transparent);
  color: var(--color-ink);
  text-decoration: none;
}

.row-actions__menu .row-actions-menu__item--danger {
  color: var(--color-danger-600, #dc2626);
}

.row-actions__menu .row-actions-menu__item--danger:hover {
  background: color-mix(in srgb, var(--color-danger-500, #dc2626) 12%, transparent);
  color: var(--color-danger-700, #b91c1c);
}

/* Collapsible action menu (used for responsive button rows) */
.action-menu {
  display: none;
  position: relative;
}

.action-menu__summary {
  list-style: none;
  cursor: pointer;
  user-select: none;
}

.action-menu__summary::-webkit-details-marker { display: none; }
.action-menu__summary::marker { content: ""; }

.action-menu__list {
  position: absolute;
  right: 0;
  top: calc(100% + 4px);
  z-index: 30;
  min-width: 220px;
  background: var(--color-component-surface);
  border: 1px solid var(--color-border);
  border-radius: 8px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25);
  padding: 4px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.action-menu__item {
  display: block;
  padding: 8px 12px;
  border-radius: 6px;
  text-decoration: none;
  color: var(--color-ink);
  font-size: 0.875rem;
}

.action-menu__item:hover {
  background: color-mix(in srgb, var(--color-ink) 8%, transparent);
  color: var(--color-ink);
  text-decoration: none;
}

@media (max-width: 1199px) {
  .fundraiser-actions-row { display: none !important; }
  .action-menu { display: inline-block; }
}

/* ==========================================================================
   Marketing / Hype page (/about)
   ========================================================================== */

.marketing {
  --hype-yellow: #ffd84d;
  --hype-pink: #ff6b9d;
  --hype-mint: #4ade80;
  --hype-sky: #60a5fa;
  --hype-peach: #fb923c;
  --hype-violet: #a78bfa;
  --hype-ink: #0f172a;
  --hype-paper: #fffaf0;

  background: var(--hype-paper);
  color: var(--hype-ink);
  font-family: "Inter", system-ui, -apple-system, sans-serif;
  width: 100%;
  margin: 0 auto;
  overflow-x: hidden;
}

/* Hero */
.marketing__hero {
  position: relative;
  padding: 5rem 1.5rem 4rem;
  text-align: center;
  background:
    radial-gradient(circle at 15% 20%, color-mix(in srgb, var(--hype-yellow) 60%, transparent) 0, transparent 35%),
    radial-gradient(circle at 85% 15%, color-mix(in srgb, var(--hype-pink) 50%, transparent) 0, transparent 35%),
    radial-gradient(circle at 75% 85%, color-mix(in srgb, var(--hype-mint) 50%, transparent) 0, transparent 40%),
    radial-gradient(circle at 10% 90%, color-mix(in srgb, var(--hype-sky) 50%, transparent) 0, transparent 35%),
    var(--hype-paper);
  overflow: hidden;
}

.marketing__hero::before,
.marketing__hero::after {
  content: "";
  position: absolute;
  border-radius: 999px;
  filter: blur(2px);
  opacity: 0.45;
  pointer-events: none;
}

.marketing__hero::before {
  top: 12%;
  left: 8%;
  width: 14rem;
  height: 14rem;
  background: var(--hype-yellow);
}

.marketing__hero::after {
  bottom: -4rem;
  right: -3rem;
  width: 18rem;
  height: 18rem;
  background: var(--hype-pink);
}

.marketing__hero-inner {
  position: relative;
  z-index: 1;
  max-width: 56rem;
  margin: 0 auto;
}

.marketing__hero-logo {
  width: 88px;
  height: 88px;
  margin: 0 auto 2rem;
  display: block;
  border-radius: 24px;
  box-shadow: 0 18px 50px -12px color-mix(in srgb, var(--hype-ink) 35%, transparent);
  transform: rotate(-4deg);
}

.marketing__hero-title {
  font-size: clamp(2.5rem, 6vw, 5rem);
  font-weight: 800;
  line-height: 1.02;
  letter-spacing: -0.03em;
  margin: 0 0 1.5rem;
}

.marketing__hero-title-accent {
  display: inline-block;
  background: var(--hype-yellow);
  padding: 0 0.4em;
  border-radius: 12px;
  transform: rotate(-1deg);
  box-shadow: 6px 6px 0 var(--hype-ink);
}

.marketing__hero-subtitle {
  font-size: clamp(1.1rem, 2vw, 1.4rem);
  line-height: 1.5;
  max-width: 38rem;
  margin: 0 auto 2.5rem;
  color: color-mix(in srgb, var(--hype-ink) 80%, transparent);
}

.marketing__hero-cta {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  justify-content: center;
  margin-bottom: 2rem;
}

.marketing__cta-primary {
  background: var(--hype-ink) !important;
  color: var(--hype-paper) !important;
  border: 3px solid var(--hype-ink) !important;
  border-radius: 999px !important;
  font-weight: 700 !important;
  padding: 0.9rem 1.75rem !important;
  font-size: 1.05rem !important;
  box-shadow: 6px 6px 0 var(--hype-yellow);
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.marketing__cta-primary:hover {
  transform: translate(-2px, -2px);
  box-shadow: 8px 8px 0 var(--hype-yellow);
  background: var(--hype-ink) !important;
}

.marketing__cta-secondary {
  background: var(--hype-paper) !important;
  color: var(--hype-ink) !important;
  border: 3px solid var(--hype-ink) !important;
  border-radius: 999px !important;
  font-weight: 700 !important;
  padding: 0.9rem 1.75rem !important;
  font-size: 1.05rem !important;
  box-shadow: 6px 6px 0 var(--hype-pink);
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.marketing__cta-secondary:hover {
  transform: translate(-2px, -2px);
  box-shadow: 8px 8px 0 var(--hype-pink);
  background: var(--hype-paper) !important;
}

.marketing__hero-meta {
  font-size: 0.9rem;
  color: color-mix(in srgb, var(--hype-ink) 60%, transparent);
  margin: 0;
  font-weight: 500;
}

/* Features */
.marketing__features {
  max-width: 76rem;
  margin: 0 auto;
  padding: 5rem 1.5rem;
}

.marketing__eyebrow {
  display: inline-block;
  background: var(--hype-violet);
  color: var(--hype-ink);
  font-weight: 700;
  font-size: 0.85rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 0.4rem 1rem;
  border-radius: 999px;
  border: 2px solid var(--hype-ink);
  margin-bottom: 1rem;
  transform: rotate(-1deg);
}

.marketing__section-title {
  font-size: clamp(2rem, 4vw, 3.25rem);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.05;
  margin: 0 0 3rem;
  max-width: 36rem;
}

.marketing__feature-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.75rem;
}

.marketing__feature {
  position: relative;
  background: white;
  border: 3px solid var(--hype-ink);
  border-radius: 24px;
  padding: 2rem 1.75rem;
  box-shadow: 8px 8px 0 var(--hype-ink);
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.marketing__feature:hover {
  transform: translate(-3px, -3px);
  box-shadow: 11px 11px 0 var(--hype-ink);
}

.marketing__feature--1 { background: color-mix(in srgb, var(--hype-yellow) 35%, white); }
.marketing__feature--2 { background: color-mix(in srgb, var(--hype-pink) 25%, white); }
.marketing__feature--3 { background: color-mix(in srgb, var(--hype-mint) 30%, white); }
.marketing__feature--4 {
  background: color-mix(in srgb, var(--hype-sky) 22%, white);
  grid-column: 1 / -1;
}
.marketing__feature--5 { background: color-mix(in srgb, var(--hype-peach) 30%, white); grid-column: 1 / -1; }

.marketing__feature-number {
  font-family: "Scorekard", "Inter", sans-serif;
  font-size: 0.85rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: var(--hype-ink);
  background: var(--hype-paper);
  border: 2px solid var(--hype-ink);
  border-radius: 999px;
  padding: 0.25rem 0.75rem;
  display: inline-block;
  margin-bottom: 1rem;
}

.marketing__feature-emoji {
  font-size: 3rem;
  line-height: 1;
  margin-bottom: 0.75rem;
}

.marketing__feature-title {
  font-size: 1.6rem;
  font-weight: 800;
  letter-spacing: -0.02em;
  margin: 0 0 0.75rem;
  line-height: 1.1;
}

.marketing__feature-body {
  font-size: 1.05rem;
  line-height: 1.55;
  color: color-mix(in srgb, var(--hype-ink) 85%, transparent);
  margin: 0 0 1.25rem;
}

.marketing__feature-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.marketing__feature-list li {
  position: relative;
  padding-left: 1.75rem;
  font-size: 0.95rem;
  line-height: 1.4;
  font-weight: 500;
}

.marketing__feature-list li::before {
  content: "✓";
  position: absolute;
  left: 0;
  top: 0;
  width: 1.25rem;
  height: 1.25rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--hype-ink);
  color: var(--hype-paper);
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 900;
}

.marketing__feature-pillars {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1rem;
}

.marketing__feature-pillars li {
  background: white;
  border: 2px solid var(--hype-ink);
  border-radius: 16px;
  padding: 1rem 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  box-shadow: 4px 4px 0 var(--hype-ink);
}

.marketing__feature-pillars strong {
  font-size: 1rem;
  font-weight: 800;
  letter-spacing: -0.01em;
}

.marketing__feature-pillars span {
  font-size: 0.85rem;
  color: color-mix(in srgb, var(--hype-ink) 70%, transparent);
  line-height: 1.35;
}

/* CTA banner */
.marketing__cta-banner {
  padding: 5rem 1.5rem;
  background: var(--hype-ink);
  color: var(--hype-paper);
  position: relative;
  overflow: hidden;
}

.marketing__cta-banner::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(circle at 20% 30%, color-mix(in srgb, var(--hype-yellow) 25%, transparent) 0, transparent 30%),
    radial-gradient(circle at 80% 70%, color-mix(in srgb, var(--hype-pink) 25%, transparent) 0, transparent 30%);
  pointer-events: none;
}

.marketing__cta-banner-inner {
  position: relative;
  max-width: 48rem;
  margin: 0 auto;
  text-align: center;
}

.marketing__cta-banner-title {
  font-size: clamp(1.75rem, 4vw, 2.75rem);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.1;
  margin: 0 0 1rem;
}

.marketing__cta-banner-subtitle {
  font-size: 1.1rem;
  line-height: 1.5;
  margin: 0 0 2rem;
  color: color-mix(in srgb, var(--hype-paper) 85%, transparent);
}

.marketing__cta-banner-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  justify-content: center;
}

.marketing__cta-banner .marketing__cta-primary {
  background: var(--hype-yellow) !important;
  color: var(--hype-ink) !important;
  border-color: var(--hype-yellow) !important;
  box-shadow: 6px 6px 0 var(--hype-paper);
}

.marketing__cta-banner .marketing__cta-primary:hover {
  background: var(--hype-yellow) !important;
  box-shadow: 8px 8px 0 var(--hype-paper);
}

.marketing__cta-banner .marketing__cta-secondary {
  background: transparent !important;
  color: var(--hype-paper) !important;
  border-color: var(--hype-paper) !important;
  box-shadow: 6px 6px 0 var(--hype-pink);
}

.marketing__cta-banner .marketing__cta-secondary:hover {
  background: transparent !important;
  box-shadow: 8px 8px 0 var(--hype-pink);
}

/* Footer */
.marketing__footer {
  padding: 2.5rem 1.5rem 3rem;
  text-align: center;
  background: var(--hype-paper);
}

.marketing__footer-logo {
  width: 40px;
  height: 40px;
  margin: 0 auto 0.75rem;
  display: block;
  border-radius: 10px;
  opacity: 0.85;
}

.marketing__footer-text {
  font-size: 0.9rem;
  color: color-mix(in srgb, var(--hype-ink) 55%, transparent);
  margin: 0;
  font-weight: 500;
}

/* ==========================================================================
   Brand footer — logo + brand name + tagline on one line (with optional link)
   ========================================================================== */

.brand-footer {
  padding: var(--space-6) var(--space-4);
  text-align: center;
}

.brand-footer__line {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--color-ink-light);
  line-height: 1.6;
}

.brand-footer__logo {
  height: 1.4em;
  width: auto;
  vertical-align: -0.3em;
}

.brand-footer__name {
  font-size: 1.25em;
  color: var(--color-ink);
}

.fish-brand {
  font-family: "Turbeau", var(--font-sans);
  font-weight: 400;
}

.fish-brand__tm {
  font-family: var(--font-sans);
  font-size: 0.5em;
  font-weight: 500;
  vertical-align: 0.7em;
  margin-left: 0.05em;
}

.brand-footer__text {
  /* inherits from .brand-footer__line */
}

.brand-footer__link {
  margin-left: 0.4em;
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.brand-footer__link:hover {
  color: var(--color-ink);
}

/* Responsive */
@media (max-width: 760px) {
  .marketing__hero { padding: 3.5rem 1.25rem 3rem; }
  .marketing__features { padding: 3.5rem 1.25rem; }
  .marketing__feature-grid { grid-template-columns: 1fr; gap: 1.25rem; }
  .marketing__feature { padding: 1.75rem 1.5rem; box-shadow: 6px 6px 0 var(--hype-ink); }
  .marketing__feature--4,
  .marketing__feature--5 { grid-column: auto; }
  .marketing__feature-pillars { grid-template-columns: 1fr; }
  .marketing__hero-cta,
  .marketing__cta-banner-actions { flex-direction: column; align-items: stretch; }
  .marketing__cta-banner { padding: 3.5rem 1.25rem; }
}

/* ==========================================================================
   Upload progress modal (manage fundraiser form)
   ========================================================================== */

.upload-progress {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.65);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
  padding: var(--space-4);
}

.upload-progress--open {
  opacity: 1;
  pointer-events: auto;
}

.upload-progress__inner {
  background: var(--color-component-surface);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg);
  padding: var(--space-6) var(--space-6) var(--space-5);
  width: 100%;
  max-width: 28rem;
  text-align: center;
}

.upload-progress__title {
  font-size: var(--text-lg);
  font-weight: var(--font-bold);
  margin: 0 0 var(--space-4);
  color: var(--color-ink);
}

.upload-progress__bar {
  background: var(--color-surface-subtle);
  height: 10px;
  border-radius: 999px;
  overflow: hidden;
  margin-bottom: var(--space-3);
}

.upload-progress__bar-fill {
  background: var(--color-primary-600);
  height: 100%;
  width: 0%;
  transition: width 0.15s linear;
  border-radius: 999px;
}

.upload-progress__count {
  font-size: var(--text-base);
  margin: 0 0 var(--space-3);
  color: var(--color-ink);
}

.upload-progress__count strong {
  font-weight: var(--font-bold);
  font-variant-numeric: tabular-nums;
}

.upload-progress__note {
  font-size: var(--text-sm);
  color: var(--color-ink-light);
  margin: 0;
  line-height: 1.45;
}

/* ==========================================================================
   Gallery tile processing status badge
   ========================================================================== */

.gallery-tile--processing .gallery-tile__img--placeholder {
  background:
    repeating-linear-gradient(
      45deg,
      color-mix(in srgb, var(--color-ink) 5%, transparent),
      color-mix(in srgb, var(--color-ink) 5%, transparent) 12px,
      color-mix(in srgb, var(--color-ink) 9%, transparent) 12px,
      color-mix(in srgb, var(--color-ink) 9%, transparent) 24px
    );
}

.gallery-tile__status {
  position: absolute;
  bottom: var(--space-1);
  left: var(--space-1);
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 7px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: var(--font-semibold);
  line-height: 1;
  z-index: 2;
}

.gallery-tile__status--ready {
  background: var(--color-success-600);
  color: white;
  padding: 4px;
}

.gallery-tile__status--ready svg {
  display: block;
}

.gallery-tile__status--processing {
  background: rgba(0, 0, 0, 0.75);
  color: white;
}

.gallery-tile__status-label {
  letter-spacing: 0.02em;
}

.gallery-tile__spinner {
  animation: gallery-tile-spin 0.9s linear infinite;
}

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

/* Group/chat member picker: chosen people on top, search results below. Rows
   and options are flex, so [hidden] alone can't hide them — force it. */
.member-picker__row[hidden],
.member-picker__option[hidden],
.member-picker__selected[hidden],
.member-picker__results[hidden] {
  display: none !important;
}

.member-picker__selected {
  display: grid;
  /* minmax(0, …) rather than a bare 1fr: grid items default to min-width:auto,
     which lets a row with a long name + "via …" tag push the remove button out
     past the card edge instead of truncating. */
  grid-template-columns: minmax(0, 1fr);
  gap: 0.25rem;
  padding: 0.25rem;
  container-type: inline-size;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
}

.member-picker__row {
  display: flex;
  align-items: center;
  min-width: 0;
  gap: 0.75rem;
  padding: 0.35rem 0.5rem;
  border-radius: var(--radius-sm, 0.25rem);
}

.member-picker__row:hover {
  background: color-mix(in srgb, currentColor 12%, transparent);
}

/* One line per person, always: emails are single unbreakable tokens, so left to
   wrap they'd give every row a different height and shove the role toggles off
   the edge in the narrow side-by-side columns. Truncate instead — the full
   address is on the row's title. */
.member-picker__identity {
  display: inline-flex;
  align-items: baseline;
  flex-wrap: nowrap;
  gap: 0.5rem;
  flex: 1 1 auto;
  min-width: 0;
}

.member-picker__name,
.member-picker__email {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* When space is tight the email gives way first — the name is what identifies
   the person, and the full address is on the row's title. */
.member-picker__name {
  flex: 0 1 auto;
}

.member-picker__email {
  flex: 0 6 auto;
  font-size: 0.75rem;
  color: var(--color-text-muted, #6b7280);
}

.member-picker__tag {
  flex: 0 0 auto;
  font-size: 0.7rem;
  padding: 0.05rem 0.4rem;
  border-radius: 999px;
  border: 1px solid var(--color-border);
  color: var(--color-text-muted, #6b7280);
  white-space: nowrap;
}

.member-picker__role {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  flex: 0 0 auto;
  font-size: 0.85rem;
  color: var(--color-text-muted, #6b7280);
  white-space: nowrap;
}

.member-picker__remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--color-text-muted, #6b7280);
  cursor: pointer;
  transition: color var(--transition-fast), background var(--transition-fast);
}

.member-picker__remove:hover {
  background: color-mix(in srgb, var(--color-danger-500) 16%, transparent);
  color: var(--color-danger-600);
}

/* One-line summary of the people an included class/group contributes. They're
   kept out of the list itself — a class can contribute dozens and would bury
   the direct members this form actually edits. */
.member-picker__note {
  margin: 0.5rem 0 0;
  font-size: 0.8rem;
  color: var(--color-text-muted, #6b7280);
}

/* Once someone is chosen the name identifies them well enough; in the narrow
   side-by-side column there isn't room for name + email + two role toggles, so
   the email drops out (it stays on the row's title). Search results always keep
   theirs — that's where you need it to tell two same-named people apart. */
@container (max-width: 26rem) {
  .member-picker__row .member-picker__email {
    display: none;
  }
}

.member-picker__results {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0.15rem;
  margin-top: 0.5rem;
  max-height: 18rem;
  overflow-y: auto;
}

.member-picker__option {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.35rem 0.5rem;
  border: 0;
  border-radius: var(--radius-sm, 0.25rem);
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.member-picker__option:hover,
.member-picker__option:focus-visible {
  background: color-mix(in srgb, currentColor 12%, transparent);
}

.member-picker__option-plus {
  flex: 0 0 auto;
  width: 1.25rem;
  text-align: center;
  color: var(--color-text-muted, #6b7280);
}

.member-picker__header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.25rem;
}

.member-picker__roster-link {
  flex: 0 0 auto;
  padding: 0;
  border: 0;
  background: transparent;
  font-size: 0.8rem;
  color: var(--color-primary-600, #2563eb);
  cursor: pointer;
  white-space: nowrap;
}

.member-picker__roster-link:hover,
.member-picker__roster-link:focus-visible {
  text-decoration: underline;
}

/* "View all members": the real membership, direct and inherited together. Its
   own dialog rather than an expanded list, because it can run to hundreds of
   people the picker itself never shows. */
.member-roster-dialog {
  width: min(34rem, calc(100vw - 2rem));
  max-width: none;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  background: var(--color-component-surface);
  color: var(--color-ink);
}

.member-roster-dialog::backdrop {
  background: rgba(0, 0, 0, 0.5);
}

.member-roster-dialog__list {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0.15rem;
  max-height: min(26rem, 60vh);
  overflow-y: auto;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 0.25rem;
}

.member-roster-dialog__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  min-width: 0;
  padding: 0.35rem 0.5rem;
  border-radius: var(--radius-sm, 0.25rem);
}

.member-roster-dialog__row:nth-child(odd) {
  background: color-mix(in srgb, currentColor 5%, transparent);
}

.member-roster-dialog__identity {
  display: flex;
  flex-direction: column;
  gap: 0.05rem;
  min-width: 0;
  overflow-wrap: anywhere;
}

.member-roster-dialog__sources {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 0.25rem;
  flex: 0 1 auto;
}

/* Include-classes / include-groups rows: the opt-in checkbox on the left, a
   link through to that source's own admin page on the right. */
.source-select-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  min-width: 0;
}

.source-select-row__main {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
}

.source-select-row__edit {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  flex: 0 0 auto;
  padding: 0.1rem 0.4rem;
  border-radius: var(--radius-sm, 0.25rem);
  font-size: 0.75rem;
  color: var(--color-text-muted, #6b7280);
  text-decoration: none;
  white-space: nowrap;
  opacity: 0;
  transition: opacity var(--transition-fast), color var(--transition-fast);
}

/* Revealed on hover/focus so a long list of classes stays quiet, but always
   visible to keyboard and touch users, who get no hover. */
.source-select-row:hover .source-select-row__edit,
.source-select-row__edit:focus-visible {
  opacity: 1;
}

.source-select-row__edit:hover,
.source-select-row__edit:focus-visible {
  color: var(--color-primary-600, #2563eb);
  background: color-mix(in srgb, currentColor 12%, transparent);
}

@media (hover: none) {
  .source-select-row__edit {
    opacity: 1;
  }
}

/* Filterable-list: force-hide non-matching items even when they use
   display:flex/inline-flex (the [hidden] attribute can't override those). */
.filterable-list-hidden {
  display: none !important;
}

/* Group/chat member + source picker cards: side-by-side on roomy viewports
   (e.g. laptop), stacking automatically on narrow screens. */
.feed-picker-grid {
  display: grid;
  gap: 1rem;
  align-items: start;
  margin-bottom: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
}

.feed-picker-grid > .card {
  margin-bottom: 0;
}

/* Pinned posts: push-pin badge, pin/unpin toggle, and a card accent. */
.classroom-post__controls {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.classroom-post__controls form.button_to {
  margin: 0;
}

.classroom-post__controls .classroom-post__actions {
  margin-left: 0;
}

/* Combined-feed avatar: source logo (group/school) with the author overlaid as
   a small circle at the bottom-right. */
.feed-avatar {
  position: relative;
  width: 2.5rem;
  height: 2.5rem;
  flex-shrink: 0;
}
.feed-avatar__source {
  width: 2.5rem;
  height: 2.5rem;
  border-radius: var(--radius-md, 8px);
  object-fit: cover;
  display: block;
}
.feed-avatar__author {
  position: absolute;
  right: -3px;
  bottom: -3px;
  width: 1.25rem;
  height: 1.25rem;
  border-radius: 50%;
  overflow: hidden;
  border: 2px solid var(--color-surface, #fff);
  background: var(--color-surface, #fff);
}
.feed-avatar__author .chat-message__avatar {
  width: 100%;
  height: 100%;
  margin: 0;
  font-size: 0.5rem;
  border-radius: 50%;
}
.feed-avatar__author .chat-message__avatar--img {
  object-fit: cover;
}

/* Combined-feed source label ("in <Class/Group/School>"). */
.classroom-post__context {
  font-weight: 600;
  color: var(--color-primary-600, #2563eb);
  text-decoration: none;
}
.classroom-post__context:hover {
  text-decoration: underline;
}

/* Viewer-facing pinned indicator: a small pin glyph, no text label. */
.classroom-post__pin-badge {
  display: inline-flex;
  align-items: center;
  color: var(--color-primary-600, #2563eb);
  opacity: 0.85;
}

.classroom-post__pin-btn.is-pinned {
  color: var(--color-primary-600, #2563eb);
  border-color: var(--color-primary-600, #2563eb);
}

/* Pinned posts: a soft glowing brand-colored frame (blue -> violet ring +
   halo), no left accent bar. Ring is drawn with a masked gradient pseudo-
   element so it respects each school's --theme-primary. */
.classroom-post--pinned {
  position: relative;
  z-index: 0;
  border-color: transparent;
  box-shadow:
    0 0 14px 1px color-mix(in srgb, var(--color-primary-600, #2563eb) 28%, transparent),
    0 0 32px 6px color-mix(in srgb, var(--color-primary-600, #2563eb) 14%, transparent);
}

.classroom-post--pinned::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1.5px; /* ring thickness */
  background: linear-gradient(135deg,
    color-mix(in srgb, var(--color-primary-600, #2563eb) 55%, #38bdf8),
    color-mix(in srgb, var(--color-primary-600, #2563eb) 60%, #a855f7));
  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  pointer-events: none;
}

/* ── Collapsible pinned section ──────────────────────────────
   Shown when a feed has 2+ pinned posts, so a wall of pins can be folded
   away without losing them. The panel animates via grid-template-rows
   (0fr → 1fr), which needs no measured heights. */
.pinned-section {
  margin-bottom: var(--space-4);
}

.pinned-section__toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  width: 100%;
  padding: var(--space-2) var(--space-3);
  margin-bottom: var(--space-3);
  font: inherit;
  color: var(--color-ink);
  cursor: pointer;
  border: 1px solid color-mix(in srgb, var(--color-primary-600, #2563eb) 24%, transparent);
  border-radius: var(--radius-full);
  background:
    linear-gradient(135deg,
      color-mix(in srgb, var(--color-primary-600, #2563eb) 12%, transparent),
      color-mix(in srgb, #a855f7 8%, transparent));
  transition: border-color 0.2s ease, background 0.2s ease, box-shadow 0.2s ease;
}

.pinned-section__toggle:hover {
  border-color: color-mix(in srgb, var(--color-primary-600, #2563eb) 45%, transparent);
  box-shadow: 0 0 12px 0 color-mix(in srgb, var(--color-primary-600, #2563eb) 18%, transparent);
}

.pinned-section__toggle:focus-visible {
  outline: 2px solid var(--color-primary-600, #2563eb);
  outline-offset: 2px;
}

.pinned-section__lead {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
}

/* Gradient chip echoing the ring on a pinned post. */
.pinned-section__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: var(--radius-full);
  color: #fff;
  background: linear-gradient(135deg,
    color-mix(in srgb, var(--color-primary-600, #2563eb) 55%, #38bdf8),
    color-mix(in srgb, var(--color-primary-600, #2563eb) 60%, #a855f7));
}

.pinned-section__label {
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
  letter-spacing: 0.02em;
}

.pinned-section__count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.25rem;
  height: 1.25rem;
  padding: 0 var(--space-1);
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  font-variant-numeric: tabular-nums;
  color: var(--color-primary-700, #1d4ed8);
  background: color-mix(in srgb, var(--color-primary-600, #2563eb) 18%, transparent);
  border-radius: var(--radius-full);
}

.pinned-section__chevron {
  display: inline-flex;
  color: var(--color-ink-light);
  transition: transform 0.32s cubic-bezier(0.4, 0, 0.2, 1), color 0.2s ease;
}

.pinned-section__toggle:hover .pinned-section__chevron {
  color: var(--color-primary-600, #2563eb);
}

.pinned-section.is-collapsed .pinned-section__chevron {
  transform: rotate(-90deg);
}

.pinned-section__panel {
  display: grid;
  grid-template-rows: 1fr;
  min-height: 0;
}

.pinned-section.is-animated .pinned-section__panel {
  transition: grid-template-rows 0.32s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.24s ease;
}

.pinned-section.is-collapsed .pinned-section__panel {
  grid-template-rows: 0fr;
  opacity: 0;
}

.pinned-section__posts {
  min-height: 0;
  overflow: hidden;
}

/* Once fully open, stop clipping so the pinned glow isn't cut off. */
.pinned-section.is-open .pinned-section__posts {
  overflow: visible;
}

@media (prefers-reduced-motion: reduce) {
  .pinned-section.is-animated .pinned-section__panel,
  .pinned-section__chevron,
  .pinned-section__toggle {
    transition: none;
  }
}

/* The tinted pill reads too dark on a dark canvas — lighten the numerals. */
:root[data-color-scheme="dark"] .pinned-section__count {
  color: var(--color-primary-300, #93c5fd);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-color-scheme="light"]) .pinned-section__count {
    color: var(--color-primary-300, #93c5fd);
  }
}

/* ---- Feature Settings ---------------------------------------------------- */
/* Centered, reasonable-width list of feature cards. */
.feature-settings {
  max-width: 40rem;
  margin: 0 auto;
}

.feature-row {
  position: relative; /* anchors the disable-confirmation popover */
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
}

.feature-row__name {
  font-weight: var(--font-semibold);
}

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

.feature-row__status--off {
  color: var(--color-danger-600);
}

/* iOS-style pill toggle, colored to the school theme when on. */
.feature-toggle {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  width: 46px;
  height: 26px;
  padding: 3px;
  border: 0;
  border-radius: 999px;
  cursor: pointer;
  background: var(--color-border);
  transition: background-color var(--transition-fast, 0.15s);
}

.feature-toggle--on {
  background: var(--color-primary-600);
  justify-content: flex-end;
}

.feature-toggle--off {
  justify-content: flex-start;
}

.feature-toggle__knob {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgb(0 0 0 / 0.3);
}

/* button_to wrapper for the enable toggle — no default form/button chrome. */
.feature-toggle-form {
  margin: 0;
  display: inline-flex;
}

/* ---- A person's name as a menu (shared/_user_menu) ----------------------- */
.user-menu {
  position: relative;
  display: inline-flex;
}

/* forms.css paints every bare <button> as a filled primary button, hover
   included, so the trigger has to opt out of both states or the author's name
   turns into a blue pill. Inherit type so it reads as the name it replaced. */
.user-menu__trigger,
.user-menu__trigger:hover,
.user-menu__trigger:focus-visible {
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  line-height: inherit;
  text-align: left;
  cursor: pointer;
}

.user-menu__trigger:hover,
.user-menu__trigger:focus-visible {
  text-decoration: underline;
  text-underline-offset: 2px;
}

.user-menu__popover {
  min-width: 15rem;
  max-width: min(20rem, calc(100vw - 2rem));
}

/* Same opt-out for the action button, which should fill the popover row. */
.user-menu__action,
.user-menu__action:hover,
.user-menu__action:focus-visible {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: var(--space-2) var(--space-3);
  border: 0;
  border-radius: var(--radius-md);
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.user-menu__action:hover,
.user-menu__action:focus-visible {
  background: color-mix(in srgb, currentColor 12%, transparent);
}

/* button_to wraps its button in a form; keep that from breaking the row. */
.user-menu__popover form {
  margin: 0;
  display: block;
}

/* ---- Post "seen by" read activity (reuses .chat-receipts popover) -------- */
.classroom-post__seen {
  margin-top: var(--space-3);
  border-top: 1px solid var(--color-border);
  padding-top: var(--space-2);
}

/* The post card clips (overflow: hidden) and later cards paint on top, so let
   the card overflow and raise its stacking while the receipts popover is open. */
.classroom-post:has(.chat-receipts[open]) {
  overflow: visible;
  position: relative;
  z-index: 5;
}

/* ---- Chat read-receipt "seen by" popover -------------------------------- */
.chat-receipts {
  position: relative;
  display: inline-block;
}

.chat-receipts__summary {
  cursor: pointer;
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
}

.chat-receipts__summary::-webkit-details-marker { display: none; }

.chat-receipts__info { opacity: 0.65; flex-shrink: 0; }
.chat-receipts__summary:hover .chat-receipts__info,
.chat-receipts[open] .chat-receipts__info { opacity: 1; }

.chat-receipts__popover {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 1400;
  min-width: 14rem;
  /* Wide enough for a long display name beside a timestamp, but never past the
     right edge of the screen. The popover is absolutely positioned from its
     anchor, which sits ~3rem in on a phone, so the viewport cap has to leave
     room for that offset as well as a margin. */
  max-width: min(26rem, calc(100vw - 5rem));
  max-height: 16rem;
  overflow-x: hidden;
  overflow-y: auto;
  background: var(--color-component-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: var(--space-2) var(--space-3);
}

/* Right-align the popover under a right-aligned ("mine") message. */
.chat-message--mine .chat-receipts__popover {
  left: auto;
  right: 0;
}

.chat-receipts__title {
  font-weight: var(--font-semibold);
  color: var(--color-text-muted);
  margin-bottom: var(--space-1);
}

.chat-receipts__list { list-style: none; margin: 0; padding: 0; }

.chat-receipts__item {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  padding: 0.15rem 0;
}

/* The timestamp is the point of the popover, so it never gives way: the name
   truncates instead. Both were nowrap with no room to shrink, which pushed the
   time out past the edge and clipped it. */
.chat-receipts__name {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
  flex: 0 1 auto;
}

.chat-receipts__time {
  white-space: nowrap;
  flex: 0 0 auto;
}

/* ---- Sidebar notifications bell popover ---------------------------------- */
.sidebar-feed-row__bell-wrap {
  display: flex;
}

/* Collapsed rail: stack the bell below the Feed icon as a full, centered 2nd
   item (instead of squeezing it beside the Feed icon). */
.sidebar.is-collapsed .sidebar-feed-row {
  flex-direction: column;
  gap: var(--space-1);
}

.sidebar.is-collapsed .sidebar-feed-row__bell-wrap {
  width: 100%;
}

.sidebar.is-collapsed button.sidebar-feed-row__bell {
  width: 100%;
  justify-content: center;
}

/* Keep the bell quiet until hover/focus, matching the sidebar disclosure buttons. */
button.sidebar-feed-row__bell {
  background: transparent;
  border: 1px solid transparent;
  font: inherit;
  cursor: pointer;
  transition: background-color var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);
}

.notif-pop {
  position: fixed;
  z-index: 1600;
  max-height: min(28rem, 70vh);
  overflow-y: auto;
  background: var(--color-component-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg), 0 0 0 1px rgb(0 0 0 / 0.03);
  padding: var(--space-2);
}

.notif-pop__loading {
  padding: var(--space-4);
  text-align: center;
  color: var(--color-text-muted);
  font-size: var(--text-sm);
}

.notif-pop__header {
  padding: var(--space-2) var(--space-2) var(--space-1);
}

.notif-pop__heading {
  font-weight: var(--font-semibold);
  font-size: var(--text-sm);
}

.notif-pop__list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.notif-pop__item-form { margin: 0; }

.notif-pop__item {
  width: 100%;
  display: block;
  padding: var(--space-2);
  border: 0;
  border-radius: var(--radius-lg);
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: background-color var(--transition-fast);
}

/* Safari ignores display:flex on <button> and centers its content, so the flex
   row lives on an inner wrapper instead. */
.notif-pop__item-inner {
  display: flex;
  align-items: flex-start;
  justify-content: flex-start;
  gap: var(--space-3);
  text-align: left;
}

.notif-pop__item:hover,
.notif-pop__item:focus-visible {
  background: color-mix(in srgb, var(--theme-primary) 10%, transparent);
}

.notif-pop__item:hover .notif-pop__item-title {
  color: var(--theme-primary);
}

.notif-pop__item:active {
  background: color-mix(in srgb, var(--theme-primary) 16%, transparent);
}

.notif-pop__icon {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  background: var(--color-primary-bg);
  color: var(--color-primary-text);
}

.notif-pop__icon--urgent {
  background: var(--color-danger-bg);
  color: var(--color-danger-600);
}

.notif-pop__text {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.1rem;
}

.notif-pop__item-title {
  font-size: var(--text-sm);
  line-height: 1.3;
  transition: color var(--transition-fast);
}

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

.notif-pop__see-all {
  display: block;
  text-align: center;
  padding: var(--space-2);
  margin-top: var(--space-1);
  border-top: 1px solid var(--color-border);
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
  color: var(--color-primary-600);
}

/* Zero state */
.notif-pop__empty {
  text-align: center;
  padding: var(--space-5) var(--space-4) var(--space-3);
}

.notif-pop__empty-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 50%;
  margin-bottom: var(--space-3);
  background: var(--color-primary-bg);
  color: var(--color-primary-text);
}

.notif-pop__empty-title {
  font-weight: var(--font-semibold);
  margin: 0 0 0.15rem;
}

.notif-pop__empty-sub {
  font-size: var(--text-xs);
  color: var(--color-text-muted);
  margin: 0 0 var(--space-3);
}

.notif-pop__see-all--muted {
  border-top: 0;
  color: var(--color-text-muted);
}

/* ---------- Calendar legend / colour chips ---------- */

/* The legend on the combined calendar doubles as its filter: each entry is a
   checkbox that switches its calendar on or off. --cal-color is the calendar's
   own colour, validated against Palette server-side. */
.cal-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
}

.cal-legend form {
  display: contents;
}

.cal-legend__item {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.3rem 0.7rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  background: color-mix(in srgb, var(--cal-color) 12%, transparent);
  color: var(--color-ink);
  font-size: 0.8125rem;
  line-height: 1.2;
  cursor: pointer;
  margin-bottom: 0;
}

.cal-legend__item:hover {
  border-color: var(--cal-color);
}

/* Switched off: drained of colour, but still legible and still clickable. */
.cal-legend__item--off {
  background: transparent;
  color: var(--color-ink-lighter);
}

/* A native checkbox, tinted to the calendar. accent-color keeps the platform's
   own tick and focus ring, so it stays recognisable as a control and keyboard
   accessible for free. */
/* A switch built out of the checkbox itself — track from the input, knob from its
   ::after — so there's no extra markup and the native focus ring, keyboard
   handling and form value all still apply. */
.cal-legend__switch {
  appearance: none;
  -webkit-appearance: none;
  position: relative;
  width: 26px;
  height: 15px;
  margin: 0;
  flex-shrink: 0;
  border: 0;
  border-radius: var(--radius-full);
  background: color-mix(in srgb, var(--color-ink) 25%, transparent);
  cursor: pointer;
  transition: background var(--transition-fast);
}

.cal-legend__switch::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 11px;
  height: 11px;
  border-radius: var(--radius-full);
  background: #fff;
  box-shadow: 0 1px 2px rgb(0 0 0 / 0.3);
  transition: transform var(--transition-fast);
}

.cal-legend__switch:checked {
  background: var(--cal-color);
}

.cal-legend__switch:checked::after {
  transform: translateX(11px);
}

.cal-legend__switch:focus-visible {
  outline: 2px solid var(--cal-color);
  outline-offset: 2px;
}

/* Spells the state out, so it doesn't rest on reading the knob's position. */
.cal-legend__state {
  font-size: 0.625rem;
  font-weight: var(--font-semibold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-ink-lighter);
}

@media (prefers-reduced-motion: reduce) {
  .cal-legend__switch,
  .cal-legend__switch::after {
    transition: none;
  }
}

/* Sits opposite the page title, so the toolbar below is only ever months and
   calendar pills. margin-left on the group rather than the link: there can be
   two of them (this calendar's settings, and the school-wide list), and `auto`
   on each would push them apart instead of keeping them together. */
.cal-header__actions {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-left: auto;
}

.cal-header__manage {
  font-size: 0.8125rem;
  color: var(--color-ink-lighter);
}

/* Inline swatch used in forms and headings. */
/* Calendar settings, opened from the calendar's own events page. Wide enough
   for the colour picker inside it, which sets its own floor. */
.calendar-settings-dialog {
  position: relative;
  max-width: 680px;
  width: calc(100vw - var(--space-8));
  max-height: calc(100vh - var(--space-8));
  overflow-y: auto;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  background: var(--color-component-surface);
  color: var(--color-ink);
}

.calendar-settings-dialog::backdrop {
  background: rgba(0, 0, 0, 0.5);
}

/* The colour control as one enclosed thing. Its parts — wheel, brightness
   track, hex field, swatches — are separate controls that only make sense read
   together, and loose in a form they look like four unrelated fields stacked up.
   The tint is mixed from --color-ink so it reads as a slight step off the
   surface in either scheme without needing a pair of overrides. */
.color-field {
  display: grid;
  gap: var(--space-4);
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: color-mix(in srgb, var(--color-ink) 4%, transparent);
}

.color-field__label {
  display: block;
  font-size: var(--text-sm);
  color: var(--color-ink);
}

/* ── Color picker ────────────────────────────────────────────
   An HSV wheel: the conic gradient is the hue, the white radial gradient over
   it is saturation falling off toward the centre, and __shade is brightness
   painted on as a black veil. See color_picker_controller.js. */
/* Wide enough for the presets, a full set of suggestions and the button on one
   line — the button is supposed to travel right as colours appear, and a
   wrapped row would drop it onto the next line instead. */
.color-picker {
  display: grid;
  gap: var(--space-4);
  justify-items: start;
  max-width: 34rem;
}

/* The wheel keeps its own width regardless, so widening the block above doesn't
   strand it in the middle of a lot of empty space. */
.color-picker__stage {
  display: grid;
  justify-items: center;
  width: 100%;
  max-width: 22rem;
  /* The wheel is a circle against straight-edged neighbours, so the gap that
     looks right elsewhere in the form looks tight here. Matched above and below
     it: the space over the wheel is this padding plus the panel's own gap, and
     the space under it is this gap, which comes to the same on both sides. */
  padding-block: var(--space-2);
  gap: var(--space-6);
}

.color-picker__wheel {
  position: relative;
  width: 12rem;
  height: 12rem;
  border-radius: var(--radius-full);
  cursor: crosshair;
  touch-action: none;
  background:
    radial-gradient(circle closest-side, #fff, rgb(255 255 255 / 0) 70%),
    conic-gradient(#f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00);
  box-shadow: var(--shadow-md), inset 0 0 0 1px rgb(0 0 0 / 0.08);
}

/* Brightness. pointer-events off so the veil never eats a drag. */
.color-picker__wheel::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: #000;
  opacity: var(--cp-shade, 0);
  pointer-events: none;
}

.color-picker__track {
  position: relative;
  width: 100%;
  height: 0.75rem;
  border-radius: var(--radius-full);
  cursor: pointer;
  touch-action: none;
  background: linear-gradient(to right, #000, var(--cp-track-end, #0a84ff));
  box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.08);
}

.color-picker__thumb {
  position: absolute;
  top: 50%;
  width: 1.125rem;
  height: 1.125rem;
  margin: -0.5625rem 0 0 -0.5625rem;
  border-radius: var(--radius-full);
  background: var(--cp-color, #fff);
  border: 2px solid var(--color-white);
  box-shadow: var(--shadow-md), 0 0 0 1px rgb(0 0 0 / 0.2);
  pointer-events: none;
  z-index: 1;
}

/* Only the wheel's thumb is placed on both axes; the track's rides the middle. */
.color-picker__wheel .color-picker__thumb {
  top: 0;
  margin-top: -0.5625rem;
  transform: translateY(0);
}

.color-picker__thumb:focus-visible {
  outline: 2px solid var(--color-primary-600);
  outline-offset: 2px;
}

.color-picker__readout {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.color-picker__preview {
  width: 2rem;
  height: 2rem;
  flex-shrink: 0;
  border-radius: var(--radius-md);
  background: var(--cp-color, #0a84ff);
  box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.12);
}

.color-picker__hex {
  width: 7.5rem;
  font-family: var(--font-mono, ui-monospace, monospace);
  text-transform: uppercase;
}

.color-picker__presets {
  display: flex;
  flex-wrap: nowrap;
  gap: var(--space-2);
  /* Scrolls rather than wraps on a viewport too narrow to hold the row: wrapping
     would drop the button onto the next line, so revealing a colour would shove
     it left and down instead of aside. At the width above it never comes to
     this. The vertical padding is room for the selected swatch's ring, which an
     overflow container would otherwise clip. */
  max-width: 100%;
  overflow-x: auto;
  padding-block: 5px;
  scrollbar-width: thin;
}

.color-picker__preset {
  width: 1.5rem;
  height: 1.5rem;
  /* Or they compress to fit instead of overflowing, and the row scrolls by less
     than a swatch — the button barely moves and the reveal reads as a twitch. */
  flex-shrink: 0;
  padding: 0;
  border: 0;
  border-radius: var(--radius-full);
  background: var(--cp-color);
  cursor: pointer;
  box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.12);
  transition: transform var(--transition-fast), box-shadow var(--transition-fast),
              width var(--transition-normal), margin var(--transition-normal),
              opacity var(--transition-normal);
}

.color-picker__preset:hover {
  transform: scale(1.12);
}

/* A suggested swatch arrives collapsed and expands, which is what shifts the
   Suggest button to the right. The negative margin cancels the flex gap while
   it has no width — gap can't be transitioned per item, so it would otherwise
   jump the row sideways before the swatch had grown at all. */
.color-picker__preset.is-entering {
  width: 0;
  margin-left: calc(var(--space-2) * -1);
  opacity: 0;
  transform: scale(0.4);
}

/* Already spoken for by another calendar — a notch out of the swatch, since
   colour alone can't carry the message on a row of colours. */
.color-picker__preset.is-taken {
  background:
    radial-gradient(circle at 50% 50%, var(--color-component-surface) 0 0.22rem, rgb(0 0 0 / 0) 0.22rem),
    var(--cp-color);
}

.color-picker__preset.is-selected {
  box-shadow: 0 0 0 2px var(--color-component-surface), 0 0 0 4px var(--cp-color);
}

.color-picker__preset:focus-visible {
  outline: 2px solid var(--color-primary-600);
  outline-offset: 2px;
}

.color-picker__suggest {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  flex-shrink: 0;
  height: 1.5rem;
  padding: 0 var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  background: transparent;
  color: var(--color-ink-light);
  font: inherit;
  font-size: var(--text-xs);
  cursor: pointer;
  transition: background-color var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
}

.color-picker__suggest:hover {
  background: color-mix(in srgb, var(--theme-primary) 10%, transparent);
  border-color: var(--theme-primary);
  color: var(--color-ink);
}

.color-picker__suggest:disabled {
  opacity: 0.5;
  cursor: default;
}

/* A literal duration, not --transition-slow: that token is "300ms ease", and
   the trailing easing collides with this shorthand's own, voiding the rule. */
.color-picker__suggest.is-spinning .color-picker__suggest-icon {
  animation: color-picker-spin 500ms ease-in-out;
}

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

.color-picker__suggest:focus-visible {
  outline: 2px solid var(--color-primary-600);
  outline-offset: 2px;
}

.color-picker__warning {
  margin: 0;
}

/* The controller already skips both effects, but the CSS says so independently
   so nothing animates if a swatch is ever added by some other route. */
@media (prefers-reduced-motion: reduce) {
  .color-picker__preset {
    transition: none;
  }

  .color-picker__suggest.is-spinning .color-picker__suggest-icon {
    animation: none;
  }
}

.color-picker__warning[hidden] {
  display: none;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-color-scheme="light"]) .color-picker__wheel,
  :root:not([data-color-scheme="light"]) .color-picker__track,
  :root:not([data-color-scheme="light"]) .color-picker__preview,
  :root:not([data-color-scheme="light"]) .color-picker__preset:not(.is-selected) {
    box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.16);
  }

  /* Left to the rule above, the selected swatch loses its ring and the picker
     stops showing which preset it is on. */
  :root:not([data-color-scheme="light"]) .color-picker__preset.is-selected {
    box-shadow: 0 0 0 2px var(--color-component-surface), 0 0 0 4px var(--cp-color);
  }

  :root:not([data-color-scheme="light"]) .color-picker__wheel {
    box-shadow: var(--shadow-lg), inset 0 0 0 1px rgb(255 255 255 / 0.16);
  }

  :root:not([data-color-scheme="light"]) .color-picker__thumb {
    border-color: var(--color-component-surface);
  }
}

:root[data-color-scheme="dark"] .color-picker__wheel,
:root[data-color-scheme="dark"] .color-picker__track,
:root[data-color-scheme="dark"] .color-picker__preview,
:root[data-color-scheme="dark"] .color-picker__preset:not(.is-selected) {
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.16);
}

:root[data-color-scheme="dark"] .color-picker__preset.is-selected {
  box-shadow: 0 0 0 2px var(--color-component-surface), 0 0 0 4px var(--cp-color);
}

:root[data-color-scheme="dark"] .color-picker__wheel {
  box-shadow: var(--shadow-lg), inset 0 0 0 1px rgb(255 255 255 / 0.16);
}

:root[data-color-scheme="dark"] .color-picker__thumb {
  border-color: var(--color-component-surface);
}

.cal-swatch {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: var(--radius-full);
  background: var(--cal-color);
  flex-shrink: 0;
  margin-right: 0.35rem;
}

/* A calendar's name as a colour pill — the manage tables and the event popover.
   Named -tag, not .cal-chip: that belongs to the month-grid event chips below,
   and sharing the name meant the grid's rules (display: flex, width: 100%,
   transparent background) were overriding these wherever this was used. */
.cal-chip-tag {
  display: inline-flex;
  align-items: center;
  padding: 0.15rem 0.5rem;
  border-radius: var(--radius-full);
  background: color-mix(in srgb, var(--cal-color) 15%, transparent);
  color: var(--cal-color);
  font-size: 0.75rem;
  font-weight: 600;
  white-space: nowrap;
}

/* The row of calendar pills inside an event popover. */
.popover-event-calendars {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-top: var(--space-3);
}

/* ---------- Month grid: events on their day (Apple Calendar style) ---------- */

/* The day cell stopped being a button so it could hold clickable event chips.
   This restores "click anywhere in the cell to select the day" as a real button
   stretched behind the contents. */
.cal-day__select {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  z-index: 0;
}

/* Everything else sits above the select button so chips stay clickable. */
.cal-day__number,
.cal-day__dots,
.cal-day__events {
  position: relative;
  z-index: 1;
}

.cal-day__select:focus-visible {
  outline: 2px solid var(--theme-primary);
  outline-offset: -2px;
}

/* Hidden until there's room — narrow viewports keep the dots + list below.
   flex: 1 + min-height: 0 so it takes exactly the space left under the date
   number and clips there, which is the height calendar#fitDays measures against
   to decide how many events fit. */
.cal-day__events {
  display: none;
  flex: 1;
  min-height: 0;
  flex-direction: column;
  gap: 1px;
  overflow: hidden;
  pointer-events: none; /* clicks fall through the gaps to the day-select button */
}

.cal-day__events > * {
  pointer-events: auto;
}

/* One knob for event text, stepped up alongside the width ladder below. Starts
   small enough to fit a cramped cell and tops out at --text-sm (14px), the
   sidebar's size — past that the calendar would be reading larger than the app
   around it. */
.cal-grid {
  --cal-chip-size: 0.6875rem; /* 11px */
}

/* One event. A timed event reads as a coloured dot + time + title; an all-day
   one is a filled bar, which is how the eye tells them apart at a glance. */
.cal-chip {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  width: 100%;
  /* Hold full height rather than shrinking. As flex items in a height-capped
     column these squash to a couple of unreadable pixels instead of overflowing,
     and because they then "fit", calendar#fitDays sees nothing to collapse and
     never shows "N more". Overflowing is the point — that's the signal. */
  flex-shrink: 0;
  padding: 1px 4px;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-ink);
  font-size: var(--cal-chip-size);
  line-height: 1.35;
  text-align: left;
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
}

.cal-chip:hover {
  background: color-mix(in srgb, var(--cal-color) 18%, transparent);
}

.cal-chip__dot {
  width: 6px;
  height: 6px;
  border-radius: var(--radius-full);
  background: var(--cal-color);
  flex-shrink: 0;
}

.cal-chip__time {
  color: var(--color-ink-lighter);
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
}

/* min-width: 0 so the title can actually shrink inside the flex row — without
   it a flex item refuses to go below its content width and the ellipsis never
   kicks in, which is what pushed the columns out of line. */
.cal-chip__title {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cal-chip--all-day {
  background: var(--cal-color);
  color: #fff;
  font-weight: var(--font-medium);
}

.cal-chip--all-day:hover {
  background: color-mix(in srgb, var(--cal-color) 85%, black);
}

/* The hidden attribute has to be able to beat the display rules above. An author
   `display: flex` outranks the UA stylesheet's [hidden] { display: none }, so
   without this the chips calendar#fitDays hides still take up space — the cell
   just clips them, and "N more" gets pushed out of sight along with them. */
.cal-chip[hidden],
.cal-day__overflow[hidden] {
  display: none;
}

.cal-day__overflow {
  flex-shrink: 0;
  padding: 0 4px;
  border: 0;
  background: transparent;
  color: var(--color-ink-lighter);
  font-size: var(--cal-chip-size);
  text-align: left;
  cursor: pointer;
}

.cal-day__overflow:hover {
  color: var(--color-ink);
  text-decoration: underline;
}

/* Roomy viewports: swap the dots for the events themselves and let the grid
   stand on its own — the list below turns into a day detail, shown only once a
   day is picked. The cells get their height from aspect-ratio, so there's no
   min-height to set here. */
@media (min-width: 1024px) {
  .cal-page {
    max-width: 72rem;
  }

  /* Fit the month to the window. Someone opening this to present on a 1366x768
     laptop should see all six weeks at once, not scroll for the last fortnight.
     .app-shell__content already has a definite height (the shell is
     100vh minus the masquerade banner), so 100% resolves against it.

     A definite height, not min-height: with min-height the column is free to grow
     past the fold, so nothing ever pressures the grid to shrink and the month
     runs off the bottom exactly as before. Pinning the height is what makes the
     shrink below actually happen. */
  .cal-page {
    display: flex;
    flex-direction: column;
    height: 100%;
  }

  /* The day detail opens under a grid that now owns the full height, so it takes
     what's left and scrolls itself rather than pushing the month off-screen. */
  .cal-events {
    min-height: 0;
    overflow-y: auto;
  }

  /* The height has to travel from .cal-page down to the grid, and there are two
     boxes in between: the turbo-frame the month is swapped through, and the
     Stimulus root inside it. Both are plain blocks by default, so the chain
     breaks at them and the grid never learns how much room it has. */
  #calendar_content,
  .cal-layout {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
  }

  .cal-grid {
    display: flex;
    flex-direction: column;
    min-height: 0;
    --cal-chip-size: 0.75rem; /* 12px */
  }

  /* 7 columns over 6 rows, so this ratio is what makes the cells square — the
     square is a property of the grid now, not of each cell.

     flex: 0 1 auto is the whole trick: no grow, so on a tall window the ratio
     caps the height and the cells stay square; shrink allowed, so on a short one
     it compresses and the cells go wide rather than the month running off the
     bottom. */
  .cal-days {
    flex: 0 1 auto;
    min-height: 0;
    aspect-ratio: 7 / 6;
    grid-auto-rows: minmax(0, 1fr);
  }

  /* Height comes from the row now. Keeping a per-cell aspect-ratio here would
     fight the grid and win, and the month would overflow again. */
  .cal-day {
    aspect-ratio: auto;
  }

  /* Back to the left, so the date lines up with the event chips beneath it. */
  .cal-day__number {
    align-self: flex-start;
  }

  .cal-day__dots {
    display: none;
  }

  .cal-day__events {
    display: flex;
  }

  /* The grid already shows every event, so the list is redundant here until you
     pick a day — then it becomes that day's detail. Narrow viewports never get
     this class and keep the list on permanently. */
  .cal-events {
    display: none;
  }

  .cal--day-selected .cal-events {
    display: block;
  }
}

/* The clear-selection button means "un-filter the list" on a narrow viewport and
   "close the day detail" on a wide one — show whichever label is true. */
.cal-clear--wide {
  display: none;
}

@media (min-width: 1024px) {
  .cal-clear--narrow {
    display: none;
  }

  .cal-clear--wide {
    display: inline;
  }
}

/* Width ladder for the month grid. The cells are square, so width buys height,
   and height is what lets a day show all its events instead of "N more". Each
   step roughly adds a couple of visible events per day:
   1024px → ~155px cells (~8 events), 1440px → ~190px (~11), 1920px → ~215px (~13).

   It stops at 100rem deliberately. Past that the squares get tall enough that the
   six-week grid needs real scrolling, and the extra room adds height rather than
   content — a day with more than ~13 events is better read in the day detail. */
@media (min-width: 1440px) {
  .cal-page {
    max-width: 88rem;
  }

  .cal-grid {
    --cal-chip-size: 0.8125rem; /* 13px */
  }
}

@media (min-width: 1920px) {
  .cal-page {
    max-width: 100rem;
  }

  /* The cap: same as the sidebar, so the two read as one interface. Bigger
     screens past here get more cell, not bigger text. */
  .cal-grid {
    --cal-chip-size: var(--text-sm); /* 14px */
  }
}

/* Ultrawide and 4K. Squares this large make a tall grid — roughly 1800px for six
   weeks — so this step trades scrolling for showing a busy day in full rather
   than behind "N more". */
@media (min-width: 2560px) {
  .cal-page {
    max-width: 128rem;
  }
}

/* ── Volunteer hours progress ──────────────────────────────────────────────
   A family's earned hours against their goal. Structurally the same as
   .fundraiser-progress above, but that block is built around currency and a
   public campaign page; this one is a signed-in stat with a plain hours figure,
   so it gets its own class rather than a set of overrides. Semantic tokens
   throughout, so it reads correctly in both colour schemes. */
.hours-progress {
  margin: 0;
}

.hours-progress__figures {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}

.hours-progress__earned {
  font-size: 1.75rem;
  font-weight: var(--font-bold);
  color: var(--brand-primary, var(--color-primary-600));
}

.hours-progress__goal {
  color: var(--color-ink-light);
  font-size: var(--text-sm);
}

.hours-progress__bar {
  height: 12px;
  background: var(--color-component-surface);
  border-radius: var(--radius-full);
  overflow: hidden;
  border: 1px solid var(--color-border);
}

.hours-progress__fill {
  height: 100%;
  background: var(--brand-primary, var(--color-primary-500));
  transition: width var(--transition-normal);
}

.hours-progress__caption {
  margin: var(--space-2) 0 0;
  font-size: var(--text-sm);
  color: var(--color-ink-light);
}

/* Copy/download button — every state's label lives in the button as its own
   span, swapped by a class so confirming never rewrites textContent (which
   would eat an icon and lose the original label across a Turbo morph). */
.copy-btn__done,
.copy-btn__working {
  display: none;
  align-items: center;
  gap: var(--space-1);
}

.copy-btn--done .copy-btn__label,
.copy-btn--working .copy-btn__label {
  display: none;
}

.copy-btn--working .copy-btn__working {
  display: inline-flex;
  animation: copyBtnPulse 1.1s ease-in-out infinite;
}

.copy-btn--done .copy-btn__done {
  display: inline-flex;
  animation: copyBtnPop 0.35s ease-out;
}

.copy-btn--done {
  color: var(--color-success-700);
  border-color: var(--color-success-600);
}

.copy-btn--working {
  cursor: progress;
}

@keyframes copyBtnPulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.5; }
}

@keyframes copyBtnPop {
  0%   { transform: scale(0.85); opacity: 0; }
  60%  { transform: scale(1.06); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .copy-btn--done .copy-btn__done,
  .copy-btn--working .copy-btn__working { animation: none; }
}

/* The check-in code actions sit in a table cell that must not wrap mid-button. */
.code-actions {
  display: inline-flex;
  gap: var(--space-2);
  justify-content: flex-end;
  flex-wrap: wrap;
}

/* A menu item with the file type held out to the right, so the label reads
   cleanly and the types line up down the menu. */
.row-actions__menu .row-actions-menu__item--typed {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-6);
}

.row-actions-menu__item__type {
  font-size: var(--text-xs);
  color: var(--color-ink-light);
}

/* The PTA page is centred against the browser window, not against the space
   left over beside the sidebar. Centring in the content area alone leaves the
   page sitting right of centre by half the sidebar's width, which reads as
   off-centre on a wide display. Reserving the sidebar's width on the right of
   the wrapper puts the middle of the content back over the middle of the
   window.

   Only above 1500px, where there's room to give that width away without
   squeezing the board. Below it the page just centres in the content area as
   any other page does. */
.pta-page {
  --sidebar-width: 18rem;
}

.app-shell:has(.sidebar.is-collapsed) .pta-page {
  --sidebar-width: 5rem;
}

/* Only inside the app shell: this padding balances the fixed sidebar, and the
   signed-out page has none — there it just shoved the board off-centre. */
@media (min-width: 1500px) {
  .app-shell .pta-page {
    padding-right: var(--sidebar-width);
    transition: padding-right var(--transition-normal);
  }
}

/* The PTA page's own header: centred, because it's a front-door page for the
   whole school rather than a form. */
.pta-header {
  text-align: center;
  margin-bottom: var(--space-8);
}

.pta-header__title {
  margin-bottom: var(--space-2);
}

.pta-header__tagline {
  max-width: 44rem;
  margin: 0 auto;
  color: var(--color-ink-light);
}

/* The PTA's own words, when they've written some. Same measure and colour as
   the stock tagline so the header reads the same either way, but it's rich text
   — several paragraphs, a list, a link — so it needs block spacing the one-line
   tagline never did. */
.pta-header__description {
  max-width: 44rem;
  margin: 0 auto;
  color: var(--color-ink-light);
  text-align: left;
}

.pta-header__description > *:last-child {
  margin-bottom: 0;
}

.pta-header__description a {
  color: var(--color-link);
}

.pta-header__actions {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-4);
}

/* PTA board
   A directory of the people who run the PTA: a portrait tile per person, name
   and title underneath. Tiles are a fixed 4:5 portrait so a row lines up
   whatever shape the photos are, and the grid reflows from four across down to
   two on a phone rather than shrinking the faces. */
.pta-board {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: var(--space-6) var(--space-5);
}

.pta-board__member {
  min-width: 0;
}

.pta-board__portrait {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  background: var(--color-component-surface);
  border-radius: var(--radius-lg);
  margin-bottom: var(--space-3);
}

/* Initials stand in when there's no photo — same box, so the grid doesn't
   change shape depending on who has uploaded one. Deliberately quieter than the
   small round avatars elsewhere: at tile size a full-bleed brand colour shouts
   over the faces beside it, so these read as a neutral placeholder instead. */
.pta-board__portrait--initials {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-component-surface);
  color: var(--color-ink-light);
  font-size: var(--text-2xl);
  font-weight: var(--font-semibold);
  letter-spacing: 0.05em;
}

.pta-board__name {
  display: inline-block;
  font-size: var(--text-base);
  font-weight: var(--font-medium);
  color: var(--color-link);
  margin-bottom: var(--space-1);
}

.pta-board__name:hover {
  color: var(--color-link-hover);
  text-decoration: underline;
}

.pta-board__title {
  font-size: var(--text-sm);
  color: var(--color-ink);
  margin-bottom: 0;
}

/* Clamped rather than left to run: most bios are two or three sentences and
   show in full, but one long one would otherwise stretch its tile and throw the
   row out of line. The full text is on the member's own page. */
.pta-board__bio {
  margin-top: var(--space-2);
  margin-bottom: 0;
  font-size: var(--text-sm);
  color: var(--color-ink-light);
  line-height: 1.5;
  display: -webkit-box;
  -webkit-line-clamp: 5;
  line-clamp: 5;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* One person's profile: the portrait beside the bio, stacking on a phone. */
.pta-profile {
  display: flex;
  gap: var(--space-6);
  align-items: flex-start;
}

.pta-profile__portrait {
  width: 220px;
  flex-shrink: 0;
}

.pta-profile__bio {
  color: var(--color-ink);
  line-height: 1.7;
}

@media (max-width: 640px) {
  .pta-profile {
    flex-direction: column;
  }

  .pta-profile__portrait {
    width: 160px;
  }
}

/* Date picker
   A native <input type="date"> upgraded on desktop to a Cally calendar in a
   popover (see date_picker_controller). The input itself stays in the DOM and
   stays the field that submits — it's only hidden from view — so everything
   here is decoration over a form that already works without it.

   Untouched on touch devices: the controller doesn't upgrade there, so the
   input renders as the plain field the rest of the form uses. */
.date-picker {
  position: relative;
}

.date-picker--upgraded > input[type="date"] {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Reads as one of the form's own inputs, because as far as the person filling
   it in that's exactly what it is. */
.date-picker__trigger {
  display: block;
  width: 100%;
  text-align: left;
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-base);
  font-family: inherit;
  color: var(--color-ink);
  line-height: var(--leading-normal);
  background-color: var(--color-canvas);
  border: 1px solid var(--color-border-dark);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.date-picker__trigger:hover {
  border-color: var(--color-primary-400);
}

/* The same focus ring the other inputs get, since it reads as one of them. */
.date-picker__trigger:focus-visible {
  outline: none;
  border-color: var(--color-primary-500);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--theme-primary) 30%, transparent);
}

.date-picker__trigger--empty {
  color: var(--color-ink-light);
}

.time-picker {
  position: relative;
}

.time-picker--upgraded > input[type="time"] {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.date-picker__popover {
  position: absolute;
  top: calc(100% + var(--space-2));
  left: 0;
  z-index: 100;
  background: var(--color-component-surface);
  border: 1px solid var(--color-border-dark);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: var(--space-3);
}

/* Cally exposes its internals as CSS parts, so the calendar takes the school's
   theme colour and the app's own tokens rather than shipping a second palette
   that would need its own dark mode.

   The accent is declared on calendar-month as well as its parent, not only on
   the wrapper: each component ships `:host { --color-accent: black }`, and a
   :host declaration beats a value inherited from an ancestor. Set it only on
   calendar-date and the days stay black while everything else themes. */
.date-picker__calendar,
.date-picker__calendar calendar-month {
  --color-accent: var(--color-primary-600);
  --color-text-on-accent: var(--color-white);
}

.date-picker__calendar {
  color: var(--color-ink);
  font-family: inherit;
}

.date-picker__heading {
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
}

/* One heading, in the header, rather than the year up top and the month again
   below — see the controller. */
.date-picker__calendar calendar-month::part(heading) {
  display: none;
}

.date-picker__chevron {
  width: 1rem;
  height: 1rem;
}

.date-picker__calendar::part(header) {
  margin-bottom: var(--space-2);
}

.date-picker__calendar::part(heading) {
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
}

.date-picker__calendar::part(button) {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  color: var(--color-ink);
  border: 1px solid var(--color-border-dark);
  border-radius: var(--radius-md);
  background: transparent;
}

/* Mixed from the ink rather than a fixed gray: --color-gray-100 stays light in
   dark mode, where it's what --color-ink is made of. */
.date-picker__calendar::part(button):hover {
  background: color-mix(in srgb, var(--color-ink) 10%, transparent);
}

.date-picker__calendar calendar-month::part(day) {
  border-radius: var(--radius-md);
  color: var(--color-ink);
}

/* Both parts, so this is the day buttons only: the weekday headings carry
   `day` as well, and they aren't clickable — a hover on "T" invites a click
   that does nothing. */
.date-picker__calendar calendar-month::part(button day):hover {
  background: color-mix(in srgb, var(--color-ink) 16%, transparent);
}


.date-picker__calendar calendar-month::part(today) {
  font-weight: var(--font-semibold);
  box-shadow: inset 0 0 0 1px var(--color-primary-400);
}

.date-picker__calendar calendar-month::part(outside) {
  color: var(--color-ink-light);
}

.date-picker__calendar calendar-month::part(disallowed) {
  color: var(--color-ink-lighter);
  text-decoration: line-through;
}

/* Popover footer — the shortcuts under the calendar. Today is where people go
   most often; Clear only appears on a field where blank is a real answer. */
.date-picker__footer {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid var(--color-border);
}

.date-picker__action {
  padding: var(--space-1) var(--space-2);
  font-size: var(--text-sm);
  font-family: inherit;
  font-weight: var(--font-medium);
  color: var(--color-link);
  background: transparent;
  border: 0;
  border-radius: var(--radius-md);
  cursor: pointer;
}

.date-picker__action:hover {
  background: color-mix(in srgb, var(--color-ink) 10%, transparent);
}

.date-picker__action--muted {
  color: var(--color-ink-light);
  justify-self: end;
}

/* Time picker
   The same trigger and popover as the date picker, holding a list of times
   instead of a calendar. Sized to show about seven at once — enough to see the
   shape of the list without covering the field below it. */
.time-picker__popover {
  padding: var(--space-1);
}

.time-picker__list {
  max-height: 15rem;
  min-width: 9rem;
  overflow-y: auto;
  outline: none;
}

.time-picker__option {
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-sm);
  color: var(--color-ink);
  border-radius: var(--radius-md);
  cursor: pointer;
}

.time-picker__option:hover,
.time-picker__option--active {
  background: color-mix(in srgb, var(--color-ink) 10%, transparent);
}

/* The chosen time keeps the accent even while the keyboard is somewhere else in
   the list, so you can always see what the field currently holds. */
.time-picker__option[aria-selected="true"] {
  background: var(--color-primary-600);
  color: var(--color-white);
  font-weight: var(--font-medium);
}
