/* ======================================================================
   community.css — member surfaces (feed · post · welcome · benefits).
   Phase 1.3, Session 4. Token-driven: every color/space/radius comes from
   static/css/themes/tokens.css (light + dark handled there). Loaded via
   _head_base.html with ?v={{ theme_asset_version }} (§7.6).

   Voice: DM Sans carries the product; JetBrains Mono (--font-mono) is the
   status layer — level chips, timestamps, counts — the community's own
   thread inside the app_cc look. Fraunces appears ONLY on the gate pages
   (welcome/benefits) via fonts_extra_html.
   ====================================================================== */

/* ---------------------------------------------------------------- nav -- */

.cc-nav {
  background: var(--bg-panel);
  border-bottom: 1px solid var(--border-subtle);
}

.cc-nav-inner {
  max-width: 860px;
  margin: 0 auto;
  padding: var(--space-md) var(--space-lg);
  display: flex;
  align-items: center;
  gap: var(--space-md);
}

.cc-nav-brand {
  font-weight: 700;
  font-size: 17px;
  color: var(--text-primary);
  text-decoration: none;
}
.cc-nav-brand:hover { color: var(--text-primary); }

.cc-nav-scope {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-on-light);
  border-left: 1px solid var(--border-subtle);
  padding-left: var(--space-md);
}

.cc-nav-links {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: var(--space-md);
}

.cc-nav-link {
  color: var(--text-muted);
  text-decoration: none;
  font-size: 14px;
  transition: color var(--transition-fast);
}
.cc-nav-link:hover { color: var(--accent-on-light); }

.cc-nav-admin {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--warning);
  border: 1px solid var(--warning);
  border-radius: var(--radius-pill);
  padding: 2px 8px;
  white-space: nowrap;
}

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

.cc-shell {
  max-width: 860px;
  margin: 0 auto;
  padding: var(--space-lg) var(--space-lg) var(--space-3xl);
}

.cc-flash {
  border-radius: var(--radius-sm);
  padding: 10px 14px;
  font-size: 14px;
  margin-bottom: var(--space-md);
  border: 1px solid var(--border-subtle);
}
.cc-flash.success { background: var(--success-bg); color: var(--success); }
.cc-flash.danger  { background: var(--danger-bg);  color: var(--danger); }

/* ----------------------------------------------------------- composer -- */

.cc-composer {
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  margin-bottom: var(--space-lg);
}

.cc-composer-collapsed {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  width: 100%;
  padding: 14px 16px;
  background: transparent;
  border: 0;
  cursor: pointer;
  text-align: left;
  color: var(--text-faint);
  font-size: 15px;
  font-family: var(--font-sans);
}
.cc-composer-collapsed:hover { color: var(--text-muted); }

.cc-composer-form { display: none; padding: 16px; }
.cc-composer.open .cc-composer-form { display: block; }
.cc-composer.open .cc-composer-collapsed { display: none; }

.cc-input-title {
  width: 100%;
  background: var(--bg-input);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: 17px;
  font-weight: 600;
  padding: 10px 12px;
  margin-bottom: var(--space-sm);
}
.cc-input-title::placeholder { color: var(--text-faint); font-weight: 500; }
.cc-input-title:focus { border-color: var(--accent); outline: none; }

.cc-toolbar {
  display: flex;
  gap: var(--space-xs);
  flex-wrap: wrap;
  margin-bottom: var(--space-sm);
}

.cc-tb {
  background: var(--bg-panel);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  font-size: 13px;
  padding: 5px 10px;
  cursor: pointer;
  transition: color var(--transition-fast), border-color var(--transition-fast);
}
.cc-tb:hover { color: var(--text-primary); }
.cc-tb.active {
  color: var(--accent-on-light);
  border-color: var(--accent);
}

.cc-editor {
  background: var(--bg-input);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  min-height: 120px;
  margin-bottom: var(--space-sm);
}
.cc-editor:focus-within { border-color: var(--accent); }
.cc-editor .ProseMirror { outline: none; min-height: 100px; }
.cc-editor .is-editor-empty:first-child::before {
  content: attr(data-placeholder);
  color: var(--text-faint);
  float: left;
  height: 0;
  pointer-events: none;
}

.cc-composer-foot {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  flex-wrap: wrap;
}

.cc-select {
  background: var(--bg-input);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
  color: var(--text-body);
  font-family: var(--font-sans);
  font-size: 14px;
  padding: 8px 10px;
  max-width: 220px;
}

.cc-attach-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--text-muted);
  font-size: 14px;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-sm);
  padding: 7px 12px;
  cursor: pointer;
  transition: color var(--transition-fast), border-color var(--transition-fast);
}
.cc-attach-label:hover { color: var(--accent-on-light); border-color: var(--accent); }
.cc-attach-label input { display: none; }

.cc-attach-previews {
  display: flex;
  gap: var(--space-sm);
  flex-wrap: wrap;
  margin-top: var(--space-sm);
}
.cc-attach-previews img {
  width: 56px;
  height: 56px;
  object-fit: cover;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-subtle);
}

.cc-composer-error {
  color: var(--danger);
  font-size: 13px;
  margin-top: var(--space-sm);
  min-height: 1em;
}

.cc-btn {
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
  background: var(--bg-panel);
  color: var(--text-body);
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: 600;
  padding: 8px 18px;
  cursor: pointer;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  transition: transform var(--transition-fast), box-shadow var(--transition-fast);
}
.cc-btn:hover { color: var(--text-primary); }

.cc-btn-gold {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--text-on-accent);
  margin-left: auto;
}
.cc-btn-gold:hover {
  color: var(--text-on-accent);
  transform: translateY(-1px);
  box-shadow: 0 4px 14px var(--accent-glow);
}
.cc-btn-gold:disabled { opacity: 0.55; cursor: default; transform: none; }

.cc-btn-ghost {
  background: transparent;
  color: var(--text-muted);
}

/* ------------------------------------------------------------ feedbar -- */

/* S22 (Marc gate): areas and sort stopped competing for one line. Sort is a
   setting — it collapsed to a single button (below) — so the chips take the
   row and WRAP. The old `overflow-x: auto` with a switched-off scrollbar was
   measured hiding 160px of areas at five areas on an 860px column: members
   could not see that anything was missing. Same lesson as §4.48's nav wrap
   and the members page's "wrap, never scroll" rule — fix the layout, never
   clip. align-items: flex-start so a wrapped second line does not drag the
   sort button down with it. */
.cc-feedbar {
  display: flex;
  align-items: flex-start;
  gap: var(--space-md);
  margin-bottom: var(--space-md);
}

.cc-areas {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
  flex: 1;
  min-width: 0;
}

.cc-area-chip {
  white-space: nowrap;
  font-size: 13.5px;
  font-weight: 500;
  color: var(--text-muted);
  background: var(--bg-panel);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-pill);
  padding: 6px 14px;
  text-decoration: none;
  transition: color var(--transition-fast), border-color var(--transition-fast);
}
.cc-area-chip:hover { color: var(--text-primary); }
.cc-area-chip.active {
  color: var(--accent-on-light);
  border-color: var(--accent);
  background: var(--accent-glow);
  font-weight: 600;
}
.cc-area-chip .n {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-faint);
  margin-left: 4px;
}

/* S22 (Marc): area description tooltips, 450ms in. The delay IS the feature —
   the row stays silent while the mouse sweeps across it and speaks only when
   you actually stop on a chip. The pause lives on the IN transition only;
   leaving is immediate, so travelling along the row never drags a trail of
   tips behind it. Wears .cc-heritage-tip's clothes verbatim (card fill,
   accent hairline, downward arrow) so no new visual atom enters the system,
   and opens DOWNWARD like every other tip here. The only animated property is
   opacity — no transform — so prefers-reduced-motion needs no special case.
   Text is community_areas.description: editable in the areas admin, never in
   code. Wrapped in @media (hover: hover) because on touch a :hover tooltip
   latches open after a tap with no way to dismiss it. The base rule below
   is load-bearing: without it, non-hover devices match NONE of the tip
   styles and the description renders as plain inline text inside the pill
   (Marc's Jul 30 phone screenshot). Hidden everywhere first; hover-capable
   devices bring it back as the positioned tooltip. */
.cc-area-tip { display: none; }

@media (hover: hover) {
  .cc-area-chip { position: relative; }

  .cc-area-tip {
    display: block;
    position: absolute;
    top: calc(100% + 9px);
    left: 0;
    z-index: 40;
    width: max-content;
    max-width: min(260px, 78vw);
    background: var(--bg-card);
    border: 1px solid var(--accent);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-elevated);
    padding: 8px 11px;
    font-size: 12.5px;
    font-weight: 400;
    line-height: 1.45;
    color: var(--text-muted);
    white-space: normal;
    text-align: left;
    opacity: 0;
    visibility: hidden;
    transition: opacity 90ms ease, visibility 0s linear 90ms;
  }
  .cc-area-tip::after {
    content: '';
    position: absolute;
    bottom: 100%;
    left: 14px;
    border: 6px solid transparent;
    border-bottom-color: var(--accent);
  }

  .cc-area-chip:hover .cc-area-tip,
  .cc-area-chip:focus-visible .cc-area-tip {
    opacity: 1;
    visibility: visible;
    transition: opacity 120ms ease 450ms, visibility 0s linear 450ms;
  }

  /* The rightmost chip's tip would run off the edge — anchor it to the right. */
  .cc-areas .cc-area-chip:last-child .cc-area-tip { left: auto; right: 0; }
  .cc-areas .cc-area-chip:last-child .cc-area-tip::after {
    left: auto;
    right: 14px;
  }
}

/* S22: sort as ONE button plus a menu (the four pills are gone). The button
   wears the chip vocabulary — panel fill, pill radius — with the mono status
   voice on the "SORT" cap and the accent on the current value: the state
   stays loud while the options move one click away. The list reuses the bell
   dropdown's clothes verbatim, so no new visual atom enters the system. */
.cc-sortmenu { position: relative; flex: 0 0 auto; }

.cc-sortbtn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  background: var(--bg-panel);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-pill);
  padding: 6px 13px;
  font-family: var(--font-sans);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--accent-on-light);
  cursor: pointer;
  white-space: nowrap;
  transition: border-color var(--transition-fast);
}
.cc-sortbtn:hover { border-color: var(--border-strong); }
.cc-sortbtn[aria-expanded="true"] { border-color: var(--accent); }
.cc-sortbtn-cap {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.cc-sortbtn svg { color: var(--text-muted); }

.cc-sort-list {
  display: none;
  flex-direction: column;
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 40;
  min-width: 172px;
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-elevated);
  padding: 4px;
}
.cc-sortmenu.open .cc-sort-list { display: flex; }

.cc-sort-list a {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  font-size: 13.5px;
  font-weight: 500;
  color: var(--text-body);
  text-decoration: none;
  border-radius: var(--radius-sm);
  padding: 7px 10px;
  white-space: nowrap;
}
.cc-sort-list a:hover { background: var(--bg-panel); color: var(--text-primary); }
.cc-sort-list a.active {
  background: var(--accent-glow);
  color: var(--accent-on-light);
  font-weight: 600;
}
/* The team-only sort names itself, below a hairline: the team can see at a
   glance that members cannot reach this view. */
.cc-sort-list a.team {
  margin-top: 3px;
  padding-top: 9px;
  border-top: 1px solid var(--border-faint);
}
.cc-sort-team {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--success);
  background: var(--success-bg);
  border-radius: 4px;
  padding: 2px 6px;
}

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

.cc-card {
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  padding: 16px;
  margin-bottom: var(--space-md);
  transition: box-shadow var(--transition-base);
}
.cc-card:hover { box-shadow: var(--shadow-elevated); }

.cc-card-pin {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent-on-light);
  margin-bottom: 10px;
}
.cc-card-pin svg { width: 12px; height: 12px; }

.cc-card-head {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
}

.cc-avatar {
  width: 38px;
  height: 38px;
  flex: 0 0 38px;
  border-radius: 50%;
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  color: var(--text-muted);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 700;
}
.cc-avatar.sm { width: 30px; height: 30px; flex-basis: 30px; font-size: 11px; }

.cc-byline { min-width: 0; }

.cc-author {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 14.5px;
  font-weight: 600;
  color: var(--text-primary);
}

.cc-lvl {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.05em;
  color: var(--accent-on-light);
  background: var(--accent-glow);
  border-radius: 4px;
  padding: 1px 6px;
  white-space: nowrap;
}

.cc-meta {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-faint);
  margin-top: 2px;
}
.cc-meta a {
  color: var(--text-muted);
  text-decoration: none;
}
.cc-meta a:hover { color: var(--accent-on-light); }

.cc-card-title {
  display: block;
  font-size: 17px;
  font-weight: 700;
  color: var(--text-primary);
  text-decoration: none;
  margin: 12px 0 4px;
  line-height: 1.35;
}
.cc-card-title:hover { color: var(--accent-on-light); }

.cc-card-excerpt {
  color: var(--text-muted);
  font-size: 14px;
  line-height: 1.55;
  margin: 0;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.cc-thumbs {
  display: flex;
  gap: var(--space-sm);
  margin-top: 12px;
}
.cc-thumbs img {
  width: 72px;
  height: 72px;
  object-fit: cover;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-subtle);
}
.cc-thumbs .more {
  width: 72px;
  height: 72px;
  border-radius: var(--radius-sm);
  border: 1px dashed var(--border-strong);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-muted);
}

.cc-card-foot {
  display: flex;
  align-items: center;
  gap: var(--space-lg);
  margin-top: 12px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-faint);
}
.cc-card-foot svg {
  width: 14px;
  height: 14px;
  vertical-align: -2px;
  margin-right: 4px;
}

.cc-loadmore {
  display: block;
  margin: var(--space-lg) auto 0;
}

.cc-empty {
  text-align: center;
  color: var(--text-muted);
  padding: var(--space-3xl) var(--space-lg);
  font-size: 15px;
}
.cc-empty strong { color: var(--text-primary); display: block; margin-bottom: 6px; }

/* --------------------------------------------------------- post page -- */

.cc-back {
  display: inline-block;
  font-size: 13.5px;
  color: var(--text-muted);
  text-decoration: none;
  margin-bottom: var(--space-md);
}
.cc-back:hover { color: var(--accent-on-light); }

.cc-post {
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  padding: var(--space-lg);
}

.cc-post-title {
  font-size: 26px;
  font-weight: 700;
  line-height: 1.25;
  margin: 14px 0 6px;
  color: var(--text-primary);
}

.cc-area-tag {
  font-size: 12px;
  font-weight: 600;
  color: var(--accent-on-light);
  background: var(--accent-glow);
  border-radius: var(--radius-pill);
  padding: 3px 10px;
  text-decoration: none;
  white-space: nowrap;
  margin-left: auto;
}

.cc-richtext {
  color: var(--text-body);
  font-size: 15.5px;
  line-height: 1.65;
  margin-top: var(--space-md);
  overflow-wrap: break-word;
}
.cc-richtext p { margin: 0 0 0.9em; }
.cc-richtext h2 { font-size: 20px; margin: 1.2em 0 0.4em; }
.cc-richtext h3 { font-size: 17px; margin: 1.1em 0 0.4em; }
.cc-richtext ul, .cc-richtext ol { padding-left: 24px; margin: 0 0 0.9em; }
.cc-richtext blockquote {
  border-left: 3px solid var(--accent);
  margin: 0 0 0.9em;
  padding: 2px 0 2px 14px;
  color: var(--text-muted);
}
.cc-richtext code {
  font-family: var(--font-mono);
  font-size: 0.88em;
  background: var(--bg-panel);
  border: 1px solid var(--border-faint);
  border-radius: 4px;
  padding: 1px 5px;
}
.cc-richtext pre {
  background: var(--bg-panel);
  border: 1px solid var(--border-faint);
  border-radius: var(--radius-sm);
  padding: 12px;
  overflow-x: auto;
}
.cc-richtext pre code { background: none; border: 0; padding: 0; }

