.main-content {
  flex: 1;
  min-width: 0;
  height: 100vh;
  overflow-y: auto;
  overflow-x: hidden;
  /* v07g — back to the original 12px top / 20px sides. The project
     panel itself handles the top-side gap symmetry via its negative
     margins (see .ph-project below) — main-content padding stays
     compact so the panels below stay close to the left edge. */
  padding: 12px 20px 18px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  color: var(--ink-on-dark);
  /* Restored rounded left corners — design intent is the glass main panel
     sitting on top of the dark sidebar drawer with soft rounded edges. */
  border-top-left-radius: var(--r-shell);
  border-bottom-left-radius: var(--r-shell);
  /* Background: at the LEFT edge (where main-content meets sidebar) the bg
     starts transparent so the sidebar/backdrop bleeds through, then transitions
     to a warm cream wash — same translucent→cream language as the topbar's
     glass-to-cream transition. */
  background:
    linear-gradient(to right,
      transparent 0%,
      color-mix(in srgb, color-mix(in srgb, var(--gold-13) 30%, var(--mix-light)) 10%, transparent) 40px,
      color-mix(in srgb, color-mix(in srgb, var(--gold-13) 30%, var(--mix-light)) 18%, transparent) 120px,
      color-mix(in srgb, color-mix(in srgb, var(--gold-13) 30%, var(--mix-light)) 10%, transparent) 360px,
      transparent 520px),
    radial-gradient(ellipse 90% 50% at 50% 0%,
      color-mix(in srgb, color-mix(in srgb, var(--gold-17) 65%, var(--mix-light)) 22%, transparent) 0%,
      color-mix(in srgb, color-mix(in srgb, var(--gold-17) 65%, var(--mix-light)) 8%, transparent) 35%,
      transparent 65%),
    linear-gradient(180deg,
      color-mix(in srgb, var(--cream-10) 6%, transparent) 0%,
      transparent 320px);
  box-shadow:
    /* bright top-left edge highlight on the rounded corner */
    inset 1px 1px 0 color-mix(in srgb, var(--hi) 28%, transparent),
    inset 0 1px 0 color-mix(in srgb, var(--hi) 32%, transparent),
    /* strong drop shadow falling LEFT onto sidebar — sells the "going under" feel */
    -14px 0 40px -10px rgba(0, 0, 0, 0.55),
    -3px 0 10px rgba(0, 0, 0, 0.22);
  scrollbar-width: thin;
  scrollbar-color: color-mix(in srgb, var(--card-border) 35%, transparent) transparent;
  position: relative;
  z-index: 3;
}
.main-content::-webkit-scrollbar { width: 8px; }
.main-content::-webkit-scrollbar-thumb { background: color-mix(in srgb, var(--card-border) 30%, transparent); border-radius: 4px; }
.main-content > * { flex-shrink: 0; }

.project-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 24px;
  /* v07i — Hugo: bigger title now occupies the previously empty
     padding zone at the top. Drop project-header padding-top to 0
     so the bigger title absorbs the height instead of pushing the
     topbar down. The .ph-project's negative margin-top still gives
     the 8px gap from the back-panel top to match the side gap. */
  padding: 0 4px 0;
  position: relative;
  z-index: 40;
}

.ph-left { min-width: 0; flex: 1; min-width: 0; }
.ph-eyebrow {
  /* v07i — Hugo: scaled up so the PROJECT eyebrow reads as part of
     the title section (was tiny at 11px). */
  font-size: var(--fs-14);
  letter-spacing: var(--track-16);
  text-transform: uppercase;
  font-weight: var(--fw-semi);
  color: var(--ink-on-dark-muted);
  margin-bottom: 6px;
}
.ph-title-row {
  display: inline-flex;
  /* 17 Sep 2026 - top, not the default baseline: an <img> logo has no text baseline, so on the
     baseline its line box grew 5px and everything below dropped 5px the moment a logo loaded */
  vertical-align: top;
  align-items: center;
  gap: 12px;
  cursor: pointer;
  user-select: none;
  background: none;
  border: none;
  padding: 0;
  text-align: left;
  border-radius: var(--r-sm);
  transition: opacity var(--dur-2) ease;
}
.ph-title-row:hover .ph-caret { background: color-mix(in srgb, var(--mix-light) 14%, transparent); }
.ph-title-row:focus-visible { outline: var(--ring-w) solid var(--leaf); outline-offset: 4px; }
.ph-title {
  font-family: var(--font-display);
  /* v07i — Hugo: scaled up to fit the bigger title section. */
  font-size: clamp(58px, 7vw, 96px);
  font-weight: var(--fw-bold);
  letter-spacing: var(--track-005);
  line-height: 0.96;
  color: var(--ink-on-dark);
  margin: 0;
  font-feature-settings: var(--tnum);
}
.ph-caret {
  background: color-mix(in srgb, var(--mix-light) 5%, transparent);
  border: 1px solid color-mix(in srgb, var(--card-border) 22%, transparent);
  border-radius: var(--r-sm);
  width: 28px; height: 28px;
  display: grid; place-items: center;
  color: var(--ink-on-dark-muted);
  cursor: pointer;
  transition: background var(--dur-1) ease;
}
.ph-caret:hover { background: color-mix(in srgb, var(--mix-light) 10%, transparent); }
.ph-meta {
  display: flex;
  align-items: center;
  /* v07i/v07l — even tighter horizontal row so Episode 01 and the
     IN PRODUCTION pill sit closer to "Nature documentary". Was 8px
     → 4px. The dot separator + EpisodeSwitcher already have their
     own internal padding so the visual gap reads well at 4px. */
  gap: 4px;
  margin-top: 10px;
  flex-wrap: wrap;
}
.ph-subtitle {
  font-size: var(--fs-13);
  color: var(--ink-on-dark-muted);
}
.ph-status-pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 12px 5px 10px;
  border-radius: var(--r-pill);
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--mix-light) 16%, transparent) 0%,
    color-mix(in srgb, var(--black) 12%, transparent) 100%);
  border: 1px solid currentColor;
  font-size: var(--fs-10-5);
  font-weight: var(--fw-bold);
  letter-spacing: var(--track-12);
  box-shadow:
    inset 0 1px 0 var(--status-pill-bevel-hi),
    inset 0 -1px 0 var(--status-pill-bevel-lo),
    0 1px 3px var(--status-pill-drop);
  text-shadow: 0 1px 1px var(--panel-text-shadow-color);
  position: relative;
}
/* v07zz72 — Audit fix: two .ph-pill-dot rules in a row were fighting.
   The second one silently dropped the `background: currentColor`
   from the first, leaving a hard-coded green dot regardless of pill
   context. Consolidated into one rule that preserves currentColor +
   the 3D inset + the leaf glow halo. */
.ph-pill-dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: currentColor;
  box-shadow:
    inset 0 -1px 0 rgba(0, 0, 0, 0.30),
    inset 0 1px 0 rgba(255, 255, 255, 0.55),
    0 0 6px color-mix(in srgb, var(--leaf) 60%, transparent);
}