/* Link policy (the rule lives in services/sanitize.py — this is its face).
   An anchor WITH an href survived the chokepoint, so it points at us: it
   wears --secondary, the token system's link blue and the one colour on this
   gold surface that reads as "click me" instead of as brand.
   An anchor WITHOUT an href is an EXTERNAL link the chokepoint neutralized,
   and it must read as plain body text. That has to be said out loud, because
   tokens.css styles every bare <a> gold-and-underlined — inheriting that
   would leave a dead link looking perfectly clickable. Both rules restate
   :hover and :visited for the same reason: tokens.css styles those too. */
.cc-richtext a[href],
.cc-richtext a[href]:hover,
.cc-richtext a[href]:visited { color: var(--secondary); filter: none; }
.cc-richtext a[href]:hover { text-decoration-thickness: 2px; }
.cc-richtext a:not([href]),
.cc-richtext a:not([href]):hover,
.cc-richtext a:not([href]):visited {
  color: inherit;
  text-decoration: none;
  filter: none;
}

.cc-post-images { margin-top: var(--space-md); }
.cc-post-images img {
  display: block;
  max-width: 100%;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-subtle);
  margin-bottom: var(--space-sm);
}

.cc-post-foot {
  display: flex;
  align-items: center;
  gap: var(--space-lg);
  margin-top: var(--space-lg);
  padding-top: var(--space-md);
  border-top: 1px solid var(--border-faint);
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--text-faint);
}

/* ------------------------------------------------- gate (welcome/etc) -- */

.cc-gate {
  min-height: calc(100vh - 70px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-2xl) var(--space-lg);
  position: relative;
}
.cc-gate::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse 70% 50% at 50% 30%,
              var(--accent-glow), transparent 70%);
  opacity: 0.5;
  pointer-events: none;
}

.cc-gate-card {
  position: relative;
  max-width: 560px;
  text-align: center;
}

.cc-gate-kicker {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent-on-light);
  margin-bottom: var(--space-md);
}

.cc-gate-title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(30px, 5.4vw, 42px);
  line-height: 1.15;
  color: var(--text-primary);
  margin: 0 0 var(--space-md);
  text-wrap: balance;
}

.cc-gate-sub {
  color: var(--text-muted);
  font-size: 16px;
  line-height: 1.6;
  margin: 0 0 var(--space-lg);
}

.cc-gate-lines {
  list-style: none;
  padding: 0;
  margin: 0 0 var(--space-xl);
  display: inline-flex;
  flex-direction: column;
  gap: var(--space-sm);
  text-align: left;
}
.cc-gate-lines li {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--text-body);
  font-size: 15.5px;
}
.cc-gate-lines svg {
  width: 16px;
  height: 16px;
  color: var(--accent-on-light);
  flex: 0 0 16px;
}

.cc-join-btn {
  background: var(--accent);
  border: 0;
  border-radius: var(--radius-md);
  color: var(--text-on-accent);
  font-family: var(--font-sans);
  font-size: 17px;
  font-weight: 700;
  padding: 14px 44px;
  cursor: pointer;
  box-shadow: 0 4px 18px var(--accent-glow);
  transition: transform var(--transition-fast), box-shadow var(--transition-fast);
}
.cc-join-btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 28px var(--accent-glow);
}

.cc-gate-note {
  margin-top: var(--space-md);
  font-size: 13px;
  color: var(--text-faint);
}
.cc-gate-note a { color: var(--accent-on-light); }

/* ------------------------------------------- the benefits door (Aug 2026) --
   Benefits is the ad-landing page and the storefront strip's signed-out
   destination, so its door asks WHO is looking and shows one of three:
   stranger → "Already a student?" · customer → "Enter the community" ·
   signed in but not a customer yet → the store, plus a way out if they are
   on the wrong email. routes_members.benefits() has the full reasoning.

   The button was an anchor wearing a button's clothes with display and
   text-decoration bolted on as inline style="": no focus ring, no pressed
   state, and 44px of side padding that turned "Log in with your student
   email" into an oversized pill on a phone.

   Scoped `.cc-door .cc-join-btn` on purpose — .cc-join-btn is ALSO the
   welcome page's "I'm in" button and the setup form's submit. Those must not
   move. The extra class is what keeps this restyle off them, and it wins on
   specificity (0,2,0 vs 0,1,0) rather than on source order. */

.cc-door {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-sm);
  margin-top: var(--space-xl);
  padding-top: var(--space-lg);
  border-top: 1px solid var(--border-subtle);
}

/* "Already a student?" / "You're signed in as…" — a label, so it reads as
   one: quieter than body copy, but not the near-invisible --text-faint
   .cc-gate-note uses. */
.cc-door-line {
  margin: 0;
  font-size: 14px;
  color: var(--text-muted);
  line-height: 1.5;
}
.cc-door-line b {
  color: var(--text-primary);
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 600;
  overflow-wrap: anywhere;   /* long addresses must not widen the card */
}

/* The sentence that tells a non-qualifying visitor where they stand. Body
   copy, not a label — it is the answer they came for. */
.cc-door-say {
  margin: 0;
  max-width: 34ch;
  font-size: 15px;
  line-height: 1.55;
  color: var(--text-primary);
}

/* ⚠️ color MUST be declared HERE, and :visited MUST be restated.
   tokens.css ships `a:visited { color: var(--accent-on-light) }` — one class
   + one element. The base `.cc-join-btn { color: ... }` is one class and
   LOSES to it, so a door that only overrides the BACKGROUND inherits gold
   text from the visited rule: gold-on-gold for anyone who has actually been
   to the community, correct black in incognito. Shipped exactly that way on
   Aug 4 and Marc caught it on the live page. Winning the selector-rank fight
   is not enough — the winning rule has to actually DECLARE the property. */
.cc-door .cc-join-btn,
.cc-door .cc-join-btn:visited {
  display: inline-flex;        /* was inline style="" */
  align-items: center;
  justify-content: center;
  gap: 10px;
  color: var(--text-on-accent);
  text-decoration: none;       /* was inline style="" */
  margin-top: var(--space-xs);
  padding: 15px 34px;
  max-width: 100%;
  /* Depth instead of a flat slab. --accent-bright is already theme-aware
     (it saturates on light rather than lightening), so this reads right in
     both without a second rule. */
  background: linear-gradient(160deg, var(--accent-bright) 0%, var(--accent) 100%);
  border-radius: 10px;
  font-size: 16px;
  letter-spacing: 0.01em;
  line-height: 1.25;
  text-align: center;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.16), 0 6px 22px var(--accent-glow);
  transition: transform var(--transition-fast),
              box-shadow var(--transition-fast),
              filter var(--transition-fast);
}

/* The arrow is the affordance the flat label was missing — it says "this
   goes somewhere" before you read the words. */
.cc-door .cc-join-btn::after {
  content: '\2192';
  font-size: 17px;
  line-height: 1;
  transition: transform var(--transition-fast);
}

.cc-door .cc-join-btn:hover {
  color: var(--text-on-accent);
  text-decoration: none;
  transform: translateY(-2px);
  filter: brightness(1.05);
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.18), 0 12px 34px var(--accent-glow);
}
.cc-door .cc-join-btn:hover::after { transform: translateX(4px); }

/* It is a button — it must feel pressed. The old one did nothing on click. */
.cc-door .cc-join-btn:active {
  transform: translateY(0);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2), 0 3px 12px var(--accent-glow);
}

/* Keyboard users got nothing before: the global link outline is invisible
   against a gold fill. */
.cc-door .cc-join-btn:focus-visible {
  outline: 3px solid var(--text-primary);
  outline-offset: 3px;
}

/* Customers routinely hold several addresses (the merge engine exists for
   exactly this). Without this line, someone signed in on the wrong one reads
   "you are not a customer" with nowhere to go. */
.cc-door-alt {
  margin: var(--space-xs) 0 0;
  font-size: 13px;
  color: var(--text-faint);
  line-height: 1.5;
}
.cc-door-alt a {
  color: var(--accent-on-light);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.cc-door-alt a:hover { color: var(--accent-bright); }

@media (max-width: 720px) {
  .cc-door { margin-top: var(--space-lg); gap: 10px; }
  /* Full width on a phone — a centred pill with 34px of side padding wraps
     awkwardly at "Log in with your student email". */
  .cc-door .cc-join-btn { width: 100%; padding: 15px 20px; font-size: 15px; }
  .cc-door-say { font-size: 14.5px; }
}

@media (prefers-reduced-motion: reduce) {
  .cc-door .cc-join-btn,
  .cc-door .cc-join-btn::after { transition: none; }
  .cc-door .cc-join-btn:hover,
  .cc-door .cc-join-btn:hover::after { transform: none; }
}

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

@media (max-width: 720px) {
  .cc-shell { padding: var(--space-md) var(--space-md) var(--space-2xl); }
  .cc-nav-inner { padding: var(--space-md); }
  .cc-nav-scope { display: none; }
  /* S22 (Marc's call): on a phone the sort button drops to its OWN line,
     right-aligned, so the area chips get the entire screen width to wrap
     into. Borrowed from the left-rail option — the one idea worth keeping
     from it without paying for the rail. */
  .cc-feedbar { flex-direction: column; align-items: stretch; gap: var(--space-sm); }
  .cc-sortmenu { align-self: flex-end; }
  /* The area chips cost the least screen they can on a phone: tighter
     type, padding and gaps (Marc's Jul 30 call — the row was eating half
     the viewport once the leaked tip text was hidden again). */
  .cc-areas { gap: 6px; }
  .cc-area-chip { font-size: 12px; padding: 4px 11px; }
  .cc-area-chip .n { font-size: 10px; margin-left: 3px; }
  .cc-post { padding: var(--space-md); }
  .cc-post-title { font-size: 21px; }
  .cc-thumbs img, .cc-thumbs .more { width: 60px; height: 60px; }
}

@media (prefers-reduced-motion: reduce) {
  .cc-btn-gold:hover, .cc-join-btn:hover { transform: none; }
  .cc-card, .cc-btn, .cc-tb, .cc-area-chip, .cc-nav-link { transition: none; }
}

/* ------------------------------------------------- post detail modal -- */
/* Feed cards open posts in a dialog over the feed; the URL pushState's to
   the post permalink (shareable), and a direct URL load renders the full
   post page instead. Marc's S4 pause call — Skool's own pattern. */

.cc-modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 1000;
  background: rgba(5, 7, 11, 0.62);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 5vh 16px;
  overflow-y: auto;
}
.cc-modal-backdrop[hidden] { display: none; }

.cc-modal {
  position: relative;
  width: 100%;
  max-width: 720px;
  margin-bottom: 5vh;
}
.cc-modal .cc-post { box-shadow: var(--shadow-elevated); }

.cc-modal-close {
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 2;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 1px solid var(--border-subtle);
  background: var(--bg-panel);
  color: var(--text-muted);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  transition: color var(--transition-fast);
}
.cc-modal-close:hover { color: var(--text-primary); }

/* iOS needs the body truly FIXED (overflow:hidden isn't enough on iPhone —
   S10, Fede's pass). feed.js sets the negative top to the saved scroll
   offset on open and restores the scroll position on close. */
body.cc-modal-open {
  position: fixed;
  left: 0;
  right: 0;
  width: 100%;
  overflow-y: scroll;
}

/* ----------------------------------------------------------- comments -- */

.cc-author-link,
.cc-comment-author {
  color: var(--text-primary);
  text-decoration: none;
  font-weight: 600;
}
.cc-author-link:hover, .cc-comment-author:hover { color: var(--accent-on-light); }
a.cc-avatar { text-decoration: none; }

.cc-comments {
  margin-top: var(--space-lg);
  padding-top: var(--space-md);
  border-top: 1px solid var(--border-faint);
}

.cc-comment-form {
  display: flex;
  gap: var(--space-sm);
  align-items: flex-end;
  margin-bottom: var(--space-md);
}
.cc-comment-input {
  flex: 1;
  background: var(--bg-input);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: 14.5px;
  line-height: 1.5;
  padding: 9px 12px;
  resize: vertical;
  min-height: 42px;
}
.cc-comment-input::placeholder { color: var(--text-faint); }
.cc-comment-input:focus { border-color: var(--accent); outline: none; }
.cc-comment-form .cc-btn-gold { margin-left: 0; }

/* The box breathes (Marc, Jul 2026 — the reply case). It OPENS at three
   lines instead of two, grows with what you write, and STOPS: past the
   ceiling it scrolls inside itself so the comment you are answering never
   gets pushed off screen. That last part IS the feature — the complaint was
   losing sight of what sat above, and an unbounded box would have made it
   worse, not better.
   CSS owns all three numbers. post.js only ever says "be as tall as your
   content" and lets min/max-height clamp it, so a phone and the live-chat
   rail get their own ceilings (below) without the script ever learning that
   a breakpoint exists.
   Scoped to .cc-comment-form ON PURPOSE: the report dialog's note textarea
   wears .cc-comment-input too but has no form around it, so it keeps the
   42px drag-handle box it shipped with, untouched.
   resize is off because a hand-dragged height and a self-sizing one fight
   over the same property — the growth replaces the grabber. */
.cc-comment-form .cc-comment-input {
  min-height: 88px;      /* 3 lines — how it opens */
  max-height: 194px;     /* 8 lines — the ceiling, then it scrolls inside */
  resize: none;
  overflow-y: auto;
}

/* A phone has less room to lose, so the ceiling drops one more line and the
   comment being answered stays on screen above the box. This sits HERE, next
   to the rule it modifies, rather than in the shared 720px block further up:
   media queries carry no specificity, so from up there it would lose to the
   194px above it on source order alone. */
@media (max-width: 720px) {
  .cc-comment-form .cc-comment-input { max-height: 172px; }
}

.cc-comment-error { color: var(--danger); font-size: 13px; min-height: 1em; margin-bottom: var(--space-sm); }

.cc-comment { margin-top: var(--space-md); }

.cc-comment-head {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
}
.cc-comment-author { font-size: 14px; }
.cc-comment-time {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-faint);
}

.cc-comment-body { margin: 6px 0 0 38px; }
.cc-comment-body.cc-richtext { font-size: 14.5px; margin-top: 6px; margin-left: 38px; }
.cc-comment-body.cc-richtext p:last-child { margin-bottom: 0; }
.cc-comment-removed {
  color: var(--text-faint);
  font-style: italic;
  font-size: 14px;
}

.cc-comment-foot {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  margin: 6px 0 0 38px;
}

.cc-like-btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: transparent;
  border: 0;
  padding: 2px 4px;
  color: var(--text-faint);
  font-family: var(--font-mono);
  font-size: 12px;
  cursor: pointer;
  transition: color var(--transition-fast);
}
.cc-like-btn svg { width: 15px; height: 15px; }
.cc-like-btn:hover { color: var(--accent-on-light); }
.cc-like-btn.liked { color: var(--accent-on-light); }
.cc-like-btn.liked svg { fill: var(--accent); stroke: var(--accent); }

.cc-reply-btn {
  background: transparent;
  border: 0;
  padding: 2px 4px;
  color: var(--text-faint);
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  transition: color var(--transition-fast);
}
.cc-reply-btn:hover { color: var(--text-primary); }

.cc-comment-likes-static {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-faint);
}

.cc-reply-slot { margin: var(--space-sm) 0 0 38px; }
.cc-reply-slot .cc-comment-form { margin-bottom: 0; }

.cc-replies {
  margin-left: 18px;
  padding-left: var(--space-md);
  border-left: 2px solid var(--border-faint);
}
.cc-replies.flat { margin-left: 0; padding-left: 0; border-left: 0; }

.cc-no-comments { color: var(--text-faint); font-size: 14px; }

/* ------------------------------------------------------------ profile -- */

.cc-avatar.lg { width: 64px; height: 64px; flex-basis: 64px; font-size: 20px; }

.cc-profile-head {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  padding: var(--space-lg);
  margin-bottom: var(--space-lg);
}
.cc-profile-name {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 22px;
  font-weight: 700;
  margin: 0 0 6px;
}
.cc-profile-stats {
  display: flex;
  gap: var(--space-md);
  flex-wrap: wrap;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-muted);
}

.cc-profile-section { margin-bottom: var(--space-lg); }
.cc-profile-heading {
  font-size: 15px;
  font-weight: 700;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin: 0 0 var(--space-sm);
}
.cc-profile-item {
  display: block;
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
  padding: 12px 14px;
  margin-bottom: var(--space-sm);
  text-decoration: none;
  transition: box-shadow var(--transition-fast);
}
.cc-profile-item:hover { box-shadow: var(--shadow-card); }
.cc-profile-item-title {
  display: block;
  color: var(--text-primary);
  font-weight: 600;
  font-size: 15px;
}
.cc-profile-item-excerpt {
  display: block;
  color: var(--text-body);
  font-size: 14px;
}
.cc-profile-item-meta {
  display: block;
  margin-top: 3px;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-faint);
}

/* ===================================================================
   Session 5 — card footer (commenter avatars + New/Last indicator),
   full-card click, report dialog, edit affordances, moderation bits.
   =================================================================== */

/* Whole card opens the post (feed.js) — signal it. */
.cc-card[data-href] { cursor: pointer; }
.cc-card[data-href]:hover .cc-card-title { color: var(--accent-on-light); }

/* Commenter avatar stack — 22px circles, overlapped, card-colored ring.
   Deterministic identity tints (member id % 6) keep a stack of initials
   from reading as identical grey coins; muted alphas work on both themes. */
.cc-foot-commenters {
  display: inline-flex;
  align-items: center;
  padding-left: 4px;
}
.cc-avatar.xs {
  width: 22px;
  height: 22px;
  flex: 0 0 22px;
  font-size: 9px;
  font-weight: 700;
  margin-left: -7px;
  border: 2px solid var(--bg-card);
  color: var(--text-primary);
  position: relative;
}
.cc-avatar.xs:first-child { margin-left: 0; }
.cc-avatar.hue-0 { background: hsla(210, 60%, 52%, 0.22); }
.cc-avatar.hue-1 { background: hsla(150, 45%, 45%, 0.22); }
.cc-avatar.hue-2 { background: hsla(35, 75%, 52%, 0.22); }
.cc-avatar.hue-3 { background: hsla(280, 45%, 58%, 0.22); }
.cc-avatar.hue-4 { background: hsla(0, 60%, 56%, 0.20); }
.cc-avatar.hue-5 { background: hsla(180, 45%, 45%, 0.22); }

/* "New comment 2h" (unseen — blue, bold) vs "Last comment Apr '24" (grey). */
.cc-foot-activity {
  font-family: var(--font-mono);
  font-size: 12px;
  white-space: nowrap;
}
.cc-foot-activity.new { color: var(--info); font-weight: 700; }
.cc-foot-activity.last { color: var(--text-faint); }

/* "(edited)" stamp — quiet, mono, next to the timestamp. */
.cc-edited {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-faint);
  font-style: normal;
}

/* Quiet text actions: Edit / Delete / Report. */
.cc-quiet-btn {
  background: transparent;
  border: 0;
  padding: 2px 4px;
  color: var(--text-faint);
  font-family: var(--font-sans);
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  transition: color var(--transition-fast);
}
.cc-quiet-btn:hover { color: var(--text-primary); }
.cc-quiet-btn.danger:hover { color: var(--danger); }

.cc-foot-actions {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: var(--space-sm);
}

/* Report dialog — sits ABOVE the post modal (z 1000). */
.cc-report-backdrop {
  position: fixed;
  inset: 0;
  z-index: 1100;
  background: rgba(5, 7, 11, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}
.cc-report-backdrop[hidden] { display: none; }

.cc-report-dialog {
  width: 100%;
  max-width: 420px;
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-elevated);
  padding: var(--space-lg);
}
.cc-report-title { font-size: 18px; font-weight: 700; margin: 0 0 4px; color: var(--text-primary); }
.cc-report-sub { font-size: 13.5px; color: var(--text-muted); margin: 0 0 var(--space-md); }

.cc-report-options {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  margin-bottom: var(--space-sm);
}
.cc-report-option {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
  font-size: 14px;
  color: var(--text-body);
  cursor: pointer;
  transition: border-color var(--transition-fast);
}
.cc-report-option:hover { border-color: var(--border-strong); }
.cc-report-option:has(input:checked) {
  border-color: var(--accent);
  background: var(--accent-glow);
}
.cc-report-option input { accent-color: var(--accent); }

.cc-report-error { color: var(--danger); font-size: 13px; min-height: 1em; margin-top: var(--space-xs); }
.cc-report-foot {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-sm);
  margin-top: var(--space-md);
}
.cc-report-thanks { font-size: 14.5px; color: var(--text-body); }

/* Post edit-in-place form. */
.cc-post-edit-form { margin-top: var(--space-md); }
.cc-post-edit-form .cc-input-title { margin-bottom: var(--space-sm); }

/* Comment edit form: stack under the hidden body, aligned with it. */
.cc-comment-edit-form { margin: 6px 0 0 38px; flex-wrap: wrap; }

/* ===================================================================
   Session 6 — composer "Music feedback" mode + waveform attach strip.
   The strip is ONE element carrying four states (empty / uploading /
   done / error); bars are an SVG mask tinted by theme tokens.
   =================================================================== */

.cc-composer-mode {
  display: flex;
  gap: 2px;
  background: var(--bg-panel);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-pill);
  padding: 3px;
  width: max-content;
  margin-bottom: var(--space-sm);
}
.cc-mode-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-sans);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-muted);
  background: transparent;
  border: 0;
  border-radius: var(--radius-pill);
  padding: 5px 14px;
  cursor: pointer;
  transition: color var(--transition-fast);
}
.cc-mode-btn:hover { color: var(--text-primary); }
.cc-mode-btn.active {
  background: var(--bg-card);
  color: var(--accent-on-light);
  box-shadow: var(--shadow-card);
}

/* Feedback mode: quiet accent rail (same vocabulary as blockquote). */
.cc-composer.feedback { border-left: 2px solid var(--accent); }

.cc-audio-strip {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: center;
  gap: var(--space-md);
  min-height: 64px;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-sm);
  padding: 12px 16px;
  margin-bottom: var(--space-sm);
  cursor: pointer;
  transition: border-color var(--transition-fast);
}
.cc-audio-strip:hover,
.cc-audio-strip.drag { border-color: var(--accent); }
.cc-audio-strip[data-state="uploading"],
.cc-audio-strip[data-state="done"] { cursor: default; border-style: solid; }
.cc-audio-strip[data-state="error"] { border-color: var(--danger); }

.cc-audio-bars {
  position: absolute;
  inset: 10px 14px;
  background: var(--text-faint);
  opacity: 0.3;
  pointer-events: none;
  -webkit-mask: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20120%2040'%3E%3Crect%20x='0'%20y='16'%20width='3'%20height='8'%20rx='1'/%3E%3Crect%20x='6'%20y='13'%20width='3'%20height='14'%20rx='1'/%3E%3Crect%20x='12'%20y='9'%20width='3'%20height='22'%20rx='1'/%3E%3Crect%20x='18'%20y='5'%20width='3'%20height='30'%20rx='1'/%3E%3Crect%20x='24'%20y='2'%20width='3'%20height='36'%20rx='1'/%3E%3Crect%20x='30'%20y='6'%20width='3'%20height='28'%20rx='1'/%3E%3Crect%20x='36'%20y='11'%20width='3'%20height='18'%20rx='1'/%3E%3Crect%20x='42'%20y='14'%20width='3'%20height='12'%20rx='1'/%3E%3Crect%20x='48'%20y='10'%20width='3'%20height='20'%20rx='1'/%3E%3Crect%20x='54'%20y='4'%20width='3'%20height='32'%20rx='1'/%3E%3Crect%20x='60'%20y='1'%20width='3'%20height='38'%20rx='1'/%3E%3Crect%20x='66'%20y='5'%20width='3'%20height='30'%20rx='1'/%3E%3Crect%20x='72'%20y='9'%20width='3'%20height='22'%20rx='1'/%3E%3Crect%20x='78'%20y='13'%20width='3'%20height='14'%20rx='1'/%3E%3Crect%20x='84'%20y='15'%20width='3'%20height='10'%20rx='1'/%3E%3Crect%20x='90'%20y='12'%20width='3'%20height='16'%20rx='1'/%3E%3Crect%20x='96'%20y='7'%20width='3'%20height='26'%20rx='1'/%3E%3Crect%20x='102'%20y='3'%20width='3'%20height='34'%20rx='1'/%3E%3Crect%20x='108'%20y='8'%20width='3'%20height='24'%20rx='1'/%3E%3Crect%20x='114'%20y='14'%20width='3'%20height='12'%20rx='1'/%3E%3C/svg%3E") repeat-x left center;
          mask: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20120%2040'%3E%3Crect%20x='0'%20y='16'%20width='3'%20height='8'%20rx='1'/%3E%3Crect%20x='6'%20y='13'%20width='3'%20height='14'%20rx='1'/%3E%3Crect%20x='12'%20y='9'%20width='3'%20height='22'%20rx='1'/%3E%3Crect%20x='18'%20y='5'%20width='3'%20height='30'%20rx='1'/%3E%3Crect%20x='24'%20y='2'%20width='3'%20height='36'%20rx='1'/%3E%3Crect%20x='30'%20y='6'%20width='3'%20height='28'%20rx='1'/%3E%3Crect%20x='36'%20y='11'%20width='3'%20height='18'%20rx='1'/%3E%3Crect%20x='42'%20y='14'%20width='3'%20height='12'%20rx='1'/%3E%3Crect%20x='48'%20y='10'%20width='3'%20height='20'%20rx='1'/%3E%3Crect%20x='54'%20y='4'%20width='3'%20height='32'%20rx='1'/%3E%3Crect%20x='60'%20y='1'%20width='3'%20height='38'%20rx='1'/%3E%3Crect%20x='66'%20y='5'%20width='3'%20height='30'%20rx='1'/%3E%3Crect%20x='72'%20y='9'%20width='3'%20height='22'%20rx='1'/%3E%3Crect%20x='78'%20y='13'%20width='3'%20height='14'%20rx='1'/%3E%3Crect%20x='84'%20y='15'%20width='3'%20height='10'%20rx='1'/%3E%3Crect%20x='90'%20y='12'%20width='3'%20height='16'%20rx='1'/%3E%3Crect%20x='96'%20y='7'%20width='3'%20height='26'%20rx='1'/%3E%3Crect%20x='102'%20y='3'%20width='3'%20height='34'%20rx='1'/%3E%3Crect%20x='108'%20y='8'%20width='3'%20height='24'%20rx='1'/%3E%3C/svg%3E") repeat-x left center;
}
.cc-audio-strip[data-state="done"] .cc-audio-bars {
  background: var(--accent);
  opacity: 0.55;
}

.cc-audio-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0%;
  background: var(--accent-glow);
  pointer-events: none;
  transition: width 0.2s linear;
}

.cc-audio-face {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.cc-audio-main {
  font-weight: 600;
  font-size: 14.5px;
  color: var(--text-body);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cc-audio-strip[data-state="empty"] .cc-audio-main { color: var(--text-muted); }
.cc-audio-strip[data-state="error"] .cc-audio-main { color: var(--danger); }
.cc-audio-strip[data-state="done"] .cc-audio-main::before {
  content: '✓ ';
  color: var(--accent-on-light);
}
.cc-audio-sub {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-faint);
}
.cc-audio-remove { position: relative; margin-left: auto; flex: 0 0 auto; }

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

/* Player-side states of the same strip (post detail, 2.1 interim). */
.cc-player-strip {
  cursor: default;
  margin: var(--space-md) 0 0;
}
.cc-player-strip[data-state="processing"] .cc-audio-bars {
  animation: cc-bars-breathe 2.2s ease-in-out infinite;
}
@keyframes cc-bars-breathe {
  0%, 100% { opacity: 0.18; }
  50% { opacity: 0.38; }
}
@media (prefers-reduced-motion: reduce) {
  .cc-player-strip[data-state="processing"] .cc-audio-bars { animation: none; }
}

.cc-player { margin: var(--space-md) 0 0; }
.cc-audio-native { width: 100%; }

/* Audio chip on feed cards: mono status voice, accent when playable. */
.cc-card-track {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 12px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--accent-on-light);
  background: var(--accent-glow);
  border-radius: var(--radius-pill);
  padding: 4px 12px;
}
.cc-card-track.processing { color: var(--text-muted); background: var(--bg-panel); }
.cc-card-track.failed { color: var(--danger); background: var(--danger-bg); }

/* ===================================================================
   Session 6 — Phase 2.2 feedback player (§6.3): waveform, controls,
   pins, light-up, "at this moment" chip, scrollable comments panel.
   =================================================================== */

.cc-player.initialized .cc-audio-native { display: none; }
.cc-player.wave-failed .cc-wave,
.cc-player.wave-failed .cc-player-controls { display: none; }
.cc-player:not(.initialized) .cc-player-controls { display: none; }

.cc-wave { min-height: 88px; }

.cc-player-controls {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  margin-top: 10px;
}
.cc-play-btn {
  width: 40px;
  height: 40px;
  flex: 0 0 auto;
  border: 0;
  border-radius: 50%;
  background: var(--accent);
  color: var(--text-on-accent);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: transform var(--transition-fast), box-shadow var(--transition-fast);
}
.cc-play-btn:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 14px var(--accent-glow);
}
.cc-play-btn .cc-ic-pause { display: none; }
.cc-player.playing .cc-ic-play { display: none; }
.cc-player.playing .cc-ic-pause { display: block; }

.cc-time {
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.cc-time-now { color: var(--accent-on-light); font-weight: 600; }
.cc-pin-count {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-faint);
}

/* A comment's "play from here" chip. */
.cc-comment-ts {
  background: var(--accent-glow);
  border: 0;
  border-radius: var(--radius-pill);
  color: var(--accent-on-light);
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 600;
  padding: 2px 9px;
  cursor: pointer;
  transition: box-shadow var(--transition-fast);
}
.cc-comment-ts:hover { box-shadow: 0 0 0 1px var(--accent); }

/* "At this moment" chip on the comment box (freezes on focus; x removes). */
.cc-ts-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  align-self: center;
  flex: 0 0 auto;
  background: var(--accent-glow);
  border: 0;
  border-radius: var(--radius-pill);
  color: var(--accent-on-light);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  padding: 5px 10px;
  cursor: pointer;
  white-space: nowrap;
}
.cc-ts-chip-x { font-size: 13px; color: var(--text-muted); }
.cc-ts-chip:hover .cc-ts-chip-x { color: var(--danger); }

/* Comments panel on feedback posts (audio AND video): fixed height, internal
   scroll (§3.3 — the feed never endless-scrolls because of a thread). */
.cc-post-feedback .cc-thread {
  max-height: 400px;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding-right: 6px;
}

/* Light-up: a comment surfaces either as the playhead crosses its moment
   (§6.3 pins) or when a notification deep-links straight to it (Jul 2026).
   Only the node's own content tints — replies stay quiet (.cc-comment-own).
   The base rule carries the soft edge and the fade to EVERY post kind now,
   because the deep-link reaches text, image and poll threads too. Both
   properties are invisible until .active paints a background, so nothing
   moves anywhere; the feedback thread keeps its extra padding on top. */