.ph-right {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 4px;
}
.ph-iconbtn {
  width: 40px; height: 40px;
  border-radius: 50%;
  /* glass-like — radial cream tint that fades from top-left to give the orb depth */
  background:
    radial-gradient(circle at 30% 28%, color-mix(in srgb, var(--cream-5) 14%, transparent), color-mix(in srgb, var(--cream-5) 2%, transparent) 65%),
    color-mix(in srgb, var(--shade-5) 2%, transparent);
  backdrop-filter: blur(10px) saturate(1.20);
  -webkit-backdrop-filter: blur(10px) saturate(1.20);
  border: none;
  color: var(--ink-on-dark);
  display: grid; place-items: center;
  cursor: pointer;
  position: relative;
  box-shadow:
    /* inner glow — top-left highlight, bottom-right falloff */
    inset 1px 1px 2px color-mix(in srgb, var(--hi) 35%, transparent),
    inset -1px -1px 2px rgba(0, 0, 0, 0.18),
    inset 0 0 12px color-mix(in srgb, var(--hi) 10%, transparent),
    /* outer drop shadow */
    0 1px 2px rgba(0, 0, 0, 0.16),
    0 6px 16px rgba(0, 0, 0, 0.22);
  transition: background var(--dur-1) ease, box-shadow var(--dur-2) ease, transform var(--dur-1) ease;
}
.ph-iconbtn::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  border-radius: inherit;
  padding: 1px;
  background: conic-gradient(from 215deg at 50% 50%,
    color-mix(in srgb, var(--hi-3) 65%, transparent) 0%,
    color-mix(in srgb, var(--foil) 25%, transparent) 18%,
    color-mix(in srgb, var(--foil) 4%, transparent) 35%,
    transparent 50%,
    transparent 75%,
    color-mix(in srgb, var(--hi) 18%, transparent) 92%,
    color-mix(in srgb, var(--hi-3) 65%, transparent) 100%);
  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
}
.ph-iconbtn:hover {
  background:
    radial-gradient(circle at 30% 28%, color-mix(in srgb, var(--cream-5) 32%, transparent), color-mix(in srgb, var(--cream-5) 8%, transparent) 65%),
    color-mix(in srgb, var(--shade-5) 6%, transparent);
  transform: translateY(-1px);
  box-shadow:
    inset 1px 1px 2px color-mix(in srgb, var(--hi) 45%, transparent),
    inset -1px -1px 2px rgba(0, 0, 0, 0.18),
    inset 0 0 14px color-mix(in srgb, var(--hi) 14%, transparent),
    0 2px 4px rgba(0, 0, 0, 0.20),
    0 8px 20px rgba(0, 0, 0, 0.28);
}
/* v07r — manual refresh button. Spins for ~0.9 s on click so the user
   has a visible signal that the action fired (and to mask the round-
   trip latency of /api/sync/trigger). */
.ph-iconbtn.is-spinning svg {
  animation: ph-refresh-spin 0.9s ease-in-out;
}
@keyframes ph-refresh-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}
/* Secondary refresh button next to the IN PRODUCTION pill — smaller
   footprint so it doesn't fight the pill for visual weight. */
.ph-iconbtn.ph-meta-refresh {
  width: 28px;
  height: 28px;
  margin-left: 8px;
  border-radius: var(--r-sm);
}
.ph-iconbtn.ph-meta-refresh svg {
  width: 15px;
  height: 15px;
}
.ph-bell-dot {
  position: absolute;
  top: 9px; right: 10px;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--amber);
  box-shadow: 0 0 0 var(--ring-w) var(--sidebar-bg);
}
/* v07zz35 — Bell "new notification" treatment. Hugo's brief: ONE
   shine, fast, diagonal — comes in from nothing, travels diagonal,
   leaves to nothing. The previous version had a noticeable two-step
   feel (scale pulse + slow horizontal sweep + persistent ring). We
   now do a single ~700 ms diagonal stripe with opacity fading in and
   out at the ends so the streak has no hard start or stop. The gold
   outline is kept as a subtle accent that pulses with the same
   timing — not its own animation. */
.ph-iconbtn.ph-iconbtn--notif-flash {
  animation: ph-bell-flash 700ms ease-out 1 forwards;
}
.ph-iconbtn.ph-iconbtn--notif-flash::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  overflow: hidden;
  /* 135° gradient = a stripe oriented top-right ↘ bottom-left.
     Moving background-position from one off-canvas diagonal corner to
     the opposite makes the highlight travel diagonally across the
     icon. background-size 250% gives the stripe enough room to leave
     the visible area entirely at both ends. */
  background: linear-gradient(135deg,
    transparent 35%,
    color-mix(in srgb, var(--hi-3) 85%, transparent) 50%,
    transparent 65%);
  background-size: 250% 250%;
  background-position: 130% -130%;
  background-repeat: no-repeat;
  animation: ph-bell-shine 700ms cubic-bezier(0.4, 0, 0.4, 1) 1 forwards;
  mix-blend-mode: screen;
  opacity: 0;
}
@keyframes ph-bell-flash {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--gold-3) 0%, transparent); }
  30%  {
    box-shadow:
      0 0 0 var(--ring-w) color-mix(in srgb, var(--gold-3) 70%, transparent),
      0 0 14px color-mix(in srgb, var(--gold-3) 35%, transparent);
  }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--gold-3) 0%, transparent); }
}
@keyframes ph-bell-shine {
  0%   { background-position: 130% -130%; opacity: 0; }
  30%  { opacity: 1; }
  70%  { opacity: 1; }
  100% { background-position: -130% 130%; opacity: 0; }
}
.ph-avatar {
  display: flex; align-items: center; gap: 6px;
  padding: 4px 10px 4px 4px;
  height: 40px;
  border-radius: var(--r-round);
  background:
    radial-gradient(circle at 30% 28%, color-mix(in srgb, var(--cream-5) 22%, transparent), color-mix(in srgb, var(--cream-5) 4%, transparent) 75%),
    color-mix(in srgb, var(--shade-5) 4%, transparent);
  backdrop-filter: blur(14px) saturate(1.30);
  -webkit-backdrop-filter: blur(14px) saturate(1.30);
  border: none;
  color: var(--ink-on-dark);
  cursor: pointer;
  position: relative;
  box-shadow:
    inset 1px 1px 2px color-mix(in srgb, var(--hi) 35%, transparent),
    inset -1px -1px 2px rgba(0, 0, 0, 0.18),
    inset 0 0 12px color-mix(in srgb, var(--hi) 10%, transparent),
    0 1px 2px rgba(0, 0, 0, 0.16),
    0 6px 16px rgba(0, 0, 0, 0.22);
  transition: background var(--dur-1) ease, box-shadow var(--dur-2) ease, transform var(--dur-1) ease;
}
.ph-avatar::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(135deg,
    color-mix(in srgb, var(--hi-3) 55%, transparent) 0%,
    color-mix(in srgb, var(--foil) 20%, transparent) 22%,
    color-mix(in srgb, var(--foil) 4%, transparent) 45%,
    transparent 65%);
  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
}
.ph-avatar:hover {
  background:
    radial-gradient(circle at 30% 28%, color-mix(in srgb, var(--cream-5) 32%, transparent), color-mix(in srgb, var(--cream-5) 8%, transparent) 75%),
    color-mix(in srgb, var(--shade-5) 6%, transparent);
  transform: translateY(-1px);
}
.ph-initials {
  width: 30px; height: 30px;
  border-radius: 50%;
  background: linear-gradient(140deg, var(--card-border), var(--leaf));
  color: var(--ink-on-leaf);
  font-family: var(--font-display);
  font-size: var(--fs-12);
  font-weight: var(--fw-bold);
  display: grid; place-items: center;
  letter-spacing: var(--track-04);
}
.ph-avatar-caret { color: var(--ink-on-dark-muted); display: inline-flex; }

/* ─── Dropdown menus (project, search, notifications, avatar) ───────── */

.ph-anchor {
  position: relative;
  display: inline-flex;
}
.ph-caret.is-open,
.ph-iconbtn.is-open,
.ph-avatar.is-open {
  background: color-mix(in srgb, var(--mix-light) 14%, transparent);
  border-color: color-mix(in srgb, var(--card-border) 45%, transparent);
}

.ph-menu {
  position: absolute;
  top: calc(100% + 8px);
  z-index: 60;
  min-width: 280px;
  padding: 8px;
  background: color-mix(in srgb, var(--shade-16) 94%, transparent);
  backdrop-filter: blur(var(--glass-blur)) saturate(1.05);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(1.05);
  border: 1px solid color-mix(in srgb, var(--card-border) 32%, transparent);
  border-radius: var(--r-md);
  box-shadow:
    0 18px 40px rgba(0,0,0,0.35),
    0 2px 6px rgba(0,0,0,0.20),
    inset 0 1px 0 rgba(255,255,255,0.06);
  color: var(--ink-on-dark);
  animation: ph-menu-in var(--dur-2) var(--ease-glide);
  transform-origin: top right;
}
.ph-menu--project { left: 0; right: auto; transform-origin: top left; }
.ph-menu--search { right: 0; width: 360px; padding: 8px; }
.ph-menu--notif  { right: 0; width: 360px; }
.ph-menu--avatar { right: 0; width: 280px; }
@keyframes ph-menu-in {
  from { opacity: 0; transform: translateY(-4px) scale(0.98); }
  to   { opacity: 1; transform: translateY(0)    scale(1); }
}

.ph-menu-eyebrow {
  font-size: var(--fs-10);
  letter-spacing: var(--track-16);
  font-weight: var(--fw-semi);
  color: var(--ink-on-dark-muted);
  padding: 6px 10px 4px;
  text-transform: uppercase;
}
.ph-menu-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 4px 8px 4px 10px;
}
.ph-menu-link {
  background: none;
  border: none;
  color: var(--ink-on-dark-muted);
  font-size: var(--fs-11);
  cursor: pointer;
  letter-spacing: var(--track-04);
}
.ph-menu-link:hover:not(:disabled) { color: var(--ink-on-dark); }
.ph-menu-link:disabled {
  opacity: 0.45;
  cursor: default;
}

.ph-menu-row {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  background: none;
  border: none;
  border-radius: var(--r-sm);
  color: var(--ink-on-dark);
  cursor: pointer;
  text-align: left;
  transition: background var(--dur-0) ease;
}
.ph-menu-row:hover { background: color-mix(in srgb, var(--mix-light) 6%, transparent); }
.ph-menu-row.is-active { background: color-mix(in srgb, var(--leaf) 14%, transparent); }

.ph-menu-row-text { flex: 1; min-width: 0; }
.ph-menu-row-title {
  font-size: var(--fs-13);
  font-weight: var(--fw-med);
  color: var(--ink-on-dark);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ph-menu-row-sub {
  font-size: var(--fs-11-5);
  color: var(--ink-on-dark-muted);
  margin-top: 2px;
  letter-spacing: var(--track-01);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ph-menu-ico {
  width: 22px;
  display: inline-flex;
  justify-content: center;
  color: var(--ink-on-dark-muted);
  flex-shrink: 0;
}
.ph-menu-check {
  color: var(--leaf);
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
}
.ph-menu-sep {
  height: 1px;
  background: color-mix(in srgb, var(--card-border) 18%, transparent);
  margin: 6px 4px;
}
.ph-menu-cta {
  color: var(--ink-on-dark-muted);
  font-weight: var(--fw-med);
}
.ph-menu-cta:hover { color: var(--ink-on-dark); background: color-mix(in srgb, var(--mix-light) 6%, transparent); }
.ph-menu-signout {
  color: color-mix(in srgb, var(--amber) 84%, var(--mix-light));
}
.ph-menu-signout .ph-menu-ico { color: color-mix(in srgb, var(--amber) 84%, var(--mix-light)); }
.ph-menu-signout:hover { background: color-mix(in srgb, color-mix(in srgb, var(--amber) 84%, var(--mix-light)) 10%, transparent); }

/* ─── Search ────────────────────────────────────────────────────────── */
.ph-search-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  background: color-mix(in srgb, var(--black) 20%, transparent);
  border: 1px solid color-mix(in srgb, var(--card-border) 25%, transparent);
  border-radius: var(--r-sm);
}
.ph-search-glyph { color: var(--ink-on-dark-muted); display: inline-flex; }
.ph-search-input {
  flex: 1;
  background: transparent;
  border: none;
  outline: none;
  color: var(--ink-on-dark);
  font-family: var(--font-body);
  font-size: var(--fs-13);
  caret-color: var(--leaf);
}
.ph-search-input::placeholder { color: var(--ink-on-dark-muted); }
.ph-search-clear {
  background: color-mix(in srgb, var(--mix-light) 6%, transparent);
  border: none;
  color: var(--ink-on-dark-muted);
  width: 22px; height: 22px;
  border-radius: 50%;
  display: grid; place-items: center;
  cursor: pointer;
}
.ph-search-clear:hover { background: color-mix(in srgb, var(--mix-light) 12%, transparent); color: var(--ink-on-dark); }
.ph-search-results {
  margin-top: 6px;
  max-height: 360px;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: color-mix(in srgb, var(--card-border) 30%, transparent) transparent;
}
.ph-search-results::-webkit-scrollbar { width: 6px; }
.ph-search-results::-webkit-scrollbar-thumb { background: color-mix(in srgb, var(--card-border) 25%, transparent); border-radius: 3px; }
.ph-search-empty {
  padding: 14px 10px;
  color: var(--ink-on-dark-muted);
  font-size: var(--fs-12);
  font-style: italic;
}
.ph-result-id {
  font-family: var(--font-mono);
  font-size: var(--fs-12);
  letter-spacing: var(--track-02);
  color: color-mix(in srgb, var(--ink-hi-3) 84%, var(--mix-dark));
}
.ph-search-hint {
  padding: 12px 10px 8px;
  font-size: var(--fs-11-5);
  color: var(--ink-on-dark-muted);
  letter-spacing: var(--track-01);
}
.ph-search-hint kbd {
  font-family: var(--font-mono);
  font-size: var(--fs-10-5);
  padding: 2px 6px;
  margin: 0 2px;
  background: color-mix(in srgb, var(--mix-light) 6%, transparent);
  border: 1px solid color-mix(in srgb, var(--card-border) 25%, transparent);
  border-radius: 4px;
  color: var(--ink-on-dark);
}

/* ─── Notifications ─────────────────────────────────────────────────── */
.ph-notif-list {
  display: flex;
  flex-direction: column;
  max-height: 380px;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: color-mix(in srgb, var(--card-border) 30%, transparent) transparent;
}
.ph-notif-list::-webkit-scrollbar { width: 6px; }
.ph-notif-list::-webkit-scrollbar-thumb { background: color-mix(in srgb, var(--card-border) 25%, transparent); border-radius: 3px; }
.ph-notif-row { align-items: flex-start; }
.ph-notif-icon {
  width: 28px; height: 28px;
  border-radius: 50%;
  border: 1px solid;
  display: grid; place-items: center;
  flex-shrink: 0;
  margin-top: 2px;
}
.ph-notif-time {
  font-size: var(--fs-10-5);
  color: var(--ink-on-dark-muted);
  letter-spacing: var(--track-02);
}
/* v07w — meta row: author + dot + time. */
.ph-notif-meta {
  display: flex;
  align-items: center;
  gap: 5px;
  margin-top: 4px;
  font-size: var(--fs-10-5);
  color: var(--ink-on-dark-muted);
}
.ph-notif-author {
  color: color-mix(in srgb, var(--ink-hi-2) 85%, var(--mix-dark));
  font-weight: var(--fw-med);
}
.ph-notif-dot-sep {
  opacity: 0.55;
}
/* v07w/v07y — Toast pop-down below the bell when a new notification
   arrives. Right edge aligned with the bell button column (the bell
   sits ~110 px from the right after the avatar + refresh icons).
   Top pushed further down so it doesn't crowd the icon row. */
.ph-notif-toast-wrap {
  position: fixed;
  top: 76px;
  right: 110px;
  z-index: var(--z-sticky);
  display: flex;
  flex-direction: column;
  gap: 8px;
  pointer-events: none;
}
.ph-notif-toast {
  pointer-events: auto;
  /* v07x — Cream palette (same family as the modal cards / asset
     popups) per Hugo. Was dark green; clashed with the rest of the
     UI. Border + shadow tuned to read against the dark forest bg. */
  background: color-mix(in srgb, var(--cream-2) 97%, transparent);
  border: 1px solid color-mix(in srgb, var(--tan-deep) 32%, transparent);
  border-radius: var(--r-md);
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--cream) 85%, transparent),
    0 6px 18px color-mix(in srgb, var(--shade) 36%, transparent),
    0 14px 32px color-mix(in srgb, var(--shade) 30%, transparent);
  padding: 12px 14px 12px 12px;
  display: flex;
  gap: 10px;
  align-items: flex-start;
  min-width: 260px;
  max-width: 360px;
  color: var(--ink);
  cursor: pointer;
  animation: ph-toast-in var(--dur-4) cubic-bezier(0.2, 0.8, 0.2, 1);
  transition: opacity 200ms ease, transform 200ms ease;
}
.ph-notif-toast.is-leaving {
  opacity: 0;
  transform: translateY(-6px);
}
.ph-notif-toast-icon {
  width: 28px; height: 28px;
  border-radius: var(--r-sm);
  display: grid; place-items: center;
  flex-shrink: 0;
  border: 1px solid;
}
.ph-notif-toast-text {
  font-size: var(--fs-12);
  line-height: 1.35;
  flex: 1;
  min-width: 0;
}
.ph-notif-toast-title {
  font-weight: var(--fw-semi);
  color: var(--ink);
  margin-bottom: 2px;
}
.ph-notif-toast-sub {
  font-size: var(--fs-11-5);
  color: color-mix(in srgb, var(--ink-umber-3) 72%, transparent);
  line-height: 1.4;
  margin-top: 1px;
}
.ph-notif-toast-author {
  font-size: var(--fs-10-5);
  color: color-mix(in srgb, color-mix(in srgb, var(--ink-tan-deep) 65%, var(--mix-dark)) 62%, transparent);
  margin-top: 3px;
  font-style: italic;
}
.ph-notif-toast-close {
  background: transparent;
  border: none;
  color: color-mix(in srgb, var(--ink-umber-3) 45%, transparent);
  cursor: pointer;
  padding: 2px;
  margin: -2px 0 0 0;
  font-size: var(--fs-14);
  line-height: 1;
}
.ph-notif-toast-close:hover { color: color-mix(in srgb, var(--ink-umber-3) 85%, transparent); }
@keyframes ph-toast-in {
  from { opacity: 0; transform: translateY(-8px); }
  to   { opacity: 1; transform: translateY(0); }
}
.ph-notif-dot {
  width: 7px; height: 7px;
  border-radius: 50%;
  margin-top: 6px;
  flex-shrink: 0;
}
.ph-notif-row.is-unread .ph-menu-row-title { color: color-mix(in srgb, var(--gold-8) 23%, var(--mix-light)); }