.cc-comment-own {
  border-radius: var(--radius-sm);
  transition: background 0.25s, box-shadow 0.25s;
}
.cc-post-feedback .cc-comment-own {
  border-radius: var(--radius-sm);
  padding: 6px 8px 8px;
  margin-left: -8px;
  transition: background 0.25s, box-shadow 0.25s;
}
.cc-comment.active > .cc-comment-own {
  background: var(--accent-glow);
  box-shadow: 0 0 0 1px var(--accent);
}

@media (max-width: 720px) {
  .cc-post-feedback .cc-thread { max-height: 320px; }
}

/* ===================================================================
   Session 7 — video feedback: the cinema frame over the pins ribbon.
   The <video> keeps native controls (transport + fullscreen); the
   waveform demotes to a 48px comment timeline underneath. True black
   behind the frame is deliberate — letterboxing, both themes.
   =================================================================== */

.cc-video-native {
  display: block;
  width: 100%;
  max-height: 62vh;
  background: #000;
  border-radius: var(--radius-sm);
}

.cc-player[data-kind="video"] .cc-wave {
  min-height: 48px;
  margin-top: 10px;
  cursor: pointer;
}
.cc-player[data-kind="video"] .cc-player-controls { margin-top: 4px; }
.cc-player[data-kind="video"] .cc-pin-count { margin-left: 0; }

/* Feed-card poster for video feedback posts: quiet frame, play hint. */
.cc-card-poster {
  position: relative;
  display: block;
  margin-top: 12px;
  border-radius: var(--radius-sm);
  overflow: hidden;
  border: 1px solid var(--border-subtle);
  background: #000;
  max-width: 340px;
}
.cc-card-poster img {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}
.cc-card-poster-play {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
}
.cc-card-poster-play svg {
  width: 40px;
  height: 40px;
  padding: 11px 9px 11px 13px;
  border-radius: 50%;
  background: rgba(5, 7, 11, 0.55);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
}

/* Attached video on a regular/poll post — inline playback, no ribbon. */
.cc-attach-video { margin-top: var(--space-md); }

/* The Video / Add poll composer affordances are buttons wearing the
   attach-label look — neutralize the UA button chrome. */
button.cc-attach-label {
  background: transparent;
  font-family: var(--font-sans);
}

/* ===================================================================
   Session 7 — polls: options as quiet rows; once results are visible
   each row carries its share as an accent-glow fill (--pct). The mono
   meta line is the status voice. Editor = dashed panel in the composer.
   =================================================================== */

.cc-poll {
  margin-top: var(--space-md);
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}
.cc-poll-option {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  width: 100%;
  text-align: left;
  background: var(--bg-input);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
  padding: 10px 14px;
  font-family: var(--font-sans);
  font-size: 14.5px;
  color: var(--text-body);
  cursor: pointer;
  transition: border-color var(--transition-fast);
}
.cc-poll-option:hover:not(:disabled) { border-color: var(--accent); }
.cc-poll-option:disabled { cursor: default; }
.cc-poll-option.results::before {
  content: '';
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--pct, 0%);
  background: var(--accent-glow);
  pointer-events: none;
  transition: width 0.35s ease;
}
.cc-poll-option.voted { border-color: var(--accent); }
.cc-poll-option.voted .cc-poll-label {
  color: var(--accent-on-light);
  font-weight: 600;
}
.cc-poll-label {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
}
.cc-poll-count {
  position: relative;
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--text-muted);
  white-space: nowrap;
}
.cc-poll-meta {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-faint);
  margin-top: 4px;
}

/* Poll editor inside the Regular composer form. */
.cc-poll-editor {
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-sm);
  padding: 12px 14px;
  margin-bottom: var(--space-sm);
}
.cc-poll-editor-head {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  margin-bottom: var(--space-sm);
}
.cc-poll-editor-title {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent-on-light);
}
.cc-poll-multi-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--text-muted);
  cursor: pointer;
}
.cc-poll-multi-label input { accent-color: var(--accent); }
.cc-poll-editor-head .danger { margin-left: auto; }
.cc-poll-opt-input {
  width: 100%;
  background: var(--bg-input);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: 14px;
  padding: 8px 11px;
  margin-bottom: 6px;
}
.cc-poll-opt-input::placeholder { color: var(--text-faint); }
.cc-poll-opt-input:focus { border-color: var(--accent); outline: none; }

@media (prefers-reduced-motion: reduce) {
  .cc-poll-option.results::before { transition: none; }
}

/* ===================================================================
   Session 8 — the status layer (§6.5) + notification bell (§6.7).
   Status speaks JetBrains Mono, as established: rank numerals, point
   deltas, unread counts. The signature is the board rank column —
   the one place the mono voice gets loud. Everything else stays in
   the quiet card vocabulary.
   =================================================================== */

/* ------------------------------------------------------------ bell -- */

.cc-bell { position: relative; }

.cc-bell-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  background: transparent;
  border: 0;
  border-radius: 50%;
  color: var(--text-muted);
  cursor: pointer;
  transition: color var(--transition-fast);
}
.cc-bell-btn:hover { color: var(--accent-on-light); }
.cc-bell-btn[aria-expanded="true"] { color: var(--accent-on-light); }

.cc-bell-badge {
  position: absolute;
  top: 1px;
  right: 0;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: var(--radius-pill);
  background: var(--accent);
  color: var(--text-on-accent);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
}

.cc-bell-drop {
  position: absolute;
  top: calc(100% + 10px);
  right: 0;
  z-index: 1200;
  width: min(360px, calc(100vw - 24px));
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-elevated);
  overflow: hidden;
}
.cc-bell-drop[hidden] { display: none; }

.cc-bell-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border-faint);
}
.cc-bell-heading {
  font-size: 13.5px;
  font-weight: 700;
  color: var(--text-primary);
}

.cc-bell-list {
  max-height: 420px;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.cc-bell-item {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 11px 14px 11px 12px;
  border-left: 2px solid transparent;
  border-top: 1px solid var(--border-faint);
  text-decoration: none;
  transition: background var(--transition-fast);
}
.cc-bell-item:first-child { border-top: 0; }
.cc-bell-item:hover { background: var(--bg-panel); }
.cc-bell-item.unread {
  border-left-color: var(--accent);
  background: var(--accent-glow);
}
.cc-bell-item .cc-avatar.xs { margin-left: 0; margin-top: 1px; }

.cc-bell-text {
  flex: 1;
  min-width: 0;
  font-size: 13.5px;
  line-height: 1.45;
  color: var(--text-body);
}
.cc-bell-text strong { color: var(--text-primary); font-weight: 600; }
.cc-bell-title {
  display: block;
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cc-bell-excerpt {
  display: block;
  color: var(--text-faint);
  font-size: 12.5px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cc-bell-time {
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--text-faint);
  white-space: nowrap;
  margin-top: 2px;
}

.cc-bell-empty {
  padding: var(--space-lg);
  font-size: 13.5px;
  color: var(--text-muted);
  text-align: center;
}

/* ----------------------------------------------------- leaderboards -- */

.cc-boards-title {
  font-size: 26px;
  font-weight: 700;
  color: var(--text-primary);
  margin: 0 0 4px;
}
.cc-boards-sub {
  color: var(--text-muted);
  font-size: 14.5px;
  margin: 0 0 var(--space-lg);
}

.cc-standing {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  flex-wrap: wrap;
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  padding: var(--space-lg);
  margin-bottom: var(--space-lg);
}
.cc-standing-main { flex: 1; min-width: 220px; }
.cc-standing-name {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 17px;
  font-weight: 700;
  color: var(--text-primary);
}
.cc-standing-points {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-muted);
  margin-top: 3px;
}
.cc-standing-meter {
  margin-top: 10px;
  height: 3px;
  border-radius: var(--radius-pill);
  background: var(--border-faint);
  overflow: hidden;
}
.cc-standing-fill {
  display: block;
  height: 100%;
  background: var(--accent);
  border-radius: var(--radius-pill);
}
.cc-standing-ranks {
  display: flex;
  gap: var(--space-lg);
}
.cc-standing-rank {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-family: var(--font-mono);
  font-size: 15px;
  font-weight: 600;
  color: var(--text-primary);
}
.cc-standing-rank em {
  font-style: normal;
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.cc-boards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-md);
  align-items: start;
}

.cc-board {
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  padding: 14px 16px;
}
.cc-board-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--border-faint);
}
.cc-board-title {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent-on-light);
}
.cc-board-sub {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-faint);
}

.cc-board-rows {
  list-style: none;
  margin: 0;
  padding: 0;
}
.cc-board-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 6px;
  border-top: 1px solid var(--border-faint);
  border-radius: var(--radius-sm);
}
.cc-board-row:first-child { border-top: 0; }
.cc-board-row.first { background: var(--accent-glow); }

/* The signature: rank numerals in the status voice — loud for the podium. */
.cc-board-rank {
  flex: 0 0 26px;
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 600;
  color: var(--text-faint);
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.cc-board-rank.top {
  font-size: 19px;
  font-weight: 700;
  color: var(--accent-on-light);
}

.cc-board-name {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-primary);
  text-decoration: none;
  overflow: hidden;
}
.cc-board-name:hover { color: var(--accent-on-light); }

.cc-board-pts {
  font-family: var(--font-mono);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.cc-board-row.first .cc-board-pts { color: var(--accent-on-light); }

.cc-board-empty {
  padding: var(--space-md) 2px;
  font-size: 13.5px;
  color: var(--text-faint);
  margin: 0;
}

/* --------------------------------------------- profile activity graph -- */

.cc-activity-card {
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  padding: 14px 16px;
}
.cc-activity-total {
  font-size: 14px;
  color: var(--text-body);
  margin: 0 0 10px;
}
.cc-activity-total strong { color: var(--text-primary); }
.cc-activity-sub {
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--text-faint);
  margin-left: 6px;
}

.cc-activity-scroll { overflow-x: auto; padding-bottom: 4px; }
.cc-activity { width: max-content; }

.cc-activity-months {
  display: grid;
  margin-left: 30px; /* day-label gutter */
  font-family: var(--font-mono);
  font-size: 9.5px;
  color: var(--text-faint);
  margin-bottom: 4px;
}

.cc-activity-body { display: flex; gap: 4px; }

.cc-activity-days {
  display: grid;
  grid-template-rows: repeat(7, 11px);
  row-gap: 3px;
  width: 26px;
  font-family: var(--font-mono);
  font-size: 9px;
  color: var(--text-faint);
}
.cc-activity-days span { line-height: 11px; }
.cc-activity-days span:nth-child(1) { grid-row: 1; }
.cc-activity-days span:nth-child(2) { grid-row: 3; }
.cc-activity-days span:nth-child(3) { grid-row: 5; }

.cc-activity-grid {
  display: grid;
  grid-auto-flow: column;
  grid-template-rows: repeat(7, 11px);
  grid-auto-columns: 11px;
  gap: 3px;
}
.cc-cell {
  width: 11px;
  height: 11px;
  border-radius: 2px;
  background: var(--bg-panel);
  border: 1px solid var(--border-faint);
}
.cc-cell.future { visibility: hidden; }
/* Contribution ramp — the accent carrying the status story, both themes. */
.cc-cell.b1 { background: color-mix(in srgb, var(--accent) 28%, transparent); border-color: transparent; }
.cc-cell.b2 { background: color-mix(in srgb, var(--accent) 50%, transparent); border-color: transparent; }
.cc-cell.b3 { background: color-mix(in srgb, var(--accent) 74%, transparent); border-color: transparent; }
.cc-cell.b4 { background: var(--accent); border-color: transparent; }

/* ------------------------------------------------- S8 responsive bits -- */

@media (max-width: 720px) {
  .cc-boards { grid-template-columns: 1fr; }
  .cc-standing-ranks { width: 100%; justify-content: space-between; }
  /* S22: the `.cc-sort` pill-group rule that lived here is gone with the
     pills themselves — the S22 block above owns the phone arrangement now. */
}

/* ===================================================================
   Session 9 — email engine (§6.7): notification settings page +
   the admin broadcast checkbox. Settings rows reuse the accent-
   checkbox row vocabulary (report dialog / poll multi) — a row
   lights up when its cadence is on.
   =================================================================== */

.cc-settings-form { max-width: 620px; }

.cc-settings-email {
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--text-body);
}

.cc-pref-row {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 14px 16px;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
  background: var(--bg-card);
  cursor: pointer;
  margin-bottom: var(--space-sm);
  transition: border-color var(--transition-fast);
}
.cc-pref-row:hover { border-color: var(--border-strong); }
.cc-pref-row:has(input:checked) {
  border-color: var(--accent);
  background: var(--accent-glow);
}
.cc-pref-row input {
  accent-color: var(--accent);
  margin-top: 3px;
  flex: 0 0 auto;
}

.cc-pref-text { min-width: 0; }
.cc-pref-title {
  display: block;
  font-size: 15px;
  font-weight: 600;
  color: var(--text-primary);
}
.cc-pref-desc {
  display: block;
  font-size: 13.5px;
  color: var(--text-muted);
  margin-top: 2px;
  line-height: 1.5;
}

.cc-pref-presets {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  flex-wrap: wrap;
  margin-top: var(--space-md);
}
.cc-pref-presets-label {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.cc-pref-presets .cc-btn-gold { margin-left: auto; }

/* Composer: admin "Email all members" checkbox (72h cooldown state). */
.cc-broadcast-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  font-weight: 600;
  color: var(--accent-on-light);
  border: 1px dashed var(--accent);
  border-radius: var(--radius-sm);
  padding: 7px 12px;
  cursor: pointer;
  transition: border-color var(--transition-fast), color var(--transition-fast);
}
.cc-broadcast-label input { accent-color: var(--accent); }
.cc-broadcast-label.cooling {
  color: var(--text-faint);
  border-color: var(--border-strong);
  cursor: default;
  font-family: var(--font-mono);
  font-size: 11.5px;
  font-weight: 500;
}

@media (max-width: 720px) {
  .cc-pref-presets .cc-btn-gold { margin-left: 0; width: 100%; justify-content: center; }
}

/* ===================================================================
   Session 10 — Fede's real-iPhone pass: image lightbox + iOS scroll
   containment. Same quiet vocabulary — the viewer is a dark room,
   the image the only light.
   =================================================================== */

/* The page never pans sideways — vertical is the only axis (VID 2). */
html, body { overflow-x: hidden; overflow-x: clip; }

/* Post images invite the tap. */
.cc-post-images img { cursor: zoom-in; }

.cc-lightbox {
  position: fixed;
  inset: 0;
  z-index: 1300; /* above post modal (1000), report (1100), bell (1200) */
  background: rgba(5, 7, 11, 0.88);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  cursor: zoom-out;
}
.cc-lightbox[hidden] { display: none; }

.cc-lightbox-img {
  max-width: min(1400px, 94vw);
  max-height: 90vh;
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-elevated);
}

.cc-lightbox-close { position: fixed; top: 14px; right: 14px; }

/* The VID 2 root cause (measured): .cc-nav-links is ~426px — wider than a
   phone — so the document panned sideways, and clipping alone amputated
   the bell + theme toggle. On small screens the nav cluster wraps and
   tightens instead of overflowing; nothing ever pushes past the edge. */
@media (max-width: 720px) {
  .cc-nav-inner { flex-wrap: wrap; }
  .cc-nav-links {
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: var(--space-sm);
    row-gap: 4px;
  }
}

/* ==========================================================================
   S12 — Live classes (Phase 4.2). Scheduled-state surfaces only: the class
   header on the class post, the feed banner, the classes page. The player
   and live chat land in the same places at S13. Token-driven throughout.
   ========================================================================== */

.cc-class-head {
    border: 1px solid var(--border-subtle);
    border-left: 3px solid var(--accent);
    background: var(--bg-card);
    border-radius: var(--radius-sm);
    padding: var(--space-md);
    margin-bottom: var(--space-md);
}
.cc-class-eyebrow {
    display: inline-block;
    font-family: var(--font-mono);
    font-size: 0.7rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--accent-on-light);
    margin-bottom: var(--space-sm);
}
.cc-class-when-line {
    color: var(--text-primary);
    font-size: 1.05rem;
    font-weight: 600;
}
.cc-class-countdown {
    font-family: var(--font-mono);
    color: var(--accent-on-light);
    font-size: 0.85rem;
    margin-top: 2px;
}
.cc-class-teacher {
    color: var(--text-muted);
    font-size: 0.9rem;
    margin-top: 2px;
}
.cc-class-doors {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-sm);
    margin-top: var(--space-md);
}
.cc-class-doors a { text-decoration: none; }
.cc-class-note {
    color: var(--text-faint);
    font-size: 0.82rem;
    margin: var(--space-sm) 0 0;
}

/* Feed banner — one slim line for the next announced class (§3.5). */
.cc-class-banner {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-sm);
    border: 1px solid var(--border-subtle);
    border-left: 3px solid var(--accent);
    background: var(--bg-card);
    border-radius: var(--radius-sm);
    padding: var(--space-sm) var(--space-md);
    margin-bottom: var(--space-md);
    text-decoration: none;
    transition: box-shadow var(--transition-fast);
}
.cc-class-banner:hover { box-shadow: 0 0 0 3px var(--accent-glow); }
.cc-class-banner-eyebrow {
    font-family: var(--font-mono);
    font-size: 0.68rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--accent-on-light);
    white-space: nowrap;
}
.cc-class-banner-title {
    color: var(--text-primary);
    font-weight: 600;
    flex: 1 1 auto;
    min-width: 40%;
}
.cc-class-banner-when {
    color: var(--text-muted);
    font-family: var(--font-mono);
    font-size: 0.8rem;
    white-space: nowrap;
}
.cc-class-banner-cta {
    color: var(--accent-on-light);
    font-size: 0.85rem;
    white-space: nowrap;
}

/* Classes page — §6.8 calendar section. */
.cc-classes-header { margin-bottom: var(--space-lg); }
.cc-classes-title {
    color: var(--text-primary);
    font-size: 1.5rem;
    margin: 0 0 4px;
}
.cc-classes-sub {
    color: var(--text-muted);
    font-size: 0.92rem;
    margin: 0;
    max-width: 60ch;
}
.cc-classes-list {
    display: grid;
    gap: var(--space-sm);
}
.cc-class-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-md);
    border: 1px solid var(--border-subtle);
    background: var(--bg-card);
    border-radius: var(--radius-sm);
    padding: var(--space-md);
}
.cc-class-when {
    font-family: var(--font-mono);
    font-size: 0.82rem;
    color: var(--text-muted);
    flex: 0 0 170px;
}
.cc-class-main { flex: 1 1 240px; }
.cc-class-title {
    display: block;
    color: var(--text-primary);
    font-weight: 600;
    text-decoration: none;
}
.cc-class-title:hover { color: var(--accent-on-light); }
.cc-class-meta {
    color: var(--text-faint);
    font-size: 0.82rem;
    margin-top: 2px;
}
.cc-class-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-sm);
}
.cc-class-actions a { text-decoration: none; }

@media (max-width: 720px) {
    .cc-class-when { flex-basis: 100%; }
    .cc-class-actions { flex-basis: 100%; }
}

/* ==========================================================================
   S13 — the LIVE half (§6.8). One rule holds the whole section: red exists
   ONLY as the on-air signal (dot, LIVE word, live rails); everything else
   keeps the gold/mono vocabulary. The signature is the ON AIR strip under
   the player — a broadcast-desk status line in the community's mono voice:
   at the edge it reads ●LIVE; scrubbed back it becomes a timecode
   ("1:24 behind") with the gold GO LIVE snap. Broadcast-DVR, never a bare
   file player (Marc's FOX-sports rule, §4.12).
   ========================================================================== */

/* The on-air signal. */
.cc-live-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--danger);
    margin-right: 6px;
    vertical-align: 1px;
    animation: cc-live-pulse 1.6s ease-in-out infinite;
}
@keyframes cc-live-pulse {
    0%, 100% { opacity: 1; box-shadow: 0 0 0 0 var(--danger-bg); }
    50% { opacity: 0.55; box-shadow: 0 0 0 4px var(--danger-bg); }
}
@media (prefers-reduced-motion: reduce) {
    .cc-live-dot { animation: none; }
}

.cc-class-head.live { border-left-color: var(--danger); }
.cc-class-eyebrow.is-live { color: var(--danger); margin-bottom: var(--space-xs); }

/* Player frame: the letterbox vocabulary (§ S7 video), 16:9 while empty so
   the page doesn't jump when the picture arrives. */
.cc-live-player { margin-top: var(--space-sm); }
.cc-live-player video {
    aspect-ratio: 16 / 9;
    max-height: 62vh;
}
.cc-live-wait {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--space-md);
    padding: 10px 14px;
    margin-top: var(--space-xs);
}
.cc-live-wait .cc-audio-bars {
    inset: 6px 10px;
    animation: cc-bars-breathe 2.2s ease-in-out infinite;
}
.cc-live-wait .cc-audio-face { position: relative; }
@media (prefers-reduced-motion: reduce) {
    .cc-live-wait .cc-audio-bars { animation: none; }
}

/* THE ON AIR STRIP — mono status voice, one line. */
.cc-onair {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    margin-top: var(--space-xs);
    padding: 6px 2px;
    font-family: var(--font-mono);
    font-size: 12px;
}
.cc-onair-live {
    color: var(--danger);
    font-weight: 700;
    letter-spacing: 0.14em;
}
.cc-onair-behind {
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}
.cc-onair-behind::before {
    content: '● ';
    color: var(--text-faint);
}
.cc-onair .cc-golive {
    padding: 4px 14px;
    font-size: 12.5px;
    margin-left: 0;
}
.cc-onair-note {
    margin-left: auto;
    color: var(--text-faint);
    font-size: 10.5px;
}

/* Live chat mode: the comments section becomes the chat rail — thread on
   top (internal scroll, pinned to the newest message by live.js), the
   input at the bottom, rows compacted. Same engine, tighter clothes. */
.cc-class-live .cc-comments {
    display: flex;
    flex-direction: column;
}
.cc-class-live .cc-comments .cc-thread {
    order: 1;
    max-height: 380px;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding-right: 6px;
}
.cc-class-live .cc-comments .cc-comment-error { order: 2; margin: 6px 0 0; }
.cc-class-live .cc-comments .cc-comment-form {
    order: 3;
    margin: var(--space-sm) 0 0;
}
.cc-class-live .cc-comment { margin-top: var(--space-sm); }
.cc-class-live .cc-comment-body,
.cc-class-live .cc-comment-body.cc-richtext { margin-left: 30px; font-size: 14px; }
.cc-class-live .cc-comment-foot { margin: 2px 0 0 30px; gap: var(--space-sm); }
/* Live chat is a chat, not an essay field: the rail keeps the compact
   opening it shipped with (watch mode budgets the phone screen around that
   number), and its ceiling stays low so a long message can never push the
   thread off a fullscreen phone. Three classes deep so it outranks the
   .cc-comment-form sizing block no matter how this file is reordered. */
.cc-class-live .cc-comment-form .cc-comment-input {
  min-height: 38px;
  max-height: 120px;
}
.cc-chat-line .cc-comment-head .cc-avatar.xs { margin-left: 0; }

/* Feed banner + nav while a class is ON AIR. */
.cc-class-banner.is-live { border-left-color: var(--danger); }
.cc-class-banner.is-live .cc-class-banner-eyebrow { color: var(--danger); }
.cc-nav-live-dot {
    display: inline-block;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--danger);
    margin-left: 5px;
    vertical-align: 2px;
    animation: cc-live-pulse 1.6s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
    .cc-nav-live-dot { animation: none; }
}

@media (max-width: 720px) {
    .cc-onair { flex-wrap: wrap; row-gap: 6px; }
    .cc-onair-note { margin-left: 0; flex-basis: 100%; }
    .cc-class-live .cc-comments .cc-thread { max-height: 320px; }
}

/* ==========================================================================
   S14 — the REPLAY state (§6.8). The class block's state grammar completes:
   the gold rail returns (red belongs to live only), the eyebrow reads
   CLASS REPLAY over a mono who/when line, and the player is the community's
   one signature engine — the letterboxed video over the golden comment
   timeline. Deliberately no new visual atoms beyond the meta line.
   ========================================================================== */

.cc-class-replay-meta {
    font-family: var(--font-mono);
    font-size: 0.8rem;
    color: var(--text-muted);
    margin-top: 2px;
}

/* The ended-state strip now carries data-state="waiting": identical look to
   "processing", but outside player.js's media-poll selector — the flip to
   REPLAY is live.js's state poll swapping the fragment. */
.cc-player-strip[data-state="waiting"] .cc-audio-bars {
    animation: cc-bars-breathe 2.2s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
    .cc-player-strip[data-state="waiting"] .cc-audio-bars { animation: none; }
}

/* ==========================================================================
   S15 — the mini-summary under the replay (§6.9). Quiet block in the S9
   letter register: mono eyebrow, muted prose, no card chrome — it reads as
   part of the class head, not a widget. The notes link is the door to the
   public layer.
   ========================================================================== */

.cc-class-summary {
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid var(--border-subtle);
}

.cc-class-summary-eyebrow {
    display: block;
    font-family: var(--font-mono);
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--accent-on-light);
    margin-bottom: 6px;
}

.cc-class-summary-text {
    margin: 0 0 8px;
    font-size: 0.92rem;
    line-height: 1.65;
    color: var(--text-muted);
    max-width: 68ch;
}

/* ===================================================================
   Session 16 — heritage badges (§3.12/§6.6, Marc's gate picks). Two
   atoms only: QUIET PILLS (the .cc-lvl status family, one size up) on
   the profile row and hover card, and the ◆ EMBLEM — a gold notification
   bubble biting the avatar's lower-right edge wherever a badge-holder
   appears. Hover or keyboard focus opens the heritage card; on touch the
   avatar tap already leads to the profile, where the pills live. The
   emblem is the section's signature — everything else stays quiet.
   =================================================================== */

.cc-badge-pill {
  display: inline-flex;
  align-items: center;
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent-on-light);
  background: var(--accent-glow);
  border-radius: 4px;
  padding: 3px 8px;
  white-space: nowrap;
}

.cc-profile-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 10px;
}

/* The avatar mark — notification geometry: the bubble's center sits
   INSIDE the circle's 45° edge point, so it reads as ON the circle
   (Marc's artifact call), with a card-colored notch ring. */
.cc-heritage {
  position: relative;
  display: inline-flex;
  flex: 0 0 auto;
}
.cc-heritage .cc-avatar { position: relative; }
.cc-heritage-emblem {
  position: absolute;
  right: -2px;
  bottom: -2px;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--text-on-accent);
  border: 2px solid var(--bg-card);
  display: grid;
  place-items: center;
}
/* SVG diamond, not a text glyph — font metrics rendered the ◆ off-center
   and tiny (Marc S16 screenshots); geometry centers perfectly. */
.cc-heritage-emblem svg {
  display: block;
  width: 8px;
  height: 8px;
}
.cc-heritage .cc-avatar.sm .cc-heritage-emblem {
  width: 13px;
  height: 13px;
  right: -1px;
  bottom: -1px;
}
.cc-heritage .cc-avatar.sm .cc-heritage-emblem svg {
  width: 7px;
  height: 7px;
}

/* The heritage card — opens DOWNWARD (threads live in scroll containers;
   an upward tip on the first visible comment would clip at the top). */
.cc-heritage-tip {
  position: absolute;
  top: calc(100% + 9px);
  left: 0;
  z-index: 40;
  width: max-content;
  max-width: min(260px, 78vw);
  background: var(--bg-card);
  border: 1px solid var(--accent);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-elevated);
  padding: 10px 12px;
  display: none;
}
.cc-heritage:hover .cc-heritage-tip,
.cc-heritage:focus-within .cc-heritage-tip { display: block; }
.cc-heritage-tip::after {
  content: '';
  position: absolute;
  bottom: 100%;
  left: 12px;
  border: 6px solid transparent;
  border-bottom-color: var(--accent);
}
.cc-heritage-tip-cap {
  display: block;
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent-on-light);
  margin-bottom: 7px;
}
.cc-heritage-tip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
}

/* ===================================================================
   Session 17 — M10 Contributor Podium (§3.4/§8.5.2, S17 gate design).
   THE RING — Marc's pick B: house gold, HALO. The last closed month's
   champions wear it on every avatar through the current month: gold
   solid · silver dashed · bronze dotted, all in the accent family
   fading with rank, floating 2px off the circle (outline — zero
   layout cost). Ring and the ◆ heritage emblem coexist. The hover
   card LEADS with the seat + month (.cc-podium-tip); the profile
   keeps every dated win forever (.cc-profile-podium — the stars on
   the shirt). Labels are admin-renameable (status badge rows).
   =================================================================== */

.cc-ring { outline-offset: 2px; }
.cc-ring-gold {
  outline: 2px solid var(--accent);
  /* The approved halo wash (option B): ~15% accent, both themes. */
  box-shadow: 0 0 0 7px color-mix(in srgb, var(--accent) 15%, transparent);
}
.cc-ring-silver {
  outline: 2px dashed color-mix(in srgb, var(--accent-bright) 62%, transparent);
}
.cc-ring-bronze {
  outline: 1.5px dotted color-mix(in srgb, var(--accent-bright) 42%, transparent);
}
/* The ring owns the outline channel — keyboard focus stays visible by
   solidifying + thickening it (tokens' focus outline would lose the
   specificity fight on ringed avatars otherwise). */
.cc-ring:focus-visible {
  outline-style: solid;
  outline-width: 3px;
}

/* Scroll-panel threads clip at their inner left edge — give the halo
   its 6px of air (feedback/replay threads + live-chat rail). */
.cc-post-feedback .cc-thread,
.cc-class-live .cc-comments .cc-thread { padding-left: 6px; }

/* Hover-card lead line: the champion's seat (month-free — the ring
   means "now"). Past wins render as dated .past rows below it. */
.cc-podium-tip {
  display: block;
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-on-light);
  margin-bottom: 7px;
}
.cc-podium-tip.past {
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: color-mix(in srgb, var(--accent-on-light) 72%, var(--text-muted));
  margin-bottom: 3px;
}
.cc-podium-tip.past.more {
  color: var(--text-faint);
  text-transform: none;
  letter-spacing: 0.04em;
}
.cc-heritage-tip .cc-podium-tip:last-child { margin-bottom: 0; }

/* The ★ memory bubble (S17, Marc's award-bubble call): a PAST winner
   with no current reign wears the heritage-style notification bubble
   on the avatar's lower-LEFT (the ◆ owns the right corner — both can
   coexist on one avatar). Hover/focus opens the same card, which
   lists the dated wins. Reigning champions never wear it — the ring
   outranks the memory. */
.cc-award-emblem {
  position: absolute;
  left: -2px;
  bottom: -2px;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--text-on-accent);
  border: 2px solid var(--bg-card);
  display: grid;
  place-items: center;
}
.cc-award-emblem svg {
  display: block;
  width: 9px;
  height: 9px;
}
.cc-heritage .cc-avatar.sm .cc-award-emblem {
  width: 13px;
  height: 13px;
  left: -1px;
  bottom: -1px;
}
.cc-heritage .cc-avatar.sm .cc-award-emblem svg {
  width: 8px;
  height: 8px;
}

/* Profile: the permanent podium record — dated win pills, newest
   first, rendered in the established .cc-badge-pill vocabulary
   (.cc-podium-star + tier class = future styling hooks). */
.cc-profile-podium {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
}