/* ─── Avatar / account card ─────────────────────────────────────────── */
.ph-account-card {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px;
}
.ph-initials-lg {
  width: 38px; height: 38px;
  font-size: var(--fs-14);
}
.ph-account-text { min-width: 0; }
.ph-account-name {
  font-size: var(--fs-13);
  font-weight: var(--fw-semi);
  color: var(--ink-on-dark);
}
.ph-account-mail {
  font-size: var(--fs-11-5);
  color: var(--ink-on-dark-muted);
  margin-top: 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ─── Project switcher (inline expanding panel) ─────────────────────── */

.ph-project {
  position: relative;
  /* v07g/v07h/v07i/v07j/v07k/v07l — Hugo wanted the project panel
     BIG and left-aligned with panels below. Negative left margin
     -16 (close-to-edge look). 20% right margin so the right edge
     of the panel (and the SWITCH-TO dropdown) sits well clear of
     the top-right icons. Top margin -4 so the panel sits ~8px from
     the back-panel top. Asymmetric padding (14 top / 4 bottom) so
     the title has breathing room from the top without pushing the
     topbar down. */
  padding: 14px 16px 4px;
  margin: -4px 20% 0 -16px;
  border-radius: 22px;
  background: transparent;
  border: 1px solid transparent;
  box-shadow: none;
  /* 17 Sep 2026 - the glass eases with the panel's height (below), on the same speed and curve,
     blur included (it used to vanish in one frame when the picker closed). --ph-picker-curve is
     the CLOSE curve here and the OPEN curve on .is-open: a transition takes the curve of the state
     it goes to, so every part of the picker below reads this one variable. */
  --ph-picker-curve: var(--ph-picker-ease-close);
  transition:
    background var(--ph-picker-dur) var(--ph-picker-curve),
    border-color var(--ph-picker-dur) var(--ph-picker-curve),
    box-shadow var(--ph-picker-dur) var(--ph-picker-curve),
    backdrop-filter var(--ph-picker-dur) var(--ph-picker-curve),
    -webkit-backdrop-filter var(--ph-picker-dur) var(--ph-picker-curve);
  z-index: 50;
  max-width: calc(100% + 16px);
}
.ph-project.is-open {
  --ph-picker-curve: var(--ph-picker-ease-open);
  background: color-mix(in srgb, var(--shade-16) 78%, transparent);
  backdrop-filter: blur(var(--glass-blur)) saturate(1.05);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(1.05);
  border-color: color-mix(in srgb, var(--card-border) 32%, transparent);
  box-shadow:
    0 32px 60px rgba(0,0,0,0.48),
    0 12px 24px rgba(0,0,0,0.28),
    inset 0 1px 0 rgba(255,255,255,0.06);
  /* v07f — dropped the v05n margin-bottom:-80px overlap. The panel
     now pushes the TopBar (and everything below) down with the same
     12px gap as every other sibling panel in .main-content. */
  z-index: var(--z-sticky);
}

/* The active title gets a fade-up keyframe whenever the active project changes. */
.ph-project .ph-title {
  animation: ph-title-promote 360ms var(--ease-glide);
}
.ph-project .ph-meta {
  animation: ph-meta-fade 360ms var(--ease-glide);
}
/* 17 Sep 2026 - a logo that is not decoded yet holds its exact place, invisible, and its entrance
   waits for the real image (ProjectHeader.jsx), so a switch changes the title once. */
.ph-project .ph-title.is-pending {
  visibility: hidden;
  animation: none;
}
/* 17 Sep 2026 - the subtitle line of a project whose episode list has not arrived yet: it keeps its
   height, invisible, and fades in once, complete (its episode label used to pop in on its own). */
.ph-project .ph-meta.is-pending {
  visibility: hidden;
  animation: none;
}
/* a logo never seen in this browser (its width is not known yet): the caret waits with it */
.ph-project .ph-title-row.is-sizing .ph-caret {
  visibility: hidden;
}
@keyframes ph-title-promote {
  from { opacity: 0; transform: translateY(14px); letter-spacing: var(--track-02); }
  to   { opacity: 1; transform: translateY(0);     letter-spacing: var(--track-005); }
}
@keyframes ph-meta-fade {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Caret rotates when the panel is open */
.ph-caret.is-open svg { transform: rotate(180deg); }
.ph-caret svg { transition: transform var(--ph-picker-dur) var(--ph-picker-curve, var(--ph-picker-ease-open)); }
/* the caret's box tints and rims with the panel too (its rim used to snap in the first frame) */
.ph-project .ph-caret {
  transition:
    background var(--ph-picker-dur) var(--ph-picker-curve),
    border-color var(--ph-picker-dur) var(--ph-picker-curve);
}

/* The "SWITCH TO" picker — opens/closes with the grid-rows trick.
   17 Sep 2026 - Hugo: "when I close the project picker, the Switch To text jumps up". The gap above
   the picker (14px), its rule (1px) and the gap under the rule (12px) were only applied while open
   and are not animatable the way they were set, so on close the label and every row snapped up 27px
   in the first frame while the height was still easing, and on open the panel grew 27px at once.
   Now those gaps belong to the label, INSIDE the clipped box, in both states: only the row height
   moves. The label and the cards fade with it, on the panel's own speed and curve (the label
   stays put and the panel edge closes over it), and they turn invisible (so Tab cannot reach
   them) only once the panel has shut. A closing picker takes no clicks: a second click of a
   double-click would otherwise land on a fading card. */
.ph-project-others {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--ph-picker-dur) var(--ph-picker-curve);
}
.ph-project-others-inner {
  overflow: hidden;
  min-height: 0;
  visibility: hidden;
  pointer-events: none;
  transition: visibility 0s linear var(--ph-picker-dur);
}
.ph-project.is-open .ph-project-others {
  grid-template-rows: 1fr;
}
.ph-project.is-open .ph-project-others-inner {
  visibility: visible;
  pointer-events: auto;
  transition-delay: 0s;
}
.ph-project-others-head,
.ph-project-strip {
  opacity: 0;
  transform: translateY(calc(-1 * var(--ph-proj-slide)));
  transition:
    opacity var(--ph-picker-dur) var(--ph-picker-curve),
    transform var(--ph-picker-dur) var(--ph-picker-curve);
}
.ph-project.is-open :is(.ph-project-others-head, .ph-project-strip) {
  opacity: 1;
  transform: none;
}

.ph-project-others-head {
  font-size: var(--fs-10);
  letter-spacing: var(--track-18);
  font-weight: var(--fw-bold);
  color: var(--ink-on-dark-muted);
  margin: var(--ph-proj-open-gap) 0 var(--ph-proj-head-gap);
  padding-top: var(--ph-proj-rule-gap);
  border-top: var(--hairline-w) solid color-mix(in srgb, var(--card-border) 18%, transparent);
  text-transform: uppercase;
}

/* 17 Sep 2026 - ONE row of small cards that scrolls sideways (a vertical wheel scrolls it too,
   ProjectHeader.jsx). The row has a FIXED height - card + hover room + scrollbar gutter - so the
   panel is the same height whether the scrollbar is there or not, for 2 projects or 50. */
.ph-project-strip {
  display: flex;
  flex-wrap: nowrap;
  align-items: flex-start;
  gap: var(--ph-proj-card-gap);
  box-sizing: border-box;
  height: calc(var(--ph-proj-card-lift) + var(--ph-proj-card-h) + var(--ph-proj-strip-gutter));
  padding-top: var(--ph-proj-card-lift);
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  scrollbar-width: thin;
  scrollbar-color: color-mix(in srgb, var(--card-border) 30%, transparent) transparent;
}

/* one project card: same paint as the old list rows, a fixed box, the tag pinned to the bottom.
   The fill and rim are variables declared ON the card, so a skin family re-points them here
   (skin-glass.css): the glass family's --card-border is already a faint line, and mixing it down
   again left the cards with no visible edge. */
.ph-project-other {
  --ph-card-fill: color-mix(in srgb, var(--mix-light) 3%, transparent);
  --ph-card-line: color-mix(in srgb, var(--card-border) 14%, transparent);
  --ph-card-fill-hover: color-mix(in srgb, var(--mix-light) 7%, transparent);
  --ph-card-line-hover: color-mix(in srgb, var(--card-border) 32%, transparent);
  flex: 0 0 var(--ph-proj-card-w);
  width: var(--ph-proj-card-w);
  height: var(--ph-proj-card-h);
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-start;
  padding: var(--ph-proj-card-pad-y) var(--ph-proj-card-pad-x);
  background: var(--ph-card-fill);
  border: var(--hairline-w) solid var(--ph-card-line);
  border-radius: var(--ph-proj-card-r);
  color: var(--ink-on-dark);
  cursor: pointer;
  text-align: left;
  margin: 0;
  overflow: hidden;
  transition:
    background var(--dur-1) ease,
    border-color var(--dur-1) ease,
    transform var(--dur-1) ease;
}
.ph-project-other:hover {
  background: var(--ph-card-fill-hover);
  border-color: var(--ph-card-line-hover);
  transform: translateY(calc(-1 * var(--ph-proj-card-lift)));
}
.ph-project-other:active { transform: translateY(0); }
/* the ring sits just inside the card, so the scrolling row cannot crop it */
.ph-project-other:focus-visible {
  outline: var(--ring-w) solid var(--leaf);
  outline-offset: calc(-1 * var(--ring-w));
}
.ph-project-other-text { flex: 0 0 auto; width: 100%; min-width: 0; }
.ph-project-other-name {
  font-family: var(--font-display);
  font-size: var(--fs-22);
  letter-spacing: var(--track-005);
  color: var(--ink-on-dark);
  line-height: 1.05;
  white-space: nowrap;
  /* cut sideways only (for the "..."): the box is one tight line, and a hidden overflow sliced the
     accents off TRØPÉ. The card's own padding holds the letters that reach above and below. */
  overflow-x: clip;
  overflow-y: visible;
  text-overflow: ellipsis;
}
.ph-project-other-sub {
  font-size: var(--fs-12);
  color: var(--ink-on-dark-muted);
  margin-top: var(--ph-proj-card-line-gap);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ph-project-other-status {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 11px;
  border-radius: var(--r-pill);
  border: 1px solid currentColor;
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--mix-light) 14%, transparent) 0%,
    color-mix(in srgb, var(--black) 12%, transparent) 100%);
  font-size: var(--fs-10);
  font-weight: var(--fw-bold);
  letter-spacing: var(--track-12);
  flex-shrink: 0;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.28),
    inset 0 -1px 0 rgba(0, 0, 0, 0.18),
    0 1px 2px rgba(0, 0, 0, 0.22);
  text-shadow: 0 1px 1px rgba(0, 0, 0, 0.30);
}
/* 16 Sep 2026 - the project STATUS TAG paints here, through tokens. ProjectHeader.jsx used to
   type the fill, rim, text and dot colours inline, and an inline style beats every skin, so the
   tag stayed the project row's own colour (magenta) under any skin. The JSX now passes only the
   row's colour, as --project-accent; a skin family may re-point any --stag-* part (skin-glass.css).
   These formulas are the old inline ones, so Paradise Found paints the same. They are declared
   on the tag itself because --project-accent only exists there. */
.ph-status-pill,
.ph-project-other-status {
  --stag-accent: var(--project-accent, var(--status-accent));
  --stag-fill-mix: var(--status-pill-fill-mix);
  --stag-line-mix: var(--status-pill-line-mix);
  --stag-fill: color-mix(in oklab, var(--stag-accent) var(--stag-fill-mix), transparent);
  --stag-line: color-mix(in oklab, var(--stag-accent) var(--stag-line-mix), transparent);
  --stag-ink: var(--stag-accent);
  --stag-dot: var(--stag-accent);
  --stag-glow: var(--stag-accent);
  background: var(--stag-fill);
  border-color: var(--stag-line);
  color: var(--stag-ink);
}
.ph-project-other-status {
  --stag-fill-mix: var(--status-list-fill-mix);
  --stag-line-mix: var(--status-list-line-mix);
}
.ph-status-pill .ph-pill-dot { background: var(--stag-dot); box-shadow: 0 0 6px var(--stag-glow); }
.ph-project-other-status .ph-pill-dot { background: var(--stag-dot); }
/* on a card the tag sits on the bottom edge, whatever the subtitle holds; a long status ends in
   "..." inside the tag (the dot keeps its size) instead of running through the tag's rim */
.ph-project-other > .ph-project-other-status {
  margin-top: auto;
  max-width: 100%;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
}
.ph-project-other-status .ph-pill-dot { flex-shrink: 0; }
.ph-project-other-status-text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* "New project" and "Import shotlist": two cards of the same size at the end of the row */
.ph-project-new {
  --ph-card-fill: color-mix(in srgb, var(--mix-light) 2%, transparent);
  --ph-card-line: color-mix(in srgb, var(--card-border) 28%, transparent);
  --ph-card-fill-hover: color-mix(in srgb, var(--mix-light) 6%, transparent);
  align-items: center;
  justify-content: center;
  gap: var(--ph-proj-card-line-gap);
  text-align: center;
  font-family: var(--font-body);
  font-size: var(--fs-12-5);
  font-weight: var(--fw-med);
  letter-spacing: var(--track-04);
  color: var(--ink-on-dark-muted);
  border-style: dashed;
}
.ph-project-new:hover {
  color: var(--ink-on-dark);
}
.ph-project-new-label {
  max-width: 100%;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}