/* ===================================================================
   Session 18b — the walking-in ritual (§3.2/§6.6/§6.12 Marc locks).
   Three surfaces + one systemic swap. The commitment page renders
   Marc's letter (word-locked S18b) over the "I'm in" button; the
   setup page's signature is the avatar slot — a dashed empty circle
   that fills with the member's face (dashed = waiting for content,
   the attach-strip vocabulary); the guidelines page is the S9
   quiet-letter register with the three middle sections indented on
   a gold rail (Marc's layout call). Systemic: photos replace
   initials inside .cc-avatar everywhere via .cc-avatar-photo — the
   img rounds ITSELF (never overflow:hidden on the avatar: the ◆/★
   bubbles sit outside the circle and must not clip). Rings and
   emblems live on the element and survive the swap untouched.
   =================================================================== */

/* The photo face — fills any .cc-avatar size (inline-flex centers it). */
.cc-avatar-photo {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
}

/* ------------------------------------------- the commitment letter -- */

.cc-letter {
  text-align: left;
  max-width: 46ch;
  margin: 0 auto var(--space-xl);
  color: var(--text-body);
  font-size: 15.5px;
  line-height: 1.7;
}
.cc-letter p { margin: 0 0 1em; }
.cc-letter-hi { color: var(--text-muted); }
.cc-letter-sign {
  font-family: var(--font-display);
  font-size: 17px;
  color: var(--text-primary);
  border-left: 3px solid var(--accent);
  padding-left: 12px;
  margin-bottom: 0;
}

/* ------------------------------------------------ profile setup page -- */

.cc-setup-card { max-width: 520px; width: 100%; }

.cc-setup-zone {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-sm);
  margin-bottom: var(--space-lg);
}
.cc-setup-zone[hidden] { display: none; }

/* The slot: dashed while waiting for a face, solid gold once it has one. */
.cc-setup-avatar {
  width: 112px;
  height: 112px;
  border-radius: 50%;
  border: 2px dashed var(--border-strong);
  background: var(--bg-elevated);
  color: var(--text-faint);
  font-size: 32px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: border-color var(--transition-fast);
}
.cc-setup-avatar.has-photo {
  border-style: solid;
  border-color: var(--accent);
}

.cc-setup-zone .cc-btn-gold,
.cc-crop-actions .cc-btn-gold { margin-left: 0; }
.cc-setup-pick input { display: none; }

.cc-setup-note {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-faint);
  margin: 0;
}

.cc-setup-error {
  color: var(--danger);
  font-size: 13.5px;
  min-height: 1em;
  margin-top: var(--space-xs);
}

/* The crop tool (vendored Cropper.js) — circular frame over the stage. */
.cc-crop { margin-bottom: var(--space-lg); }
.cc-crop[hidden] { display: none; }
.cc-crop-stage {
  height: 320px;
  background: #000;
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.cc-crop-stage img { display: block; max-width: 100%; }
.cc-crop .cropper-view-box,
.cc-crop .cropper-face { border-radius: 50%; }
.cc-crop .cropper-view-box {
  outline: 0;
  box-shadow: 0 0 0 1px var(--accent);
}
.cc-crop-zoom {
  width: 100%;
  accent-color: var(--accent);
  margin: var(--space-sm) 0 4px;
}
.cc-crop-actions {
  display: flex;
  justify-content: center;
  gap: var(--space-sm);
  margin-top: var(--space-sm);
}

.cc-setup-form { text-align: left; margin-top: var(--space-md); }
.cc-setup-label {
  display: block;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-primary);
  margin-bottom: 6px;
}
.cc-setup-label span {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  color: var(--text-faint);
  margin-left: 6px;
}
/* S25: the name field wears the bio's field look — ONE style, two elements
   (an <input> must not inherit the textarea's min-height / resize). */
.cc-setup-bio,
.cc-setup-input {
  width: 100%;
  background: var(--bg-input);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: 14.5px;
  line-height: 1.5;
  padding: 10px 12px;
}
.cc-setup-bio { resize: vertical; min-height: 72px; }
.cc-setup-input { margin-bottom: var(--space-md); }
.cc-setup-bio::placeholder,
.cc-setup-input::placeholder { color: var(--text-faint); }
.cc-setup-bio:focus,
.cc-setup-input:focus { border-color: var(--accent); outline: none; }
.cc-setup-form .cc-join-btn {
  width: 100%;
  margin-top: var(--space-md);
}

/* -------------------------------------------------- guidelines page -- */

.cc-guidelines { max-width: 640px; }
.cc-guidelines-title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(26px, 4.6vw, 34px);
  line-height: 1.2;
  color: var(--text-primary);
  margin: 0 0 var(--space-md);
}
.cc-guidelines-lead {
  color: var(--text-body);
  font-size: 15.5px;
  line-height: 1.7;
  margin: 0 0 var(--space-lg);
}

/* Marc's layout call: the three sections sit INDENTED between the
   full-width intro and closing — the gold rail carries the indent. */
.cc-guide-inner {
  border-left: 3px solid var(--accent);
  padding-left: var(--space-lg);
  margin: 0 0 var(--space-lg) var(--space-sm);
  display: flex;
  flex-direction: column;
  gap: var(--space-lg);
}
.cc-guide-head {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent-on-light);
  margin: 0 0 6px;
}
.cc-guide-inner p {
  margin: 0;
  color: var(--text-body);
  font-size: 15px;
  line-height: 1.7;
  max-width: 58ch;
}
.cc-guidelines-close {
  color: var(--text-primary);
  font-size: 15.5px;
  font-weight: 600;
  margin: 0 0 var(--space-md);
}
.cc-guidelines .cc-letter-sign { margin-top: var(--space-sm); }

/* Profile additions: the bio line + the self-edit door. */
.cc-profile-bio {
  margin: 8px 0 0;
  color: var(--text-body);
  font-size: 14.5px;
  line-height: 1.6;
  max-width: 56ch;
}
.cc-profile-edit {
  display: inline-block;
  margin-top: 6px;
  padding-left: 0;
}

@media (max-width: 720px) {
  .cc-crop-stage { height: 260px; }
  .cc-guide-inner { padding-left: var(--space-md); margin-left: 0; }
}

/* ===================================================================
   Session 19 — RESERVED RINGS (plan §8 P6 team-presentation row,
   Marc's locked design 2026-07-23 + the S19 gate). Two ring colors
   nobody can earn sit ABOVE the podium gold: GREEN = CC team (super
   admin / community moderator) · BLUE = CC teacher (calendar role).
   services/podium.py resolves precedence server-side (reserved always
   wins; no ★ bubble ever rides a reserved avatar). Same solid+halo
   treatment as gold — these are the top of the hierarchy. Semantic
   tokens (--success/--info) carry both themes. Board-row avatars wear
   rings since S19 too (staff excluded from the boards entirely).
   =================================================================== */

.cc-ring-team {
  outline: 2px solid var(--success);
  box-shadow: 0 0 0 7px color-mix(in srgb, var(--success) 15%, transparent);
}
.cc-ring-teacher {
  outline: 2px solid var(--info);
  box-shadow: 0 0 0 7px color-mix(in srgb, var(--info) 15%, transparent);
}

/* Hover-card lead lines take their ring's color (gold tiers keep the
   established accent voice — .cc-podium-tip's own color). */
.cc-podium-tip.team { color: var(--success); }
.cc-podium-tip.teacher { color: var(--info); }

/* ===================================================================
   Session 20 — the member directory (/community/members, plan §8 P6,
   Marc's gate pick: the Skool list). Quiet reuse of the established
   vocabulary: rows wear the card clothes, the count line + joined
   dates speak mono, avatars carry the S19 resolved rings. The team
   strip leads with RINGS ONLY — labels live in the hover tip (rings
   don't count themselves, Marc's gate call) — and wraps instead of
   scrolling so tips and ring halos never clip (§4.87 family).
   =================================================================== */

.cc-members-title {
  font-size: 26px;
  font-weight: 700;
  color: var(--text-primary);
  margin: 0 0 4px;
}
.cc-members-count {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-muted);
  margin: 0 0 var(--space-md);
}
.cc-members-count strong { color: var(--accent-on-light); font-weight: 700; }

/* Search — plain GET form; the input speaks the established input voice. */
.cc-msearch {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  margin-bottom: var(--space-md);
}
.cc-msearch svg { width: 15px; height: 15px; color: var(--text-faint); flex: 0 0 15px; }
.cc-msearch-input {
  flex: 1;
  min-width: 0;
  background: var(--bg-input);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: 14.5px;
  padding: 9px 12px;
}
.cc-msearch-input::placeholder { color: var(--text-faint); }
.cc-msearch-input:focus { border-color: var(--accent); outline: none; }
.cc-msearch .cc-btn-gold { margin-left: 0; }
.cc-msearch-meta {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-muted);
  margin: 0 0 var(--space-md);
}

/* Team & teachers strip — wraps, never scrolls (tips open downward and
   halos need their air; an overflow container would clip both). */
.cc-strip-eyebrow {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent-on-light);
  margin: 0 0 var(--space-sm);
}
.cc-team-strip {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-md) var(--space-lg);
  padding: 8px 6px var(--space-md);
  border-bottom: 1px solid var(--border-faint);
  margin-bottom: var(--space-lg);
}
.cc-strip-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
  min-width: 84px;
  text-decoration: none;
}
.cc-strip-name {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-primary);
  text-align: center;
}
.cc-strip-card:hover .cc-strip-name { color: var(--accent-on-light); }

/* The rows — Skool's list in the community's card clothes. The whole
   row is the profile link. */
.cc-mrows { display: flex; flex-direction: column; gap: 10px; }
.cc-mrow {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  padding: 14px 18px;
  text-decoration: none;
  transition: box-shadow var(--transition-base);
}
.cc-mrow:hover { box-shadow: var(--shadow-elevated); }
.cc-mrow .cc-heritage { flex: 0 0 auto; }
.cc-mrow-main { flex: 1; min-width: 0; }
.cc-mrow-name {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 15px;
  font-weight: 600;
  color: var(--text-primary);
}
.cc-mrow-bio {
  display: block;
  margin-top: 3px;
  font-size: 13.5px;
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cc-mrow-joined {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-faint);
  white-space: nowrap;
}

@media (max-width: 720px) {
  .cc-mrow { flex-wrap: wrap; padding: 12px 14px; }
  /* joined line drops under the bio, aligned with the text column
     (64px .lg avatar + the row gap). */
  .cc-mrow-joined { flex-basis: 100%; margin: 2px 0 0 calc(64px + var(--space-md)); }
  .cc-team-strip { gap: var(--space-md); }
}

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

/* ------------------------------------------------- who liked (Jul 2026) --
   Marc's separation gate: the heart is a pill you press, this is TEXT you
   read and click. They must never look like the same control, so the
   opener carries no icon, no border and no pill padding — it underlines on
   hover, which the heart never does. At zero it degrades to plain faint
   text: nothing to open, nothing to promise. */
.cc-likers-btn {
  background: transparent;
  border: 0;
  padding: 2px 0;
  color: var(--text-faint);
  font-family: var(--font-mono);
  font-size: 12px;
  cursor: pointer;
  transition: color var(--transition-fast);
}
.cc-likers-btn:hover:not([disabled]),
.cc-likers-btn:focus-visible:not([disabled]) {
  color: var(--text-primary);
  text-decoration: underline;
}
.cc-likers-btn[disabled] { cursor: default; text-decoration: none; }

/* The list itself — same elevation family as the report dialog, which also
   has to clear the post modal behind it. */
.cc-likers-backdrop {
  position: fixed;
  inset: 0;
  z-index: 1100;
  background: rgba(5, 7, 11, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}
.cc-likers-backdrop[hidden] { display: none; }

.cc-likers-dialog {
  position: relative;   /* .cc-modal-close anchors to THIS, not the page */
  width: 100%;
  max-width: 380px;
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-elevated);
  padding: var(--space-lg);
}
.cc-likers-head { margin-bottom: var(--space-sm); }
.cc-likers-title {
  font-size: 18px;
  font-weight: 700;
  margin: 0;
  color: var(--text-primary);
}

/* A long list scrolls INSIDE the dialog — the page behind never moves. */
.cc-likers-body {
  max-height: min(60vh, 420px);
  overflow-y: auto;
  margin: 0 calc(var(--space-sm) * -1);
  padding: 0 var(--space-sm);
}

.cc-liker-row {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding: 7px 8px;
  border-radius: var(--radius-sm);
  text-decoration: none;
  transition: background var(--transition-fast);
}
.cc-liker-row:hover { background: var(--bg-elevated); }
.cc-liker-name {
  min-width: 0;
  flex: 1;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cc-likers-empty,
.cc-likers-more {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-faint);
  margin: var(--space-sm) 0 0;
  padding: 0 8px;
}

@media (max-width: 720px) {
  .cc-likers-dialog { padding: var(--space-md); }
  .cc-likers-body { max-height: 70vh; }
}

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

/* ------------------------------------ the two-stage hover (S32, desktop) --
   Marc's call: on a mouse the count answers WITHOUT a click — faces grow out
   of it, then a capped card. Everything that REVEALS lives inside the
   capability query below, so a phone cannot reach this styling even if a
   script misfires; the base rules here are inert by construction — a
   zero-width stack and a hidden names span render byte-identically to the
   S27 control. Capability, never width: a touch laptop and an iPad with a
   trackpad both land on the right side of it, where a breakpoint would get
   them backwards (the §4.119 lesson, one floor up). */
.cc-likers-wrap { position: relative; display: inline-block; }
.cc-likers-btn { display: inline-flex; align-items: center; }

.cc-likers-stack {
  display: inline-flex;
  align-items: center;
  width: 0;
  overflow: hidden;
  opacity: 0;
}
.cc-likers-face {
  width: 19px;
  height: 19px;
  flex: 0 0 19px;
  margin-right: -6px;          /* the overlap that makes it read as a stack */
  border-radius: 50%;
  border: 1.5px solid var(--bg-card);
  background: var(--bg-elevated);
  color: var(--text-muted);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 8px;
  font-weight: 700;
  overflow: hidden;
}
.cc-likers-face img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }
/* Rings shrink with the face — the 2px offset of a full avatar would swallow
   a 19px one. Colors still come from the resolved cc-ring-<kind> class. */
.cc-likers-face.cc-ring { outline-width: 1.5px; outline-offset: 0; }

@media (hover: hover) and (pointer: fine) {
  .cc-likers-stack {
    transition: width .19s cubic-bezier(.2, .7, .3, 1),
                opacity .19s ease, margin-right .19s ease;
  }
  .cc-likers-wrap.cc-peeking .cc-likers-stack {
    width: var(--cc-stack-w, 0px);
    opacity: 1;
    margin-right: 8px;
  }
  /* The count steps aside for the names — same line, no second row. */
  .cc-likers-wrap.cc-peeking .cc-likers-total { display: none; }
  .cc-likers-names { color: var(--text-primary); }

  /* Beat 2. Capped, so it NEVER scrolls: past the cap the tail becomes a
     door to the dialog (Marc's call — a floating card must not trap the
     wheel). Rows reuse .cc-liker-row from the dialog, one row style. */
  .cc-likers-card {
    position: absolute;
    bottom: calc(100% + 11px);
    left: -10px;
    z-index: 60;
    width: 238px;
    padding: 11px;
    background: var(--bg-card);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-elevated);
    opacity: 0;
    transform: translateY(5px);
    pointer-events: none;
    transition: opacity .15s ease, transform .15s ease;
  }
  /* The bridge: without it the gap between control and card cancels the
     hover the moment the pointer starts crossing it. */
  .cc-likers-card::after {
    content: "";
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    height: 13px;
  }
  .cc-likers-wrap.cc-carded .cc-likers-card {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
  }

  .cc-likers-more.as-door {
    display: block;
    width: 100%;
    margin-top: 7px;
    padding: 7px 8px 2px;
    text-align: left;
    background: transparent;
    border: 0;
    border-top: 1px solid var(--border-faint);
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--text-faint);
    cursor: pointer;
    transition: color var(--transition-fast);
  }
  .cc-likers-more.as-door:hover { color: var(--accent-on-light); }
  .cc-likers-more.as-door:focus-visible {
    outline: 2px solid var(--accent-on-light);
    outline-offset: -2px;
    border-radius: var(--radius-sm);
  }
}