/* ─── Search pill (inline expanding to the left) ────────────────────── */

.ph-search-anchor {
  position: relative;
  width: 40px;
  height: 40px;
  flex-shrink: 0;
}
.ph-search-pill {
  position: absolute;
  top: 0;
  right: 0;
  height: 40px;
  width: 40px;
  display: flex;
  align-items: center;
  border-radius: var(--r-round);
  background:
    radial-gradient(circle at 30% 28%, color-mix(in srgb, var(--cream-5) 22%, transparent), color-mix(in srgb, var(--cream-5) 4%, transparent) 75%),
    color-mix(in srgb, var(--shade-5) 4%, transparent);
  backdrop-filter: blur(14px) saturate(1.30);
  -webkit-backdrop-filter: blur(14px) saturate(1.30);
  border: none;
  overflow: hidden;
  box-shadow:
    inset 1px 1px 2px color-mix(in srgb, var(--hi) 35%, transparent),
    inset -1px -1px 2px rgba(0, 0, 0, 0.18),
    inset 0 0 12px color-mix(in srgb, var(--hi) 10%, transparent),
    0 1px 2px rgba(0, 0, 0, 0.16),
    0 6px 16px rgba(0, 0, 0, 0.22);
  transition: width var(--dur-5) var(--ease-glide), background 160ms ease, box-shadow 160ms ease, border-radius var(--dur-5) ease;
  z-index: 5;
}
.ph-search-pill.is-open { border-radius: 22px; }
/* (anchor ring removed — the pill itself owns its glass styling) */
.ph-search-pill.is-open {
  width: 320px;
  background: color-mix(in srgb, var(--shade-17) 55%, transparent);
  border: none;
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--hi) 32%, transparent),
    inset 1px 0 0 color-mix(in srgb, var(--hi-2) 16%, transparent),
    inset 0 -1px 0 rgba(0, 0, 0, 0.22),
    0 14px 30px rgba(0,0,0,0.34);
  cursor: text !important;
}
.ph-search-anchor.is-open,
.ph-search-anchor.is-open *,
.ph-search-pill.is-open,
.ph-search-pill.is-open *,
.ph-search-pill.is-open .ph-search-iconbtn,
.ph-search-pill.is-open .ph-search-iconbtn:hover,
.ph-search-pill.is-open .ph-search-input-inline { cursor: text !important; }
.ph-search-input-inline {
  flex: 1;
  min-width: 0;
  background: transparent;
  border: none;
  outline: none;
  color: var(--ink-on-dark);
  font-family: var(--font-body);
  font-size: var(--fs-13);
  padding: 0 6px 0 16px;
  caret-color: var(--leaf);
  /* fade in slightly after the pill expands */
  animation: ph-search-input-fade var(--dur-4) ease 80ms both;
}
.ph-search-input-inline::placeholder { color: var(--ink-on-dark-muted); }
@keyframes ph-search-input-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.ph-search-clear-inline {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--mix-light) 6%, transparent);
  border: none;
  color: var(--ink-on-dark-muted);
  display: grid; place-items: center;
  cursor: pointer;
  margin-right: 4px;
  flex-shrink: 0;
}
.ph-search-clear-inline:hover { background: color-mix(in srgb, var(--mix-light) 12%, transparent); color: var(--ink-on-dark); }
.ph-search-iconbtn {
  width: 40px;
  height: 40px;
  flex-shrink: 0;
  background: none;
  border: none;
  color: var(--ink-on-dark);
  display: grid; place-items: center;
  cursor: pointer;
  border-radius: var(--r-md);
  transition: background var(--dur-1) ease;
}
.ph-search-iconbtn:hover { background: color-mix(in srgb, var(--mix-light) 6%, transparent); }
.ph-search-pill.is-open .ph-search-iconbtn { color: var(--ink-on-dark-muted); }

.ph-search-results-pop {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 60;
  width: 360px;
  padding: 8px;
  background: color-mix(in srgb, var(--shade-16) 96%, transparent);
  backdrop-filter: blur(var(--glass-blur)) saturate(1.05);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(1.05);
  border: 1px solid color-mix(in srgb, var(--card-border) 32%, transparent);
  border-radius: var(--r-md);
  box-shadow:
    0 18px 40px rgba(0,0,0,0.35),
    0 2px 6px rgba(0,0,0,0.20),
    inset 0 1px 0 rgba(255,255,255,0.06);
  color: var(--ink-on-dark);
  max-height: 400px;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: color-mix(in srgb, var(--card-border) 30%, transparent) transparent;
  animation: ph-menu-in var(--dur-2) var(--ease-glide);
  transform-origin: top right;
}
.ph-search-results-pop::-webkit-scrollbar { width: 6px; }
.ph-search-results-pop::-webkit-scrollbar-thumb { background: color-mix(in srgb, var(--card-border) 25%, transparent); border-radius: 3px; }

/* ─── t07 — Episode switcher ─────────────────────────────────────── */
.ph-episode {
  position: relative;
  margin-left: 18px;
  align-self: flex-end;
  /* keeps the episode pill aligned with the bottom of the project title */
  padding-bottom: 4px;
}
/* Hugo fix — compact variant lives inside .ph-meta (the subtitle row),
   which is its own align-items:center flex. Drop the flex-end +
   padding-bottom + margin-left baked in for the full-mode placement
   so the compact pill sits on the same baseline as 'Nature documentary'
   and the IN PRODUCTION pill. */
.ph-meta .ph-episode--compact {
  margin-left: 0;
  align-self: center;
  padding-bottom: 0;
}
.ph-episode-pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px 6px 12px;
  background: color-mix(in srgb, var(--cream) 45%, transparent);
  border: 1px solid var(--card-border);
  border-radius: var(--r-round);
  cursor: pointer;
  color: var(--ink);
  font-family: var(--font-body);
  transition: background var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease;
}
.ph-episode-pill:hover { background: color-mix(in srgb, var(--cream) 65%, transparent); }
.ph-episode-pill.is-open {
  background: color-mix(in srgb, var(--cream) 85%, transparent);
  border-color: color-mix(in srgb, var(--tan-deep) 55%, transparent);
  box-shadow: 0 2px 6px color-mix(in srgb, var(--shadow-ink) 10%, transparent);
}
.ph-episode-eyebrow {
  font-size: var(--fs-9-5);
  font-weight: var(--fw-bold);
  letter-spacing: var(--track-12);
  text-transform: uppercase;
  color: var(--ink-muted);
  padding: 2px 6px;
  border-radius: var(--r-round);
  background: color-mix(in srgb, var(--tan-deep) 10%, transparent);
}
.ph-episode-name {
  font-size: var(--fs-12-5);
  font-weight: var(--fw-semi);
  letter-spacing: var(--track-02);
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ph-episode-caret {
  display: inline-flex;
  align-items: center;
  color: var(--ink-muted);
  transition: transform 160ms ease;
}
.ph-episode-caret.is-open { transform: rotate(180deg); }

.ph-episode-menu {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: var(--z-header-menu);
  min-width: 280px;
  padding: 6px;
  border-radius: var(--r-md);
  background: color-mix(in srgb, var(--cream-2) 98%, transparent);
  border: 1px solid var(--card-border);
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--cream) 85%, transparent),
    0 8px 22px color-mix(in srgb, var(--shadow-ink) 20%, transparent),
    0 14px 32px color-mix(in srgb, var(--shade) 18%, transparent);
  display: flex;
  flex-direction: column;
  gap: 1px;
  animation: ph-menu-in var(--dur-2) var(--ease-glide);
  transform-origin: top left;
}
.ph-episode-menu .ph-menu-eyebrow {
  padding: 6px 10px 4px;
}
.ph-episode-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
}
.ph-episode-row.is-active { background: color-mix(in srgb, var(--leaf) 14%, transparent); }
.ph-episode-num {
  font-family: var(--font-display);
  font-size: var(--fs-14);
  letter-spacing: var(--track-05);
  color: var(--ink-muted);
  min-width: 38px;
}
.ph-episode-row .ph-menu-row-title { font-size: var(--fs-12-5); font-weight: var(--fw-semi); }
.ph-episode-row .ph-menu-row-sub { font-size: var(--fs-10-5); color: var(--ink-muted); text-transform: uppercase; letter-spacing: var(--track-06); }
.ph-episode-check { color: var(--olive-3); display: inline-flex; }

.ph-episode-new {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  color: var(--ink);
  font-weight: var(--fw-semi);
  font-size: var(--fs-12);
}
.ph-episode-new:hover { background: color-mix(in srgb, var(--tan-deep) 10%, transparent); }
.ph-episode-new-form {
  display: flex;
  gap: 6px;
  padding: 6px 8px 8px;
}
.ph-episode-new-input {
  flex: 1;
  font: inherit;
  font-family: var(--font-body);
  font-size: var(--fs-12);
  color: var(--ink);
  background: color-mix(in srgb, var(--cream) 55%, transparent);
  border: 1px solid var(--card-border);
  border-radius: var(--r-xs);
  padding: 6px 8px;
  outline: none;
}
.ph-episode-new-input:focus {
  border-color: color-mix(in srgb, var(--leaf) 70%, transparent);
  box-shadow: 0 0 0 var(--ring-w) color-mix(in srgb, var(--leaf) 15%, transparent);
}
.ph-episode-new-submit {
  font: inherit;
  font-family: var(--font-body);
  font-size: var(--fs-11-5);
  font-weight: var(--fw-semi);
  letter-spacing: var(--track-04);
  padding: 4px 12px;
  border-radius: var(--r-pill);
  border: 1px solid color-mix(in srgb, var(--olive-2) 85%, transparent);
  background: color-mix(in srgb, var(--leaf) 85%, transparent);
  color: var(--ink-cream);
  cursor: pointer;
  transition: background var(--dur-1) ease;
}
.ph-episode-new-submit:hover { background: color-mix(in srgb, var(--olive-2) 95%, transparent); }

/* ─── t06c — inline (compact) episode switcher ──────────────────────
   When EpisodeSwitcher is rendered inside the project subtitle line
   (.ph-meta), drop the surrounding pill — render the title + caret
   as flowing inline text so the line reads naturally. */
.ph-episode--compact {
  display: inline-flex;
  align-items: center;
  margin: 0;
  padding: 0;
  vertical-align: middle;
  position: relative;          /* dropdown menu still anchors to this */
}
.ph-episode-pill--compact {
  background: transparent;
  border: none;
  padding: 0;
  border-radius: 0;
  box-shadow: none;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-family: var(--font-body);
  color: var(--ink);
  font-size: var(--fs-12-5);
  font-weight: var(--fw-semi);
  cursor: pointer;
  transition: color var(--dur-2) ease;
}
.ph-episode-pill--compact:hover { color: var(--ink-strong); }
.ph-episode-pill--compact:hover,
.ph-episode-pill--compact.is-open { background: transparent; }
.ph-episode-pill--compact .ph-episode-name {
  max-width: 320px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  letter-spacing: var(--track-02);
  /* v04a — match the muted cream/grey of the genre subtitle. */
  color: var(--ink-on-dark-muted);
  font-size: var(--fs-13);
  font-weight: var(--fw-med);
}
.ph-episode-pill--compact .ph-episode-caret {
  display: inline-flex;
  align-items: center;
  color: var(--ink-muted);
  transform: scale(0.85);
  transition: transform 160ms ease;
}
.ph-episode-pill--compact .ph-episode-caret.is-open { transform: scale(0.85) rotate(180deg); }

/* Subtitle separator dot between project type and episode name. */
.ph-meta-sep {
  display: inline-block;
  margin: 0 6px;
  color: var(--ink-soft);
  font-weight: 400;
}

/* v01b — Expanded new-episode form. Original .ph-episode-new-form was a
   single-field horizontal flex; the v01b prompt requires 3 fields
   (title, episode number, description). New rules below stack the form
   vertically without touching the original .ph-episode-new-form rule. */
.ph-episode-menu .ph-episode-new-form {
  flex-direction: column;
  gap: 8px;
  padding: 8px 10px 10px;
}
.ph-episode-new-field {
  display: flex; flex-direction: column;
  gap: 3px;
}
.ph-episode-new-label {
  font-size: var(--fs-10);
  font-weight: var(--fw-bold);
  letter-spacing: var(--track-10);
  text-transform: uppercase;
  color: var(--ink-muted);
}
.ph-episode-new-input.ph-episode-new-num {
  flex: 0 0 auto;
  width: 80px;
}
.ph-episode-new-input.ph-episode-new-desc {
  font-family: inherit;
  resize: vertical;
  min-height: 36px;
}
.ph-episode-new-actions {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  margin-top: 2px;
}
.ph-episode-new-cancel {
  font: inherit;
  font-family: var(--font-body);
  font-size: var(--fs-11-5);
  font-weight: var(--fw-med);
  letter-spacing: var(--track-04);
  padding: 4px 12px;
  border-radius: var(--r-pill);
  border: 1px solid var(--card-border);
  background: color-mix(in srgb, var(--cream) 40%, transparent);
  color: var(--ink-muted);
  cursor: pointer;
  transition: background var(--dur-1) ease;
}
.ph-episode-new-cancel:hover { background: color-mix(in srgb, var(--cream) 70%, transparent); }
.ph-episode-new-submit:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* v07zz175 — Online pill in the project-meta row, right after the status pill.
   Mirrors the TopBar "N ONLINE" pill (pill + hover-slide avatars). Fades in on
   every page EXCEPT Overview (where the TopBar already shows it). The wrapper
   collapses to 0 width when hidden so the meta row never shifts. */