@media (prefers-reduced-motion: reduce) {
  .cc-likers-stack, .cc-likers-card { transition: none; }
}

/* ======================================================================
   FOLDED BACK IN — Aug 4 2026
   ======================================================================
   Everything below this line used to live in its own stylesheet, linked
   separately from feed.html / post.html / members.html:

     class-banner.css · community-unread.css · community-mentions.css
     community-autoload.css · live-theater.css

   Every one of them opened with the same sentence — "deliberately NOT in
   community.css, and the reason is the only reason" — and that reason was
   always the same: this file was stamped ?v={{ theme_asset_version }}, so
   editing it wiped every visitor's stored Light/Dark choice. Five sessions
   in a row each chose a side file over resetting 120K people, and the
   community's styling ended up spread across six files with nothing in
   this one pointing at any of them.

   Marc killed the cause on Aug 4: stylesheets now ride static_file()'s
   CONTENT HASH (_head_base.html), and THEME_ASSET_VERSION does only the
   deliberate launch reset. Editing this file publishes itself and resets
   nobody, so the side files had no reason left to exist.

   ⚠️ ORDER IS LOAD-BEARING. These sheets were emitted AFTER community.css
   and several of their rules win on SOURCE ORDER at equal specificity —
   .cc-class-banner's tinted fill over the base card fill is the clearest
   case. They are appended here, at the END, for exactly that reason. Do
   not hoist these blocks up into their original sections.

   player-chrome.css is NOT here and should not be: the membership lesson
   page (a different surface entirely) links it too, so it is genuinely
   shared rather than a workaround. cropper.min.css stays out as vendor code.
   ====================================================================== */

/* ======================================================================
   §A — the "N new comments" divider (was community-unread.css, Jul 2026)

   Rendered through _comment.html on both the feed modal and the permalink.
   ====================================================================== */

/* The line the member stopped reading at. It marks WHERE the new run starts
   and says HOW MANY there are — it deliberately does not claim that
   everything below it is new, because a reply renders under its parent and
   can drop already-read comments beneath the line (Marc's call: that is
   context for the new reply, not noise). The copy carries that honestly:
   "4 new comments", never "everything from here". */
.cc-newline {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 22px 0 4px;
  /* Breathing room when this element IS the scroll target — the deep-link
     from the feed card and a bare #cc-new URL both land here, and flush
     against the top edge reads like the thread was cut off. CSS owns the
     number so neither caller has to do scroll arithmetic. */
  scroll-margin-top: 24px;
}

/* The rule is the accent at a third of its weight: present enough to read as
   a boundary, quiet enough that the thread stays the subject. opacity rather
   than a hardcoded rgba so it tracks --accent-on-light across both themes
   (dark #d29922, light #9a6700) instead of freezing one of them. */
.cc-newline::before,
.cc-newline::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--accent-on-light);
  opacity: 0.35;
}

.cc-newline-label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--accent-on-light);
  white-space: nowrap;
}

/* ======================================================================
   §B — @-mentions (was community-mentions.css, Aug 2026, Marc's gate)
   ====================================================================== */

/* ---------------------------------------------------------- the mention --
   A tagged member is GOLD, not link-blue. Blue is what the S31 link policy
   gave "this leaves the paragraph and goes somewhere"; a mention is a PERSON
   inside the sentence, and gold is the room's own colour for people
   (rings, badges, the level chip).

   [href] is not decoration. The chokepoint keeps class="cc-mention" even
   when it drops an href that failed the link policy — so a hand-forged
   mention pointing at an external host arrives here with the class and no
   href, and this selector deliberately does not match it. It falls through
   to the a:not([href]) rule above and renders as ordinary text, which is
   exactly what a mention that leads nowhere should look like.

   Specificity is (0,3,1) against .cc-richtext a[href]'s (0,2,1), so the gold
   wins on its own merit and not on load order — which still matters now that
   both live in one file. */
.cc-richtext a.cc-mention[href],
.cc-richtext a.cc-mention[href]:hover,
.cc-richtext a.cc-mention[href]:visited {
  color: var(--accent-on-light);
  font-weight: 600;
  text-decoration: none;
  filter: none;
}
.cc-richtext a.cc-mention[href]:hover {
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* Inside the composer the same markup is a TipTap atom: one thing you select
   and delete whole, never a link you can click your way out of the editor
   with. */
.cc-editor a.cc-mention {
  color: var(--accent-on-light);
  font-weight: 600;
  text-decoration: none;
  cursor: default;
  border-radius: var(--radius-sm);
  padding: 0 1px;
}
.cc-editor a.cc-mention.ProseMirror-selectednode {
  background: var(--accent-glow);
  outline: none;
}

/* ------------------------------------------------------------- the menu --
   A singleton on <body> (mentions.js explains why), wearing the bell
   dropdown's clothes so it reads as the same system rather than a new one. */
.cc-mention-menu {
  position: absolute;
  z-index: 1300;              /* over the post modal, under nothing */
  max-width: min(340px, calc(100vw - 24px));
  padding: 4px;
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-elevated);
  overflow: hidden;
}
.cc-mention-menu[hidden] { display: none; }

.cc-mention-item {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  width: 100%;
  padding: 6px 8px;
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--text-body);
  font-family: inherit;
  font-size: 14px;
  text-align: left;
  cursor: pointer;
}
/* Hover and keyboard land on the SAME state — with a menu this short, a
   second highlight for "where the arrow keys are" would just be two things
   claiming to be the selection. */
.cc-mention-item:hover,
.cc-mention-item.active {
  background: var(--accent-glow);
  color: var(--text-primary);
}
.cc-mention-item:focus-visible { outline: none; }

.cc-mention-face { flex: 0 0 auto; }
.cc-mention-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cc-mention-empty {
  padding: 10px 12px;
  color: var(--text-muted);
  font-size: 13px;
}

/* Coarse pointers get a real target: 6px of padding is a mouse affordance,
   not a thumb one. */
@media (pointer: coarse) {
  .cc-mention-item { padding: 10px 10px; }
}

/* ======================================================================
   §C — the members list loading itself (was community-autoload.css)

   The ghost rows are the point. A spinner reports that SOMETHING is
   happening; these report that MEMBERS are coming, in the shape they will
   arrive in — and because a ghost is exactly as tall as the row that
   replaces it, nothing on the page jumps when the real names land.
   Geometry below is quoted from .cc-mrow / .cc-avatar.lg above; the two
   have to stay in step, which is why every number says where it came from.
   ====================================================================== */

/* The skeleton tones are an overlay on --bg-card, not a colour of their
   own, so they read as "this row is still developing" in both themes.
   The boot script stamps data-theme before any stylesheet loads, so these
   two rules always resolve; :root is belt and braces. */
:root {
  --cc-ghost-base:  rgba(255, 255, 255, 0.055);
  --cc-ghost-sheen: rgba(255, 255, 255, 0.115);
}
[data-theme="dark"] {
  --cc-ghost-base:  rgba(255, 255, 255, 0.055);
  --cc-ghost-sheen: rgba(255, 255, 255, 0.115);
}
[data-theme="light"] {
  --cc-ghost-base:  rgba(0, 0, 0, 0.055);
  --cc-ghost-sheen: rgba(0, 0, 0, 0.11);
}

/* The sentinel. Empty for most of its life — it needs a box for the
   observer to measure, and it is where the ghosts, the retry button and
   the closing line all render, so it owns no spacing of its own. */
.cc-autoload {
  display: block;
  min-height: 1px;
}

/* Announced by the live region, never seen. */
.cc-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* 10px twice: the gap .cc-mrows puts between rows, so the ghosts continue
   the list's rhythm instead of starting a new one. */
.cc-ghosts {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 10px;
}

/* Quoted from .cc-mrow. */
.cc-ghost-row {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  padding: 14px 18px;
}

/* Each row a little fainter than the one above it: the list doesn't end,
   it trails off — which is exactly what is true while a page is in
   flight. */
.cc-ghost-row:nth-child(2) { opacity: 0.75; }
.cc-ghost-row:nth-child(3) { opacity: 0.5; }

.cc-ghost-av {
  width: 64px;                     /* .cc-avatar.lg */
  height: 64px;
  flex: 0 0 64px;
  border-radius: 50%;
}
.cc-ghost-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 9px;
}
.cc-ghost-bar { height: 11px; border-radius: 6px; }
.cc-ghost-bar.name { width: 38%; }               /* .cc-mrow-name */
.cc-ghost-bar.bio  { width: 68%; height: 9px; }  /* .cc-mrow-bio */

.cc-ghost-av,
.cc-ghost-bar {
  background: linear-gradient(
    100deg,
    var(--cc-ghost-base) 30%,
    var(--cc-ghost-sheen) 50%,
    var(--cc-ghost-base) 70%
  );
  background-size: 300% 100%;
  animation: cc-ghost-sheen 1.4s ease-in-out infinite;
}
/* Staggered so the light reads as one pass moving down the list rather
   than three rows blinking in unison. */
.cc-ghost-row:nth-child(2) .cc-ghost-av,
.cc-ghost-row:nth-child(2) .cc-ghost-bar { animation-delay: 0.1s; }
.cc-ghost-row:nth-child(3) .cc-ghost-av,
.cc-ghost-row:nth-child(3) .cc-ghost-bar { animation-delay: 0.2s; }

@keyframes cc-ghost-sheen {
  from { background-position: 160% 0; }
  to   { background-position: -60% 0; }
}

/* The closing line — the quiet mono voice of .cc-members-count, at the
   other end of the same list. It only ever appears after a page has
   actually loaded, so a search that returns five people never gets told
   it has reached the end of five people. */
.cc-autoload-end {
  text-align: center;
  font-family: var(--font-mono);
  font-size: 11.5px;
  letter-spacing: 0.04em;
  color: var(--text-faint);
  margin: 0;
  padding: var(--space-lg) 0 var(--space-sm);
}

@media (max-width: 720px) {
  /* Mirrors the .cc-mrow mobile rule. */
  .cc-ghost-row { flex-wrap: wrap; padding: 12px 14px; }
}

@media (prefers-reduced-motion: reduce) {
  .cc-ghost-av,
  .cc-ghost-bar {
    animation: none;
    background: var(--cc-ghost-base);
  }
}

/* ======================================================================
   §D — the class banner's PROMINENCE layer + "(your local time)" +
        the Warm Split panel (was class-banner.css, Aug 2026)

   Marc: "casi ni te enteras que está ahí."

   ⚠️ These rules OVERRIDE the §S12 base vocabulary further up this file at
   EQUAL specificity — the tinted fill over the base card fill is the
   clearest case. They only work from BELOW it. Do not move them up.

   DESIGN. Zero new visual atoms. The tinted fill + accent border is the
   system's existing "this one is active" treatment, already carried by the
   active area chip, the unread bell row, a checked preference row and the
   first leaderboard row. The eyebrow's broadcast mark is the SAME glyph the
   class feed cards use, which also makes the two states symmetric: a
   scheduled class wears the dish, a live one wears the red dot. The one
   place boldness is spent is the COUNTDOWN — the only element here with real
   colour weight — because "in 2 days" is what turns a date into a reason to
   come back. Red still outranks gold: a class ON AIR keeps the danger
   vocabulary (§S13).
   ====================================================================== */

.cc-class-banner {
    background: var(--accent-glow);
    border-color: var(--accent);
    padding: var(--space-md);
    gap: 6px var(--space-md);
}
.cc-class-banner:hover {
    box-shadow: 0 0 0 3px var(--accent-glow);
    border-color: var(--accent-bright);
}

.cc-class-banner-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.cc-class-banner-eyebrow svg { flex: 0 0 auto; }

/* The class NAME is what a member reads — it stops inheriting body size. */
.cc-class-banner-title {
    font-size: 1.05rem;
    font-weight: 700;
    line-height: 1.35;
}

/* The forced second line. Two lines are not a compromise here — at the
   shell's 860px this row was never going to hold six items, and letting it
   wrap on its own put the countdown a column away from the date. Breaking
   at a fixed point gives desktop and phone the SAME two-line structure:
   what the class is, then when it is. */
.cc-class-banner-break { flex: 0 0 100%; height: 0; }

/* The date steps up from muted to body: it sits on a tinted fill now, and
   it carries the local-time note, so it has to stay comfortably readable
   while still ranking below the countdown. */
.cc-class-banner-when { color: var(--text-body); }

/* The arrow anchors the far end of the second line, opposite the when/count
   pair — so the line reads "when · how soon ............ the way in". */
.cc-class-banner-cta { margin-left: auto; }

/* THE SIGNATURE. Mono status voice like every other count in this system,
   but the only element on the banner wearing the foreground gold.
   :empty is what keeps it honest — the span ships with no text and no
   whitespace, so with the script dead it never reserves a slot for a
   countdown that will never tick. */
.cc-class-banner-count {
    font-family: var(--font-mono);
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--accent-on-light);
    white-space: nowrap;
}
.cc-class-banner-count:empty { display: none; }

/* Red is the on-air signal and outranks the gold treatment above (§S13).
   border-color covers all four sides, which is why the border-left-color
   rule for this state further up is simply superseded here rather than
   fought with. */
.cc-class-banner.is-live {
    background: var(--danger-bg);
    border-color: var(--danger);
}
.cc-class-banner.is-live:hover {
    border-color: var(--danger);
    box-shadow: 0 0 0 3px var(--danger-bg);
}

/* ------------------------------------------------ "(your local time)" -- */

/* Appended by classes.js AFTER it converts a stamp, never rendered by the
   server (see tzNote()). Quiet by construction: it is a reassurance, not a
   fact the member came for. */
.cc-tz-note {
    margin-left: 5px;
    font-family: var(--font-mono);
    font-size: 0.72rem;
    font-weight: 400;
    color: var(--text-faint);
    white-space: nowrap;
}

/* The class post's when-line is a block, not a flex row — the note follows
   the time inline and wraps as one unit on a narrow column. */
.cc-class-when-line .cc-tz-note { font-size: 0.68em; }

/* ------------------------------------------------------------- phone -- */

/* The structure is already right from the break above — the phone only
   tightens it. The arrow goes away: the whole banner is the tap target, so
   on touch "Open class →" is decoration paying for a line. */
@media (max-width: 720px) {
    .cc-class-banner {
        padding: var(--space-sm) var(--space-md);
        gap: 5px var(--space-sm);
    }
    .cc-class-banner-title { font-size: 1rem; }
    .cc-class-banner-cta { display: none; }
    .cc-tz-note { font-size: 0.66rem; }
}

/* -------- Warm Split — the upcoming-class panel + save-my-seat -------- */

/* The wrapper sheds its card chrome — the split panel IS the card in this
   state. Two classes beat the one-class base rule above. */
.cc-class-head.sched-split {
    border: 0;
    background: transparent;
    padding: 0;
    border-radius: 0;
}

.cc-class-split {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    align-items: stretch;
    border: 1px solid var(--accent);
    background: var(--accent-glow);
    border-radius: 10px;
    overflow: hidden;
}
/* The image column exists only when a class HAS an image (the template
   stamps has-thumb) — otherwise a fixed track would render 320px of
   empty tint. */
.cc-class-split.has-thumb {
    grid-template-columns: minmax(0, 1fr) 320px;
}
.cc-class-split-info {
    /* The extra bottom breathing is Marc's Aug 3 call — the note was
       sitting on the border. */
    padding: 18px 20px 24px;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 9px;
    min-width: 0;
}
.cc-class-split-info .cc-class-eyebrow { margin-bottom: 0; }
.cc-class-split-title {
    font-size: 1.28rem;
    font-weight: 700;
    line-height: 1.25;
    letter-spacing: -0.01em;
    color: var(--text-primary);
    text-wrap: balance;
}
.cc-class-split .cc-class-teacher,
.cc-class-split .cc-class-countdown { margin-top: 0; }
.cc-class-split .cc-class-doors { margin-top: 4px; }
.cc-class-split .cc-class-note { margin-top: 0; }

/* The image slot — Marc's three rules, resolved together (Aug 3 prod
   review): NEVER crop, centered when it can't fill, and it must TOUCH the
   panel's top and bottom borders. The img renders at its NATURAL ratio
   filling the fixed 320px column; when its height beats the text column
   (any square-ish upload — the shape the form encourages), the IMAGE
   defines the row, so it touches both borders exactly. A wider-than-tall
   upload can't reach both edges without cropping, so it centers instead.
   No absolute positioning, no aspect-ratio circularity — the first cut
   derived the box from the row height and browsers resolved it a few px
   short, shaving the image bottom under overflow:hidden. */
.cc-class-split-thumb {
    min-width: 0;
    border-left: 1px solid var(--border-subtle);
    display: flex;
    align-items: center;
    justify-content: center;
}
.cc-class-split-thumb img {
    display: block;
    width: 100%;
    height: auto;
}

/* THE SIGNATURE, promoted: the countdown is the one loud element in the
   panel — a gold pill wearing the black-on-gold button rule. :empty keeps
   it honest before the script ticks (the banner's own contract). */
.cc-count-pill {
    font-size: 0.84rem;
    font-weight: 700;
    color: var(--text-on-accent);
    background: linear-gradient(120deg, var(--accent-bright), var(--accent));
    border-radius: var(--radius-pill);
    padding: 5px 13px;
    white-space: nowrap;
    box-shadow: 0 4px 18px var(--accent-glow);
}
.cc-count-pill:empty { display: none; }

/* Save my seat — hover promises the 15-minute email; the saved state is a
   quiet confirmation (server-rendered on revisit, classes.js flips it
   live). Dark-glass tip on both themes — the player-chrome precedent. */
.cc-seat-wrap { position: relative; display: inline-flex; }
.cc-seat-btn.saved {
    background: transparent;
    color: var(--success);
    border: 1px solid var(--success);
    cursor: default;
}
.cc-seat-tip {
    position: absolute;
    bottom: calc(100% + 9px);
    left: 0;
    z-index: 5;
    width: 238px;
    background: #0d1117;
    color: #e6edf3;
    border: 1px solid #30363d;
    border-radius: 8px;
    padding: 8px 12px;
    font-size: 0.76rem;
    line-height: 1.45;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
    opacity: 0;
    transform: translateY(4px);
    pointer-events: none;
    transition: opacity var(--transition-fast), transform var(--transition-fast);
}
.cc-seat-tip::after {
    content: '';
    position: absolute;
    top: 100%;
    left: 24px;
    border: 6px solid transparent;
    border-top-color: #0d1117;
}
.cc-seat-wrap:hover .cc-seat-tip,
.cc-seat-btn:focus-visible + .cc-seat-tip { opacity: 1; transform: none; }
.cc-seat-wrap.saved .cc-seat-tip { display: none; }
@media (prefers-reduced-motion: reduce) {
    .cc-seat-tip { transition: none; }
}

/* "streams right here" — the note gains its camera glyph. */
.cc-class-here-note {
    display: flex;
    align-items: flex-start;
    gap: 7px;
}
.cc-class-here-note svg {
    flex: 0 0 auto;
    margin-top: 2px;
    color: var(--accent-on-light);
}

/* The room is warming up — real commenter faces + an honest count. */
.cc-class-social {
    display: flex;
    align-items: center;
    gap: 10px;
    color: var(--text-muted);
    font-size: 0.85rem;
    margin-top: var(--space-sm);
}
.cc-social-stack { display: inline-flex; }

/* Scheduled state only: the title lives in the panel, so the duplicate h1
   hides (post.js still reads the node) and the body renders under a cap. */
.cc-title-tucked { display: none; }
.cc-about-cap {
    font-family: var(--font-mono);
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--text-faint);
    margin: 2px 0 6px;
}

/* Banner mini square — the thumb stands beside the two-line grammar; the
   flow wrapper reproduces the banner's own wrap behavior so the break
   keeps working exactly as documented above. */
.cc-class-banner-thumb {
    width: 52px;
    aspect-ratio: 1 / 1;
    border-radius: 6px;
    overflow: hidden;
    flex: 0 0 auto;
    align-self: center;
    border: 1px solid var(--border-subtle);
}
.cc-class-banner-thumb img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    object-position: center;
    display: block;
}
.cc-class-banner-flow {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 6px var(--space-md);
    flex: 1 1 0;
    min-width: 0;
}

/* The banner's social line — Marc's Option A: its OWN line below the
   date (flex-basis 100% forces the wrap, the break-element trick's
   sibling). Same data as the class post's, tighter copy. */
.cc-class-banner-social {
    flex: 0 0 100%;
    display: flex;
    align-items: center;
    gap: 7px;
    margin-top: 2px;
    color: var(--text-muted);
    font-size: 0.82rem;
}

/* The banner's seat button — lives in the CTA slot, right-anchored like
   the CTA it replaces; compact, and it STAYS on phones (an action, not
   the decoration the hidden CTA was). */
.cc-banner-seat {
    margin-left: auto;
    align-self: center;
    background: var(--accent);
    color: var(--text-on-accent);
    font-weight: 700;
    font-size: 0.8rem;
    border: 0;
    border-radius: 7px;
    padding: 7px 14px;
    cursor: pointer;
    white-space: nowrap;
}
.cc-banner-seat:hover { background: var(--accent-bright); }

/* --------------------------------------------------- warm split, phone -- */
@media (max-width: 720px) {
    .cc-class-split { grid-template-columns: 1fr; }
    .cc-class-split-thumb {
        order: -1;
        width: 100%;
        max-width: 240px;
        margin: 16px auto 0;
        border: 1px solid var(--border-subtle);
        border-radius: 8px;
        overflow: hidden;       /* radius only — the natural-height img
                                   never exceeds this box */
    }
    .cc-class-split-title { font-size: 1.12rem; }
    .cc-class-banner-thumb { display: none; }
}

/* ======================================================================
   §E — live watch mode: fullscreen-with-chat for the LIVE class hour
        (was live-theater.css, Jul 2026)

   live.js drives three state classes:
     .cc-live-watch  on the <article> — the one ancestor holding BOTH the
                     player and the chat, so nothing re-parents, playback
                     never resets, and comments-only swaps land inside the
                     layout untouched
     .cc-chat-hidden on the same article — chat collapsed, video full-bleed
     .cc-watch-open  on <body> — the iOS-proof scroll lock (S10 recipe;
                     skipped when the feed modal's own lock already holds)

   Layout rule (Marc's gate): ORIENTATION decides. Landscape — desktop,
   tablet or phone — is video + chat rail on the right; portrait is video
   on top, chat filling the rest. Real element-fullscreen rides on top
   where the API exists; this overlay is the fullscreen on iPhone.
   Red stays the on-air signal only; everything here is the established
   mono/gold vocabulary. No new animation — nothing for reduced-motion.
   ====================================================================== */

/* ------------------------------------------------ ON AIR strip controls -- */

/* The fullscreen button wears .cc-golive's compact strip metrics. */
.cc-onair .cc-watch-fs {
    padding: 4px 12px;
    font-size: 12px;
    margin-left: 0;
    white-space: nowrap;
}
.cc-watch-fs svg { display: block; }

/* The chat toggle floats on the player's top-right corner — right where
   the rail unfolds (Marc's call: the strip sat too far from the chat it
   controls). Dark-glass over the picture (.cc-card-poster-play family),
   deliberately theme-independent: video is its own backdrop. */
.cc-watch-chat {
    position: absolute;
    top: 10px;
    right: 10px;
    z-index: 3;
    align-items: center;
    gap: 6px;
    border: 1px solid rgba(255, 255, 255, .28);
    border-radius: var(--radius-pill);
    background: rgba(5, 7, 11, .55);
    -webkit-backdrop-filter: blur(2px);
    backdrop-filter: blur(2px);
    color: #fff;
    font: 600 12px/1 var(--font-sans);
    padding: 7px 12px;
    cursor: pointer;
    white-space: nowrap;
}
.cc-watch-chat:hover { border-color: var(--accent, #c9a86a); }
.cc-watch-chat:focus-visible {
    outline: 2px solid var(--accent, #c9a86a);
    outline-offset: 2px;
}

/* Quiet Zoom door — a link in the quiet-button clothes. */
.cc-watch-zoom {
    text-decoration: none;
    white-space: nowrap;
}

/* Watch-only controls stay off until watch mode; the fullscreen button is
   the entry and shows always (inside the strip, which liveReady reveals). */
.cc-watch-chat,
.cc-watch-zoom,
.cc-watch-fs .cc-ic-shrink,
.cc-watch-fs .cc-watch-word-out { display: none; }

.cc-live-watch .cc-watch-chat { display: inline-flex; }
.cc-live-watch .cc-watch-zoom { display: inline; }
.cc-live-watch .cc-watch-fs .cc-ic-shrink,
.cc-live-watch .cc-watch-fs .cc-watch-word-out { display: inline; }
.cc-live-watch .cc-watch-fs .cc-ic-expand,
.cc-live-watch .cc-watch-fs .cc-watch-word-in { display: none; }

/* Chat toggle names its next action: "Hide chat" ↔ "Show chat". */
.cc-watch-chat .cc-chat-word-show { display: none; }
.cc-chat-hidden .cc-watch-chat .cc-chat-word-hide { display: none; }
.cc-chat-hidden .cc-watch-chat .cc-chat-word-show { display: inline; }

/* --------------------------------------------------------- the overlay -- */

/* Fixed full-viewport stage above the lightbox (1300) — the article keeps
   its own var(--bg-card), so both themes carry through untouched. */
article.cc-post.cc-live-watch {
    position: fixed;
    inset: 0;
    z-index: 1400;
    margin: 0;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    display: grid;
    grid-template-columns: minmax(0, 1fr) 340px;
    grid-template-rows: minmax(0, 1fr);
    gap: var(--space-sm) var(--space-md);
    padding: max(10px, env(safe-area-inset-top))
             max(14px, env(safe-area-inset-right))
             max(10px, env(safe-area-inset-bottom))
             max(14px, env(safe-area-inset-left));
    overflow: hidden;
}

/* Narrow landscape (phones sideways): a slimmer chat rail. */
@media (orientation: landscape) and (max-width: 900px) {
    article.cc-post.cc-live-watch { grid-template-columns: minmax(0, 1fr) 280px; }
}

/* Only the stream and the chat exist in watch mode. */
.cc-live-watch > .cc-card-pin,
.cc-live-watch > .cc-card-head,
.cc-live-watch > #cc-post-content,
.cc-live-watch > .cc-post-images,
.cc-live-watch > .cc-poll,
.cc-live-watch > .cc-post-foot,
.cc-live-watch .cc-class-doors,
.cc-live-watch .cc-class-eyebrow,
.cc-live-watch .cc-class-teacher { display: none; }

/* The class head sheds its card clothes and becomes the player column:
   video fills, the ON AIR strip stays anchored underneath. */
.cc-live-watch > .cc-class-head {
    grid-column: 1;
    grid-row: 1;
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 0;
    margin: 0;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
}
.cc-live-watch .cc-live-player {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
    margin-top: 0;
    position: relative;   /* anchors the corner chat toggle over the video */
}
.cc-live-watch .cc-live-player video {
    flex: 1 1 auto;
    min-height: 0;
    width: 100%;
    height: auto;
    max-height: none;
    aspect-ratio: auto;
    object-fit: contain;
    background: #000;
    border-radius: 0;
}

/* The chat rail — same engine, the S13 chat-mode order (thread over the
   input) now filling the full height. */
.cc-live-watch > .cc-comments {
    grid-column: 2;
    grid-row: 1;
    min-width: 0;
    min-height: 0;
    margin-top: 0;
    padding-top: 0;
    border-top: 0;
    border-left: 1px solid var(--border-faint);
    padding-left: var(--space-md);
}
.cc-class-live.cc-live-watch .cc-comments .cc-thread {
    max-height: none;
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
}
/* Live chats read bottom-up: while messages are few they anchor to the
   input, not the ceiling — the first node's auto margin eats the slack
   (works for the "No comments yet" line too). Once the thread overflows,
   scrolling behaves exactly as before. */
.cc-class-live.cc-live-watch .cc-comments .cc-thread > :first-child {
    margin-top: auto;
}

/* Chat collapsed: the video takes the whole stage. Selectors carry the
   article qualifier so they outrank the base overlay rules above. */
article.cc-post.cc-live-watch.cc-chat-hidden { grid-template-columns: minmax(0, 1fr); }
article.cc-post.cc-live-watch.cc-chat-hidden > .cc-comments { display: none; }

/* Portrait — phone or tablet held upright: video on top at its natural
   16:9, chat fills the rest (Marc's gate call). */
@media (orientation: portrait) {
    article.cc-post.cc-live-watch {
        grid-template-columns: minmax(0, 1fr);
        grid-template-rows: auto minmax(0, 1fr);
    }
    .cc-live-watch > .cc-class-head { grid-row: 1; }
    .cc-live-watch > .cc-comments {
        grid-column: 1;
        grid-row: 2;
        border-left: 0;
        padding-left: 6px;   /* §4.87 — ring halos need their air */
        border-top: 1px solid var(--border-faint);
        padding-top: var(--space-sm);
    }
    .cc-live-watch .cc-live-player video {
        flex: 0 0 auto;
        aspect-ratio: 16 / 9;
        max-height: 48vh;    /* tall tablets: chat keeps the majority */
    }
    article.cc-post.cc-live-watch.cc-chat-hidden { grid-template-rows: minmax(0, 1fr); }
    .cc-chat-hidden.cc-live-watch .cc-live-player video {
        flex: 1 1 auto;
        aspect-ratio: auto;
        max-height: none;
        min-height: 0;
    }
}

/* ------------------------------------------------------- page behind ---- */

/* iOS-proof scroll lock — the body.cc-modal-open recipe with its own class
   so the feed modal's lock (and its scroll restore) is never fought. */
body.cc-watch-open {
    position: fixed;
    left: 0;
    right: 0;
    width: 100%;
    overflow-y: scroll;
}

/* ------------------------------------------- phones, no button pressed -- */

/* The sticky default (Marc's pick A): while a class is LIVE on a small
   screen, the player block pins to the top of the viewport, so scrolling
   down to the chat never loses the picture. Watch mode overrides it. */
@media (max-width: 720px) {
    .cc-class-live:not(.cc-live-watch) .cc-class-head {
        position: sticky;
        top: 0;
        z-index: 20;
    }
}

/* ====================================================================== */
/* Video auto-loop (Aug 2026, phase8) — loop-ON attach videos play muted   */
/* inside the feed card; the composer's video strip grew the loop toggle.  */
/* ====================================================================== */

/* The card video wears the poster image's exact clothes — same box, same
   crop — so a loop-ON card and a poster card sit identically in the feed. */
.cc-card-poster video {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

/* "Loop this video" in the composer's attach strip (feed.html #cc-vstrip). */
.cc-loop-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
  font-size: 12.5px;
  color: var(--text-secondary);
  cursor: pointer;
  white-space: nowrap;
}
.cc-loop-label input {
  accent-color: var(--accent);
  cursor: pointer;
}
/* The same label inside the post-edit form (post.js builds it there). */
.cc-post-edit-form .cc-loop-label { margin: 8px 0 2px; }