.ph-online {
  display: inline-flex;
  align-items: center;
  max-width: 0;
  margin-left: 0;
  opacity: 0;
  overflow: hidden;          /* clipped only while hidden */
  pointer-events: none;
  vertical-align: middle;
  /* v07zz38 — never let the crowded meta row squeeze this pill: a shrunk
     wrapper compressed the slid-out avatar strip and overflow:hidden shaved
     it off (the "cropped on hover" bug). The meta row wraps instead. */
  flex-shrink: 0;
  transition: opacity var(--dur-5) ease, max-width var(--dur-6) ease, margin var(--dur-5) ease;
}
.ph-online.is-visible {
  max-width: 420px;          /* room for the pill + slid-out avatars */
  margin-left: 8px;
  opacity: 1;
  pointer-events: auto;
  overflow: visible;         /* v07zz177 — was clipping the pill's right edge */
}
/* v07zz177 — EXACTLY matches .ph-status-pill (the IN PRODUCTION pill) so they
   read as a pair, but solid green with white text per Hugo. Same padding / gap /
   font-size / letter-spacing / radius as that pill. */
.ph-online-pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  flex-shrink: 0;
  padding: 5px 12px 5px 10px;
  border-radius: var(--r-pill);
  border: 1px solid var(--olive-7);
  background: var(--olive-7);
  color: var(--ink-cream);
  font-size: var(--fs-10-5);
  font-weight: var(--fw-bold);
  letter-spacing: var(--track-12);
  white-space: nowrap;
  position: relative;
  z-index: 2;
}
.ph-online-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--cream);
  box-shadow: 0 0 5px rgba(255, 255, 255, 0.5);
  flex-shrink: 0;
}
.ph-online-label { line-height: 1; }
/* Avatars hidden behind the pill; slide out to the right on hover. */
.ph-online-avatars {
  display: inline-flex;
  align-items: center;
  gap: 5px;                   /* v07zz39 — clear spacing between avatars (the old -7px overlap read as "too close") */
  max-width: 0;
  margin-left: -8px;          /* tuck behind the pill's rounded end while collapsed */
  overflow: hidden;
  flex-shrink: 0;
  opacity: 0;
  transition: max-width var(--dur-6) ease, margin-left var(--dur-6) ease, opacity 200ms ease;
}
.ph-online:hover .ph-online-avatars {
  max-width: 360px;
  margin-left: 9px;           /* clear gap from the pill, not tucked under it */
  overflow: visible;          /* v07zz39 — once revealed, never clip the avatars */
  opacity: 1;
  padding-right: 4px;         /* breathing room past the last avatar */
}
.ph-online-avatar {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  margin-left: 0;             /* v07zz39 — spacing now handled by the container gap */
  display: grid;
  place-items: center;
  font-size: var(--fs-8-5);
  font-weight: var(--fw-bold);
  letter-spacing: var(--track-02);
  color: var(--ink-cream);
  background: var(--olive-8);
  border: 2px solid var(--panel-cream);
  box-shadow: inset 0 0 0 var(--hairline-w) rgba(0, 0, 0, 0.12);
  flex-shrink: 0;
}
.ph-online-avatar.is-me { background: var(--olive-7); }

/* ── v07zz283 — ScalePill: always-visible App-scale control ────────────
   Sits first in the .ph-right icon cluster. The button shows the LIVE
   effective percentage in the app's mono; the popover mirrors the bell/
   avatar cream-glass language. Same option set as Settings → App scale. */
.ph-scale-anchor { position: relative; }
/* A stretched circle reads as a squashed egg next to the round icon
   buttons — the scale control is a ROUNDED SQUARE instead (same corner
   language as the mobile hamburger), clearly a "readout", not an icon. */
.ph-scale-btn {
  width: auto;
  min-width: 0;
  padding: 0 10px;
  border-radius: var(--r-md);
  font-family: var(--font-mono);
}
.ph-scale-val {
  font-size: var(--fs-11-5);
  font-weight: var(--fw-semi);
  letter-spacing: var(--track-01);
  color: inherit;
  white-space: nowrap;
}
.ph-scale-val i { font-style: normal; opacity: 0.55; font-size: var(--fs-9-5); margin-left: 1px; }
.ph-scale-pop {
  position: absolute;
  top: calc(100% + 10px);
  right: 0;
  z-index: var(--z-header-pop);
  min-width: 196px;
  padding: 8px;
  border-radius: var(--r-card);
  background: color-mix(in srgb, var(--cream-5) 96%, transparent);
  border: 1px solid color-mix(in srgb, var(--card-border) 55%, transparent);
  box-shadow: 0 18px 48px color-mix(in srgb, var(--shade-11) 38%, transparent), inset 0 1px 0 color-mix(in srgb, var(--cream) 80%, transparent);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  animation: phScalePop var(--dur-2) var(--ease-glide);
}
@keyframes phScalePop { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
.ph-scale-pop-head {
  font-size: var(--fs-10); font-weight: var(--fw-heavy); letter-spacing: var(--track-18);
  color: var(--ink-muted); padding: 6px 10px 8px;
}
.ph-scale-opt {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  width: 100%; padding: 8px 10px; border: 0; border-radius: var(--r-9);
  background: transparent; cursor: pointer; text-align: left;
  font: inherit; font-size: var(--fs-13); font-weight: var(--fw-semi); color: var(--ink);
  transition: background 110ms ease;
}
.ph-scale-opt:hover { background: color-mix(in srgb, var(--olive) 12%, transparent); }
.ph-scale-opt.is-active { background: color-mix(in srgb, var(--olive) 16%, transparent); }
.ph-scale-opt-hint { font-style: normal; font-weight: var(--fw-med); font-size: var(--fs-11-5); color: var(--ink-muted); }
.ph-scale-tick { width: 16px; text-align: right; color: var(--ink-moss); font-weight: var(--fw-heavy); }

/* 17 Sep 2026 - StylePill: the Overview's skin switcher (ProjectHeader.jsx). It reuses the App-scale
   popover and rows; only the width and the swatch strip are its own. */
.ph-style-pop { min-width: var(--ph-style-pop-w); }
.ph-style-opt { justify-content: flex-start; }
.ph-style-swatches { display: inline-flex; gap: var(--ph-style-swatch-gap); flex: 0 0 auto; margin: 0; }
.ph-style-opt .ph-style-swatch { width: var(--ph-style-swatch); height: var(--ph-style-swatch); }
.ph-style-name { flex: 1 1 auto; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* 15 Sep 2026 — the project's wordmark in place of its name (Hugo: "put the trope logo at the
   top instead of the TROPE text"). The <img> takes the h1's exact line box (font-size × line
   height), so the pills below never move. */
.ph-title--logo {
  display: block;
  height: calc(clamp(58px, 7vw, 96px) * 0.96);
  width: auto;
  max-width: min(60vw, 620px);
  object-fit: contain;
  object-position: left center;
  margin: 0;
}
