/*
 * Brand accent variables below map onto the shared token file
 * (/design-tokens.css, linked in index.html before this stylesheet) per
 * memory/Yeja_AI_Master_Design_Guide_20260704.md. These used to be hardcoded
 * to pure black/white (design-guide-audit 2026-07-05 flagged this as the
 * platform shell's worst compliance gap — it should be the flagship
 * compliant surface). --rust/--olive/--blue/--gold are legacy names kept so
 * existing rules referencing them don't break; they now resolve to the
 * guide's real accents instead of monochrome.
 *
 * Full compliance pass 2026-07-07: --rail-collapsed and --topbar-height were
 * still wrong (80px/72px vs. the guide's real 68px/64px — Master Design
 * Guide §3 "Global Navigation Shell Dimensions"), and apps/platform/
 * shell-styles.css duplicated this exact same wrong block. Since
 * shell-styles.css loads BEFORE this file in index.html, this file's
 * declarations always won the cascade — meaning a fix applied only to
 * shell-styles.css would have had zero visible effect. Confirmed
 * shell-styles.css has no selector this file doesn't already have (full
 * diff), then deleted it entirely rather than maintain two files that must
 * stay byte-identical or silently diverge again.
 *
 * Phase 2 fix (2026-07-13, v2026.3 design-guide rollout): the
 * html[data-theme="dark"] block below had NO var() wrapper on --ink/
 * --muted/--paper/--surface/--surface-alt/--line/--charcoal — it hard-
 * overrode them with literal, stale old-palette hex values (#121212,
 * #333333, etc.), completely defeating Phase 1's design-tokens.css
 * retokening for the shell specifically whenever dark mode was active.
 * Every other app reads --yeja-canvas/--yeja-text-primary/etc. straight
 * from design-tokens.css with no local override, so they picked up the
 * new warm ramp automatically in Phase 1 — the shell did not, because of
 * this block. Now wrapped in var(--yeja-*, ...) fallbacks matching the
 * :root block's own pattern, so the shell's dark mode tracks
 * design-tokens.css/an active theme same as every other surface. Also
 * fixed --charcoal's :root fallback chain, which referenced the now-
 * deleted --yeja-n900 (removed in Phase 1's warm-ramp retokening,
 * replaced by --yeja-gray-*) — it was silently always falling through to
 * its hardcoded #121212 fallback instead of ever resolving via the token
 * system; now points at --yeja-gray-1000.
 */
:root {
  --ink: var(--yeja-text-primary, #0D0D0D);
  --muted: var(--yeja-text-muted, #5A5A5A);
  --paper: var(--yeja-canvas, #FCFBFA);
  --surface: var(--yeja-canvas, #FCFBFA);
  --surface-alt: var(--yeja-sidebar, #FFFFFF);
  --line: var(--yeja-border, #DEDEDE);
  --charcoal: var(--yeja-gray-1000, #0D0D0D);
  --rust: var(--yeja-crimson, #E53935);
  --olive: var(--yeja-mint, #43A047);
  --blue: var(--yeja-cobalt, #1E88E5);
  --gold: var(--yeja-amber, #FFB300);
  --accent: var(--yeja-cobalt, #1E88E5);
  --rail-width: var(--shell-sidebar-width, 260px);
  --rail-collapsed: var(--shell-sidebar-collapsed, 68px);
  --topbar-height: var(--shell-header-height, 64px);
  color-scheme: light;
}

html[data-theme="dark"] {
  --ink: var(--yeja-text-primary, #FFFFFF);
  --muted: var(--yeja-text-muted, #ADADAD);
  --paper: var(--yeja-canvas, #0D0D0D);
  --surface: var(--yeja-canvas, #0D0D0D);
  --surface-alt: var(--yeja-sidebar, #212020);
  --line: var(--yeja-border, #242424);
  --charcoal: var(--yeja-gray-0, #FFFFFF);
  --rust: var(--yeja-crimson, #E53935);
  --olive: var(--yeja-mint, #43A047);
  --blue: var(--yeja-cobalt, #1E88E5);
  --gold: var(--yeja-amber, #FFB300);
  --accent: var(--yeja-cobalt, #1E88E5);
  color-scheme: dark;
}

* {
  box-sizing: border-box;
}

html {
  min-height: 100%;
}

body {
  min-height: 100%;
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-family-base, "Inter", system-ui, sans-serif);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

a {
  color: inherit;
  text-decoration: none;
}

button,
input,
select,
textarea {
  font: inherit;
}

/*
 * Compliance pass 2026-07-07: this file's real layout wrapper is
 * .master-layout (toggled via classList.toggle("collapsed") in
 * shell-module-federation.js and matched by class="master-layout" in
 * index.html), NOT .app-shell/.rail-collapsed — those were dead,
 * unreferenced selectors from an earlier shell iteration, styled instead by
 * a duplicate inline <style> block in index.html with its own separate,
 * wrong hardcoded values (260px/64px, using --bg/--bg-secondary variables
 * that don't exist anywhere in the token system). Moved the real rule here
 * (using the correct §3 tokens) and removed the inline block + the dead
 * .app-shell selectors, so there is exactly one place this layout is
 * defined.
 */
/*
 * Shell breakout (2026-07-14): the left-rail app switcher is gone —
 * .master-layout is now a single-column stack (topbar row, then the
 * workspace row) instead of the old two-column rail+workspace grid.
 * --rail-width/--rail-collapsed tokens are no longer consumed here (kept
 * declared in :root above only in case a saved custom theme still
 * references them via platform-theme.js's MANAGED_PROPERTIES — see that
 * file's own comment on why removing a still-possibly-referenced token
 * outright is riskier than just letting it go unused).
 */
.master-layout {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

/*
 * Brand mark — replicated directly from apps/experimental/styles.css's
 * real .topnav__logo-mark (20px, not the old rail's 30px — the guide's
 * §1 description was implemented at the rail's larger size before this
 * fix; Experimental's actual, canonical value is 20px). Four real brand
 * accents (Crimson primary / Cobalt secondary / Amber tertiary / Mint
 * quaternary — Master Design Guide §1).
 */
.brand-mark {
  width: 20px;
  height: 20px;
  flex: 0 0 20px;
  border: 2px solid var(--yeja-crimson, #E53935);
  border-radius: 50%;
  box-shadow:
    4px 0 0 -1.4px var(--yeja-cobalt, #1E88E5),
    -2.6px 3.3px 0 -1.4px var(--yeja-amber, #FFB300),
    1.3px -3.3px 0 -1.4px var(--yeja-mint, #43A047);
  transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}

/*
 * App availability 2026-07-07 — Master Design Guide §4 "Disabled States"
 * spec (50% opacity + pointer-events: none), applied to top-bar app-
 * switcher entries for apps an admin has disabled globally or for the
 * user's category. See apps/admin/migrations/017_user_categories_app_availability.sql
 * and shell-module-federation.js's applyAppAvailabilityToSidebar().
 */
.app-link-disabled {
  opacity: 0.5;
  pointer-events: none;
}

/*
 * Skip link (backlog 97c8be23) — the first tabbable element on the page,
 * jumping straight to #app-canvas where every federated app mounts.
 *
 * Positioned off-screen rather than display:none or visibility:hidden:
 * both of those remove an element from the tab order entirely, which
 * would make the link unreachable and therefore useless — the exact
 * "a dead rule leaves an unreachable control" failure in this repo's
 * own a11y notes. It must stay focusable at all times and only become
 * VISIBLE on focus.
 *
 * Uses :focus, not :focus-visible — a skip link is reached by Tab, and
 * :focus-visible's heuristics are the wrong gate for something whose
 * entire purpose is keyboard navigation.
 */
.skip-link {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 1000;
  padding: 10px 16px;
  border-radius: 0 0 8px 0;
  background: var(--yeja-cobalt);
  color: var(--yeja-gray-0);
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
  /* Off-screen but focusable. */
  transform: translateY(-101%);
}

.skip-link:focus {
  transform: translateY(0);
  outline: 2px solid var(--yeja-cobalt);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: no-preference) {
  .skip-link {
    transition: transform 120ms ease-out;
  }
}

/*
 * Keyboard focus ring — Master Design Guide §4 "Accessibility and System
 * States": Cobalt, 2px solid outline, 2px offset, on every interactive
 * element.
 */
.topbar-brand:focus-visible,
.topbar-apps-trigger:focus-visible,
.topbar-avatar-trigger:focus-visible,
.topbar-create-trigger:focus-visible,
.topbar-favorites-trigger:focus-visible,
.topbar-notifications-trigger:focus-visible,
.cart-btn:focus-visible,
.topbar-avatar-panel-item:focus-visible,
.button:focus-visible,
.icon-action:focus-visible,
.account-chip:focus-visible,
.logout-chip:focus-visible {
  outline: 2px solid var(--yeja-cobalt, #1E88E5);
  outline-offset: 2px;
}

/*
 * Moved from index.html's inline <style> block, 2026-07-07 compliance pass
 * (see the .master-layout comment above for the full explanation of why
 * that block existed and why it's gone now). Shell breakout (2026-07-14):
 * absorbed .workspace's role directly — #app-canvas is now the topbar's
 * only sibling, so there's no intermediate wrapper needed.
 */
.app-canvas {
  flex: 1;
  min-width: 0;
  overflow-y: auto;
  background: var(--paper);
  /* Real bug fixed 2026-07-15 (Commissions "won't load" report — root
   * cause was CSS, not the iframe/auth/token handoff, which all worked
   * correctly). flex:1 alone gives this element a size via the flex
   * layout algorithm, but does NOT give it a resolvable height for a
   * percentage-height CHILD — Commissions' iframe (apps/commissions/
   * app-module.js) uses height:100%, which fell back to the browser's
   * ~150px default for a sizeless iframe, clipping the entire app to a
   * thin strip. Every other app paints directly into this canvas via JS
   * and never hit this, since they don't depend on a resolvable
   * ancestor height. Lost when the shell-breakout work (2026-07-14,
   * commit b9aa444) replaced the old rail+workspace layout — the old
   * .workspace class apparently had this covered and .app-canvas never
   * got it. Same calc(100vh - var(--topbar-height)) pattern already
   * used by apps/my_studio/styles.css's own .app-main.studio-mode. */
  height: calc(100vh - var(--topbar-height));
  /* Second pass, same day: the height fix above was necessary but not
   * sufficient — live CDP verification found the iframe's own
   * height:100% still resolved to the browser's sizeless-iframe default
   * on the real deployed page (an isolated minimal repro with identical
   * CSS did not reproduce it — percentage-height-on-flex-item resolution
   * is unreliable in exactly this way in real-world layouts). Switched
   * Commissions' iframe to position:absolute; inset:0 instead, which
   * never depends on percentage-height resolution — this element is the
   * positioned ancestor it needs. */
  position: relative;
}

.theme-portal-status {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 12px;
  padding: 24px;
  text-align: center;
  background: var(--paper);
  color: var(--ink);
}

.theme-portal-status.is-error {
  color: var(--ink);
}

.theme-portal-status button {
  min-height: 44px;
  padding: 8px 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius-control, 10px);
  background: var(--surface);
  color: var(--ink);
  cursor: pointer;
}

/* Menus use the native hidden attribute as their accessibility source of
 * truth. Component display rules have higher specificity than the UA rule,
 * so keep this explicit override beside the menu styles. */
.topbar-apps-panel[hidden],
.topbar-avatar-panel[hidden],
.dropdown__panel[hidden] {
  display: none !important;
}

/* L2 tab strip — this app's own view tabs (e.g. Art Board's All
 * Artworks/Trending/Collections), populated per-app from
 * app-registry.js's menuItems (see shell-module-federation.js's
 * renderAppL2Tabs()). Shell breakout (2026-07-14): moved from a
 * separate row above #app-canvas into .topbar-left, directly matching
 * apps/experimental/app.js's own .topnav__left (#exp-nav-links sits
 * right next to the logo there too — this is the same slot, not a new
 * design decision). Hidden via [hidden] for apps with no second
 * top-level view, rather than rendering an empty strip. */
.app-l2-tabs {
  display: flex;
  align-items: center;
  gap: 18px;
}
.app-l2-tabs .yeja-tab {
  padding: 0;
  font-size: var(--text-body-size, 14px);
  color: var(--muted);
}
.app-l2-tabs .yeja-tab[aria-selected="true"] {
  color: var(--ink);
  font-weight: 700;
}

/*
 * GLOBAL TOP BAR — replicated directly from apps/experimental/app.js's
 * real <header class="topnav"> and apps/experimental/styles.css's
 * matching rules (Components 1/2/4/5 there), generalized from
 * .experimental-app-scoped classes and --exp- prefixed tokens to real
 * global classes and the shell's existing --yeja- prefixed tokens. This
 * is the ONE universal shell chrome now — apps/experimental/app.js's
 * own internal .topnav is deleted in the same pass as this file, so
 * there is exactly one top bar rendered, ever, matching what this file
 * defines.
 * Zone order, left to right: .topbar-left (brand + this-app's-own view
 * tabs, same slot as Experimental's .topnav__left/#exp-nav-links) —
 * .search-wrap (flex:1, centered, matches Experimental's own
 * .search-wrap sizing) — .topbar-right (Create / Notifications / Avatar,
 * matches Experimental's .topnav__right icon cluster order and shape:
 * Create is a filled .dropdown__trigger pill, Notifications is a plain
 * circular icon button, Avatar opens the cross-app-switcher dropdown).
 */
/* --rail-bg/--rail-text/--rail-hover-bg/--rail-active-bg: a custom
 * theme's chrome-surface tokens (apps/shared/platform-theme.js's
 * MANAGED_PROPERTIES, still named --rail-* — the wire format predates
 * the shell breakout and isn't worth a rename, since theme-schema.js's
 * DEFAULT_THEME_TOKENS/PRESET_THEMES and every saved user theme in the
 * cc_themes table already use surfaces.rail/railActive/railHover as
 * field names). The top bar is the rail's direct successor as "the
 * platform's own persistent chrome, distinct from canvas content" — so
 * it's the correct new consumer of these tokens, not a namespace that
 * needs to change. */
.topbar {
  position: sticky;
  top: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 24px;
  background: var(--rail-bg, var(--paper));
  border-bottom: 1px solid var(--line);
}

.topbar-left {
  display: flex;
  align-items: center;
  gap: 28px;
  min-width: 0;
}

.topbar-brand {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 700;
  font-size: var(--text-body-size, 15.5px);
  color: var(--rail-text, var(--ink));
}

.topbar-brand-text {
  white-space: nowrap;
}

/* Current-app pill (2026-07-22, real user instruction): "My Studio" etc.
 * next to the logo, updated on every app switch — see loadApp()'s
 * currentAppPill block in shell-module-federation.js.
 *
 * Fixed 2026-07-25 (real user instruction, backlog 63e705d7): promoted
 * from a plain text badge to a real clickable pill button — clicking it
 * now navigates to that app's default landing page via the shell's
 * existing data-app-link mechanism (shell-module-federation.js).
 * Combined with .yeja-pill-btn-ghost (apps/shared/components.css) for
 * border/fill color, sized "compact" to fit the topbar rather than the
 * ghost button's normal 0.5em/1.25em padding — but border-radius must be
 * set HERE, not assumed from .yeja-pill-btn-ghost: that class is a
 * modifier meant to layer on top of the base .yeja-pill-btn class (which
 * owns border-radius/display/cursor), and this element only carries the
 * modifier, not the base class — confirmed live 2026-07-25 as a real
 * shipped bug (square corners, not a capsule) after the user screenshotted
 * production and called it out directly. */
.topbar-current-app-pill {
  height: 24px;
  padding: 0 12px;
  border-radius: var(--radius-pill, 999px);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  flex: 0 0 auto;
}

/* Superseded 2026-07-18: the old hover-only 180deg flip is replaced by a
 * continuous idle spin (.yeja-brand-animated, apps/shared/design-tokens.css)
 * added directly on .brand-mark in the markup — a hover-triggered
 * transform on the same property would fight the running keyframe
 * animation and stutter on mouseenter, so the hover rule is removed
 * rather than layered on top of it. prefers-reduced-motion is handled by
 * that shared rule's own media query. */

.search-wrap {
  position: relative;
  flex: 1;
  max-width: 420px;
  margin: 0 32px;
}

/*
 * Global search — replicated directly from apps/experimental/styles.css's
 * real .search-pill/.search-pill__input-wrap rules (Component 2 there).
 * Distinct from any in-canvas search a mounted app might render.
 */
.search-pill {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--surface);
  border-radius: var(--radius-pill, 999px);
  padding: 10px 16px;
  border: 1px solid var(--muted);
}
.search-pill .icon,
.search-pill .yeja-icon {
  flex: 0 0 auto;
  color: var(--muted);
}
.search-pill:focus-within .icon,
.search-pill:focus-within .yeja-icon {
  color: var(--ink);
}
.search-pill__input-wrap {
  position: relative;
  flex: 1;
  display: flex;
  align-items: center;
}
.search-pill input {
  border: none;
  outline: none;
  background: none;
  width: 100%;
  font-size: var(--text-body-size, 14px);
  font-family: inherit;
  color: var(--ink);
  position: relative;
  z-index: 1;
}
.search-pill input::placeholder { color: transparent; }
.search-pill__placeholder {
  position: absolute;
  left: 0;
  /* Real bug fixed 2026-08-02 (backlog: "animated text inside the
   * universal search pill bar must not exceed the boundaries of the
   * search pill") — right:0 + overflow:hidden give `white-space:nowrap`
   * something to actually clip against. Without a right edge, the
   * absolutely-positioned element just grows to its full, unclipped
   * content width for any placeholder phrase longer than the pill
   * itself, visibly spilling out past the pill's rounded border. */
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  font-size: var(--text-body-size, 14px);
  font-family: inherit;
  color: var(--muted);
  pointer-events: none;
  white-space: nowrap;
  overflow: hidden;
  /* No text-overflow:ellipsis — this is a live typewriter animation, not
   * static truncated text; a "..." would look like a permanent
   * truncation indicator flickering in and out as the animated text
   * grows/shrinks each cycle, rather than a clean hard clip. */
  transition: color 0.3s ease;
}
/* Blinking type-cursor, CSS-only — matches Experimental's real
 * .search-pill__placeholder::after exactly. */
.search-pill__placeholder::after {
  content: '';
  display: inline-block;
  width: 1px;
  height: 1em;
  margin-left: 1px;
  background: currentColor;
  vertical-align: -0.15em;
  animation: search-pill-caret-blink 1s step-end infinite;
}
@keyframes search-pill-caret-blink {
  0%, 100% { opacity: 1; }
  50% { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .search-pill__placeholder::after { animation: none; }
}
.search-pill input:focus ~ .search-pill__placeholder { display: none; }

/*
 * Search-focus overlay — replicated directly from
 * apps/experimental/styles.css's real .search-overlay rules (real
 * recently-viewed + real extracted colors there). This is the one place
 * in the shell that surfaces it; the platform-wide equivalent reads from
 * whichever module the shell has mounted (see shell-module-federation.js).
 */
.search-overlay {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  right: 0;
  background: var(--surface);
  border-radius: var(--radius-menu, 16px);
  border: 1px solid var(--line);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18);
  padding: 16px;
  display: none;
  flex-direction: column;
  gap: 16px;
  z-index: 200;
  max-height: 60vh;
  overflow-y: auto;
}
.search-overlay.is-open { display: flex; }
.search-overlay__label {
  font-size: var(--text-label-size, 12px);
  color: var(--muted);
  margin-bottom: 10px;
}
.search-overlay__label-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.search-overlay__label-row .search-overlay__label { margin-bottom: 0; }
.search-overlay__clear {
  font-size: var(--text-label-size, 11px);
  color: var(--muted);
  margin-bottom: 10px;
  border: none;
  background: none;
  cursor: pointer;
}
.search-overlay__clear:hover { color: var(--ink); }
.search-overlay__colors {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.search-overlay__swatch {
  display: flex;
  align-items: center;
  height: 32px;
  padding: 0 12px;
  border-radius: var(--radius-pill, 999px);
  border: 1px solid rgba(0, 0, 0, 0.08);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
  color: #FFFFFF;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
  cursor: pointer;
}
.search-overlay__swatch:hover { transform: scale(1.05); }
.search-overlay__recent {
  display: flex;
  gap: 10px;
  overflow-x: auto;
  flex-wrap: wrap;
}
.search-overlay__recent-item {
  flex: 0 0 auto;
  width: 64px;
  height: 64px;
  border-radius: 3px;
  overflow: hidden;
  background: var(--line);
  border: none;
  cursor: pointer;
  padding: 0;
}
.search-overlay__recent-item:hover { transform: scale(1.04); }
.search-overlay__recent-item img { display: block; width: 100%; height: 100%; object-fit: cover; }
.search-overlay__recent-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted);
  font-weight: 700;
}

/* Favorites/Cart badge — matches Experimental's real .cart-count exactly */
.cart-count {
  position: absolute;
  top: -2px;
  right: -2px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: var(--radius-pill, 999px);
  background: var(--ink);
  color: var(--paper);
  font-size: 10px;
  line-height: 16px;
  text-align: center;
}
.empty-msg {
  padding: 24px;
  text-align: center;
  color: var(--muted);
  font-size: var(--text-body-size, 14px);
}

/* Topbar cart panel item rows (2026-07-28) — real user-instructed
 * checkout feature; the panel's content (#topbar-cart-panel-inner) never
 * had its own item styling before this, since renderCartPanel() only
 * ever had real content once Art Board's currentModule.getCart() hook
 * happened to be populated. Mirrors apps/art_board/styles.css's own
 * .cart-item-* rules (the two panels render the exact same item shape). */
#topbar-cart-panel-inner .cart-item-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  /* 5px gap + 5px padding-bottom = ~10px between item lines, same as
   * the Create menu's stacked 5px-padded rows (2026-07-25 user
   * instruction). The earlier 10px+10px still read twice as loose. */
  gap: 5px;
}
#topbar-cart-panel-inner .cart-item {
  display: flex;
  align-items: center;
  gap: var(--space-2, 16px);
  padding-bottom: 5px;
  border-bottom: 1px solid var(--line);
}
#topbar-cart-panel-inner .cart-item:last-child {
  border-bottom: none;
  padding-bottom: 0;
}
#topbar-cart-panel-inner .cart-item-img,
#topbar-cart-panel-inner .cart-item-placeholder {
  width: 44px;
  height: 44px;
  border-radius: var(--radius-control, 8px);
  object-fit: cover;
  flex: 0 0 auto;
  background: var(--surface-alt);
}
#topbar-cart-panel-inner .cart-item-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  color: var(--muted);
}
#topbar-cart-panel-inner .cart-item-text {
  flex: 1;
  min-width: 0;
}
#topbar-cart-panel-inner .cart-item-title {
  margin: 0;
  font-size: var(--text-body-size, 14px);
  font-weight: 600;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
#topbar-cart-panel-inner .cart-item-price {
  flex: 0 0 auto;
  font-size: var(--text-body-size, 14px);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
#topbar-cart-panel-inner .cart-total-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: var(--space-2, 16px);
  padding-top: var(--space-2, 16px);
  border-top: 1px solid var(--line);
  font-weight: 700;
}
#topbar-cart-panel-inner .cart-total-amount {
  font-variant-numeric: tabular-nums;
}
#topbar-cart-checkout-btn {
  width: 100%;
  margin-top: var(--space-2, 16px);
  justify-content: center;
}

.topbar-right {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 16px;
}

/* Icon — matches apps/experimental/styles.css's real .icon class
 * exactly (16px, 1.75px stroke, round caps/joins, no fill) — every
 * inline SVG in the top bar relies on this instead of hardcoding
 * stroke/size attributes per-icon. Master Design Guide §3
 * "Iconography": stroke-width 1.75px platform-wide. */
.icon {
  width: 16px;
  height: 16px;
  stroke: currentColor;
  stroke-width: 1.75px;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Create — matches Experimental's .dropdown__trigger exactly: filled
 * ink pill, not an outline/ghost button. */
.dropdown { position: relative; }
.dropdown__trigger {
  display: flex;
  align-items: center;
  gap: 6px;
  background: var(--ink);
  color: var(--paper);
  border-radius: var(--radius-pill, 999px);
  padding: 8px 16px;
  border: none;
  font-size: var(--text-body-size, 14px);
  cursor: pointer;
}
.dropdown__panel {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  min-width: 280px;
  background: var(--surface);
  border-radius: var(--radius-menu, 16px);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.14);
  padding: 8px;
  display: none;
  z-index: 200;
}
/* Same enter animation as .topbar-apps-panel/.topbar-avatar-panel below
 * (backlog 4c9a50fc, 2026-07-26: universal top panel menus must share
 * the same aesthetic characteristics) — was a hard display:none->block
 * toggle with no transition while the other two panel types faded+slid
 * in over 150ms. */
.dropdown__panel.is-open {
  display: block;
  animation: topbar-avatar-panel-enter 0.15s ease-out;
}

.action-item {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 100%;
  gap: 2px;
  padding: 10px 12px;
  border: 0;
  background: transparent;
  border-radius: 12px;
  text-align: left;
  cursor: pointer;
  transition: background 0.15s ease-in-out;
}
.action-item:hover {
  background: var(--surface-alt);
}
/* Real bug fixed 2026-07-15 ("favorites shows 1 but says No favorites
 * yet"): this class's own display:flex beats the browser's built-in
 * [hidden]{display:none} UA rule in specificity — #topbar-favorites-empty
 * (an .action-item) rendered visually even when JS correctly set the
 * hidden attribute, because the empty-state block and the real favorited
 * item both sit inside #topbar-favorites-panel and neither one's
 * disappearance was ever actually enforced by CSS. Same bug class as
 * apps/my_studio/styles.css's own documented .upload-queue[hidden] fix. */
.action-item[hidden] { display: none; }
.action-item__label {
  font-size: var(--text-body-size, 14px);
  font-weight: 700;
  color: var(--ink);
}
.action-item__desc {
  font-size: var(--text-label-size, 12px);
  color: var(--muted);
}

/* Create menu (2026-07-22, real user instruction: "shrink the padding...
 * so items are 50% closer together") — scoped to #topbar-create-panel
 * only, not the shared .action-item class itself, since that same class
 * is also used for the Favorites panel's empty state and shouldn't
 * shrink along with it. 10px top/bottom -> 5px halves the visible gap
 * between adjacent items. */
#topbar-create-panel .action-item {
  padding-top: 5px;
  padding-bottom: 5px;
}

/* Favorites panel item — real card row (image + title + item-type label),
 * replacing the old bare 64x64 image-or-placeholder tile
 * (.search-overlay__recent-item, built for a "recently viewed" strip,
 * not a real labeled list) that a favorited item rendered as with no
 * text at all. Panel widened via #topbar-favorites-panel below since
 * .dropdown__panel's default 280px min-width crowds a title next to a
 * real thumbnail. */
#topbar-favorites-panel,
#topbar-notifications-panel { width: 320px; }
/* Row-to-row spacing matched to the Create menu (2026-07-25, user
 * instruction: favorites/notifications/cart item lines must sit as
 * close together as #topbar-create-panel .action-item rows do). Create
 * rows stack with no flex gap and 5px vertical padding; these lists
 * inherited .search-overlay__recent's 10px gap on top of 8px row
 * padding, so rows sat ~26px apart. Gap zeroed here (scoped to the two
 * panel lists, not the search overlay's actual recent-thumbnail strip)
 * and .favorite-item padding brought down to the same 5px. */
#topbar-favorites-list,
#topbar-notifications-list { gap: 0; }
.favorite-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 5px 8px;
  border: 0;
  background: transparent;
  border-radius: 12px;
  text-align: left;
  cursor: pointer;
  transition: background 0.15s ease-in-out;
}
.favorite-item:hover { background: var(--surface-alt); }
.favorite-item__thumb {
  flex: 0 0 auto;
  width: 48px;
  height: 48px;
  border-radius: 8px;
  overflow: hidden;
  background: var(--line);
}
.favorite-item__thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
.favorite-item__placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted);
  font-weight: 700;
}
.favorite-item__text {
  min-width: 0;
  flex: 1;
}
.favorite-item__title {
  font-size: var(--text-body-size, 14px);
  font-weight: 700;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.favorite-item__desc {
  font-size: var(--text-label-size, 12px);
  color: var(--muted);
}
/* Notification rows share .favorite-item's card shape — a distinct
 * left dot instead of a thumbnail image, and an unread state (bold title
 * + accent dot) so it reads as different from a favorited item at a
 * glance without a second panel/tab. */
.favorite-item__section-label {
  padding: 8px 8px 4px;
  font-size: var(--text-label-size, 12px);
  font-weight: 700;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
.notification-item .favorite-item__thumb {
  background: transparent;
  /* The inherited thumb box is 48x48 sized for a real Favorites artwork
   * image, but a notification only puts an unread dot here — at 48px it
   * silently props every row up to 58px even after the 2026-07-25 gap/
   * padding tightening, which is why notification rows still sat visibly
   * looser than the Create menu's text-only rows. 16px keeps the dot
   * column without the dead vertical space; the row now collapses to
   * text height (~47px), same as a Create menu row. */
  width: 16px;
  height: 16px;
}
.notification-item .favorite-item__placeholder {
  color: var(--yeja-cobalt, #1E88E5);
  font-size: 20px;
  line-height: 1;
}
.notification-item.is-unread .favorite-item__title {
  font-weight: 700;
}
.notification-item:not(.is-unread) {
  opacity: 0.7;
}
/* Actor-name link inside a notification row (2026-07-25, real user
 * instruction) — needs to visually read as a real link (distinct color +
 * underline on hover), not blend into the surrounding title text the
 * way a plain nested <a> with no styling would. */
.notification-item__actor {
  color: var(--yeja-cobalt, #1E88E5);
  text-decoration: none;
}
.notification-item__actor:hover {
  text-decoration: underline;
}

/* Unread-notifications dot on the dedicated Notifications (bell) trigger
 * — split back out from the combined Favorites+Notifications surface
 * (backlog 008884bd, 2026-08-02, reverting b6d257fc/1201e5ab). Bottom-
 * right placement carried over unchanged from the old combined-trigger
 * dot, since this button has no numeric badge to collide with. */
.notification-unread-dot {
  position: absolute;
  bottom: 0px;
  right: 0px;
  width: 8px;
  height: 8px;
  border-radius: var(--radius-pill, 999px);
  background: var(--yeja-crimson, #E53935);
  border: 1.5px solid var(--paper);
}

/* Notifications — matches Experimental's plain circular .cart-btn icon
 * button (used there for Favorites/Notifications/Cart alike). */
.cart-btn {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-pill, 999px);
  border: none;
  background: transparent;
  color: var(--ink);
  cursor: pointer;
  padding: 0;
}
.cart-btn:hover {
  background: var(--surface-alt);
}

/* Avatar trigger + dropdown — matches Experimental's .avatar-trigger/
 * .profile-panel exactly (Component 5 in that file's styles.css). */
.topbar-avatar-wrap {
  position: relative;
}

.topbar-avatar-trigger {
  width: 32px;
  height: 32px;
  flex: 0 0 32px;
  border: none;
  border-radius: var(--radius-pill, 999px);
  background: var(--surface-alt);
  color: var(--ink);
  display: inline-grid;
  place-items: center;
  cursor: pointer;
  overflow: hidden;
  font-size: var(--text-label-size, 12px);
  font-weight: 700;
  padding: 0;
}

.topbar-avatar-fallback {
  display: inline-grid;
  place-items: center;
  width: 100%;
  height: 100%;
}

/* Universal Apps menu (2026-07-26) — same trigger footprint as the
 * avatar button (32px round), Google-apps-style 3x3 dot grid icon. */
.topbar-apps-trigger {
  width: 32px;
  height: 32px;
  flex: 0 0 32px;
  border: none;
  border-radius: var(--radius-pill, 999px);
  background: transparent;
  color: var(--ink);
  display: inline-grid;
  place-items: center;
  cursor: pointer;
  padding: 0;
}
.topbar-apps-trigger:hover {
  background: var(--surface-alt);
}
.topbar-apps-trigger .icon {
  width: 20px;
  height: 20px;
  /* Base .icon is stroke: currentColor / fill: none (outline icons) —
   * this is a filled 3x3 dot grid instead, so both need overriding or
   * the circles render invisible. */
  stroke: none;
  fill: currentColor;
}
.topbar-apps-trigger .yeja-icon {
  /* Increased from 20px (2026-07-23, real user instruction) — the 32px
   * button circle still has enough padding at 24px to avoid clipping. */
  font-size: 24px;
}

.topbar-apps-panel {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  width: 260px;
  background: var(--surface);
  border-radius: var(--radius-menu, 16px);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.14);
  padding: 12px;
  z-index: 200;
  display: none;
  grid-template-columns: repeat(3, 1fr);
  gap: 4px;
}
/* Toggle mechanism unified to .is-open (backlog 4c9a50fc, 2026-07-26) —
 * was the `hidden` attribute, which had already caused a real bug: this
 * class's own display:grid beat the browser's built-in
 * [hidden]{display:none} rule in specificity, so toggling `hidden` in JS
 * silently had no visible effect without an explicit `[hidden]{display:
 * none}` override (previously here). Matches .dropdown__panel's
 * mechanism (Create/Favorites/Notifications/Cart) so all 5 universal
 * topbar menus share one open/close code path instead of two. */
.topbar-apps-panel.is-open {
  display: grid;
  animation: topbar-avatar-panel-enter 0.15s ease-out;
}

.topbar-apps-panel-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 12px 4px;
  border: 0;
  border-radius: var(--radius-control, 8px);
  background: transparent;
  color: var(--ink);
  font-size: 11px;
  font-weight: 600;
  text-align: center;
  cursor: pointer;
  line-height: 1.2;
}
.topbar-apps-panel-item .icon {
  width: 22px;
  height: 22px;
  stroke-width: 1.5px;
}
.topbar-apps-panel-item .yeja-icon {
  font-size: 22px;
}
.topbar-apps-panel-item:hover {
  background: var(--surface-alt);
  color: var(--yeja-cobalt, var(--accent));
}
.topbar-apps-panel-item:focus-visible {
  outline: 2px solid var(--yeja-cobalt, var(--accent));
  outline-offset: -2px;
}

.topbar-avatar-panel {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  width: 280px;
  background: var(--surface);
  border-radius: var(--radius-menu, 16px);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.14);
  padding: 16px 0;
  z-index: 200;
  display: none;
}
/* Toggle mechanism unified to .is-open (backlog 4c9a50fc, 2026-07-26) —
 * was the `hidden` attribute; see .topbar-apps-panel above for the full
 * rationale (all 5 universal topbar menus now share one open/close
 * mechanism instead of two). */
.topbar-avatar-panel.is-open {
  display: block;
  animation: topbar-avatar-panel-enter 0.15s ease-out;
  /* Bound to the viewport and scroll internally (PROG-P3, 2026-08-03).
   *
   * This panel previously had NO height limit and overflow-y:visible, which
   * was survivable only because its content happened to fit: measured live,
   * it ended 717px down an 900px viewport. Expanding the Platform Layout
   * rail added ~385px and pushed "Log Out" to 1156px — off-screen, with no
   * scroll container to reach it. A disclosure that makes Log Out
   * unreachable is a worse bug than the one it was added to solve.
   *
   * 100dvh (not vh) so mobile browser chrome is accounted for; the 24px
   * subtrahend keeps the panel clear of the very bottom edge, and `top` is
   * already offset from the trigger so this measures the space that
   * actually remains below it. */
  max-height: calc(100dvh - var(--topbar-height, 64px) - 24px);
  overflow-y: auto;
  overscroll-behavior: contain;
}

@keyframes topbar-avatar-panel-enter {
  from { opacity: 0; transform: translateY(-6px); }
  to { opacity: 1; transform: translateY(0); }
}

.topbar-avatar-panel-section {
  padding: 0 16px;
}
.topbar-avatar-panel-section + .topbar-avatar-panel-section {
  border-top: 1px solid var(--line);
  margin-top: 8px;
  padding-top: 8px;
}

.topbar-avatar-panel-label {
  font-size: var(--text-label-size, 12px);
  color: var(--muted);
  padding-top: 4px;
  padding-bottom: 6px;
}
.topbar-avatar-panel-section.topbar-avatar-panel-label {
  border-top: 0;
  margin-top: 0;
  padding-top: 0;
}

/* "Account Hub" (2026-08-02, backlog bd5a6a24) — this was a plain <div>
 * section label reading "Account Settings"; it is now a real <button>
 * that navigates to ?app=profile&view=account, so the heading of the
 * Account group is itself the way into the hub.
 *
 * It must be reset explicitly: font-family and font-size do NOT inherit
 * into form controls, so a <button> here would otherwise paint in the UA
 * default face at the UA default size while every sibling item uses the
 * platform's. Same trap that hit the Profile hub cards under 1cece0a2
 * item 4. text-align is reset for the same reason (buttons centre by
 * default; every other item in this panel is left-aligned). */
button.topbar-avatar-panel-label {
  display: block;
  width: 100%;
  border: 0;
  background: transparent;
  font: inherit;
  font-size: var(--text-label-size, 12px);
  text-align: left;
  cursor: pointer;
}
button.topbar-avatar-panel-label:hover {
  color: var(--ink);
}
button.topbar-avatar-panel-label:focus-visible {
  outline: 2px solid var(--yeja-cobalt);
  outline-offset: 2px;
  border-radius: 4px;
}

.topbar-avatar-panel-item {
  display: flex;
  align-items: center;
  width: 100%;
  min-height: 28px;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--ink);
  font-size: var(--text-body-size, 14px);
  text-align: left;
  cursor: pointer;
}
.topbar-avatar-panel-item:hover {
  color: var(--yeja-cobalt, var(--accent));
}
/* Account Settings submenu icons (2026-08-02, backlog b8c53d53). The item
 * is already display:flex/align-items:center, so the ligature sits inline
 * on its own; this only supplies the gap and sizes the glyph to the label.
 * The icons are the SAME Material Symbols ligatures the Account hub cards
 * use, so the two surfaces stay visually in step.
 *
 * flex-shrink:0 matters: several labels are long ("Preferences &
 * Notifications", "Atelier (Personal Webpage)") and would otherwise
 * squash the glyph rather than the text in a narrow panel. */
.topbar-avatar-panel-item .yeja-icon {
  font-size: 18px;
  margin-inline-end: 10px;
  flex-shrink: 0;
  color: var(--muted);
}
.topbar-avatar-panel-item:hover .yeja-icon {
  color: inherit;
}
.topbar-avatar-panel-logout {
  color: var(--yeja-crimson, #E53935);
}

.topbar-avatar-panel-theme {
  padding: 12px 16px;
  /* Center the light/dark control (backlog 008884bd, 2026-08-02, real
   * user instruction) — .yeja-theme-control is itself display:inline-flex
   * (apps/shared/design-tokens.css), so it hugs the left edge of this
   * full-width section by default without an explicit centering rule
   * here. */
  display: flex;
  justify-content: center;
}

/* Onboarding preset toggle (Plan v2 Phase 4, 2026-07-27, tracker
 * 3c411561) — a custom two-option control, deliberately NOT built as a
 * role="radiogroup" .segmented (that pattern is grid-size's, a different
 * control per the plan's own corrected finding). Modeled closely on
 * .yeja-theme-control's own visual shape (label + pill buttons) since it
 * mounts in the same panel section family. */
.topbar-avatar-panel-preset {
  padding: 12px 16px;
  display: flex;
  justify-content: center;
}
.yeja-preset-control {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.yeja-preset-label {
  font-size: var(--text-label-size, 12px);
  color: var(--muted);
}
.yeja-preset-option {
  padding: 4px 10px;
  border-radius: var(--radius-pill, 999px);
  border: 1px solid var(--line);
  background: transparent;
  color: var(--muted);
  font-size: var(--text-label-size, 12px);
  cursor: pointer;
}
.yeja-preset-option.is-active {
  border-color: var(--ink);
  color: var(--ink);
  background: var(--surface);
}

/* Onboarding routing flow — 3 full-canvas screens shown on first
 * authenticated load for a brand-new signup (profiles.onboarding_preset
 * still null). Renders directly into #app-canvas, same element loadApp()
 * would otherwise mount an app into — this IS the canvas content until
 * the user answers or skips, not an overlay layered on top of a mounted
 * app. */
.plat-onboarding-overlay {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 60vh;
  padding: var(--space-4, 32px);
}
.plat-onboarding-card {
  width: min(560px, 100%);
  display: flex;
  flex-direction: column;
  gap: var(--space-3, 24px);
  align-items: center;
  text-align: center;
}
.plat-onboarding-progress {
  display: flex;
  gap: 6px;
}
.plat-onboarding-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--line);
}
.plat-onboarding-dot.is-active {
  background: var(--ink);
}
.plat-onboarding-dot.is-done {
  background: var(--muted);
}
.plat-onboarding-title {
  margin: 0;
  font-size: var(--text-h1-size, 28px);
  font-weight: var(--text-h1-weight, 700);
  color: var(--ink);
}
.plat-onboarding-options {
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 100%;
}
.plat-onboarding-option {
  width: 100%;
  padding: 14px 20px;
  border-radius: var(--radius-card, 12px);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font-size: var(--text-body-size, 15px);
  text-align: left;
  cursor: pointer;
  transition: border-color 0.15s cubic-bezier(0.4, 0, 0.2, 1), background 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}
.plat-onboarding-option:hover {
  border-color: var(--ink);
  background: var(--surface-hover, var(--line));
}
.plat-onboarding-skip {
  border: none;
  background: transparent;
  color: var(--muted);
  font-size: var(--text-label-size, 12px);
  text-decoration: underline;
  cursor: pointer;
  padding: 4px;
}

/* Treasure Map P1.4 — identity steps (tracker 23bafafe). These screens
 * collect data rather than offering a single choice, so they need form
 * controls the three original preference screens never had. They reuse
 * the same overlay/card/progress/skip chrome above; everything here is
 * additive. */
.plat-onboarding-card-form {
  /* Left-aligned because these are labelled fields, not centred choices —
   * a centred label above a full-width input reads as decoration. */
  text-align: left;
  align-items: stretch;
  gap: var(--space-2, 16px);
}
.plat-onboarding-card-form .plat-onboarding-progress,
.plat-onboarding-card-form .plat-onboarding-title {
  align-self: center;
  text-align: center;
}
.plat-onboarding-lede {
  margin: 0;
  color: var(--muted);
  font-size: var(--text-body-size, 15px);
  text-align: center;
}
.plat-onboarding-subtitle {
  margin: 0 0 8px;
  font-size: var(--text-label-size, 12px);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
}
.plat-onboarding-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  width: 100%;
}
.plat-onboarding-field-label {
  font-size: var(--text-label-size, 12px);
  color: var(--muted);
}
.plat-onboarding-field input,
.plat-onboarding-card-form select {
  width: 100%;
  padding: 12px 14px;
  border-radius: var(--radius-card, 12px);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font-size: var(--text-body-size, 15px);
  font-family: inherit;
}
.plat-onboarding-field-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  width: 100%;
}
.plat-onboarding-checkbox {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 20px;
  border-radius: var(--radius-card, 12px);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font-size: var(--text-body-size, 15px);
  cursor: pointer;
  transition: border-color 0.15s cubic-bezier(0.4, 0, 0.2, 1), background 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}
.plat-onboarding-checkbox:hover {
  border-color: var(--ink);
  background: var(--surface-hover, var(--line));
}
.plat-onboarding-checkbox input {
  accent-color: var(--yeja-cobalt);
  width: 16px;
  height: 16px;
}
.plat-onboarding-summary {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  width: 100%;
  border: 1px solid var(--line);
  border-radius: var(--radius-card, 12px);
  overflow: hidden;
}
.plat-onboarding-summary-row {
  display: grid;
  grid-template-columns: 140px 1fr;
  gap: 12px;
  padding: 12px 16px;
  background: var(--surface);
}
.plat-onboarding-summary-row + .plat-onboarding-summary-row {
  border-top: 1px solid var(--line);
}
.plat-onboarding-summary dt {
  color: var(--muted);
  font-size: var(--text-label-size, 12px);
}
.plat-onboarding-summary dd {
  margin: 0;
  color: var(--ink);
  font-size: var(--text-body-size, 15px);
}
.plat-onboarding-avatar-row {
  display: flex;
  align-items: center;
  gap: 16px;
}
.plat-onboarding-avatar {
  width: 72px;
  height: 72px;
  flex: 0 0 72px;
  border-radius: 50%;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--surface-hover, var(--line));
  color: var(--ink);
  font-size: 28px;
  font-weight: 600;
}
.plat-onboarding-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* The native file input is visually replaced by the pill button beside
 * it, but stays in the DOM and focusable so keyboard and assistive tech
 * still reach the real control. */
.plat-onboarding-file input[type="file"] {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
.plat-onboarding-file {
  cursor: pointer;
}
.plat-onboarding-file input[type="file"]:focus-visible + span {
  outline: 2px solid var(--yeja-cobalt);
  outline-offset: 2px;
}
.plat-onboarding-address-group + .plat-onboarding-address-group {
  margin-top: var(--space-2, 16px);
}
.plat-onboarding-address {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.plat-onboarding-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 12px;
  width: 100%;
}
.plat-onboarding-back {
  border: none;
  background: transparent;
  color: var(--muted);
  font-size: var(--text-body-size, 15px);
  cursor: pointer;
  padding: 8px 4px;
  margin-right: auto;
}
.plat-onboarding-status {
  font-size: var(--text-label-size, 12px);
  color: var(--muted);
  min-height: 1em;
}
/* --yeja-mint is the success FOREGROUND token (--yeja-success-bg is the
 * paired background); both theme correctly. Not --yeja-emerald, which is
 * referenced in two places in this repo but defined nowhere — its
 * fallback silently masks that. */
.plat-onboarding-status.is-ok {
  color: var(--yeja-mint);
}
.plat-onboarding-status.is-bad,
.plat-onboarding-error {
  color: var(--yeja-crimson);
  font-size: var(--text-label-size, 12px);
  min-height: 1em;
}
.plat-onboarding-card-form :is(input, select, button):focus-visible {
  outline: 2px solid var(--yeja-cobalt);
  outline-offset: 2px;
}
@media (max-width: 560px) {
  .plat-onboarding-field-row {
    grid-template-columns: 1fr;
  }
  .plat-onboarding-summary-row {
    grid-template-columns: 1fr;
    gap: 2px;
  }
}

/* Preset-switch blocking-confirmation modal — own local copy, same
 * pattern as apps/wallet/app.js's .wal-offer-accept-modal (Phase 3,
 * shipped 2026-07-27) and originally Art Board's ensureDownloadModalPortal.
 * Each app/surface re-scopes its own copy rather than sharing one
 * component, per this repo's established convention. */
.plat-preset-switch-backdrop {
  position: fixed;
  inset: 0;
  background: color-mix(in oklch, var(--yeja-backdrop) 55%, transparent);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 200;
  padding: var(--space-3, 24px);
}
.plat-preset-switch-card {
  width: min(440px, 100%);
  display: flex;
  flex-direction: column;
  gap: var(--space-2, 16px);
  background: var(--yeja-canvas, #fff);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--radius-menu, 16px);
  padding: var(--space-3, 24px);
  box-shadow: 0 24px 64px rgba(0, 0, 0, 0.25);
}
.plat-preset-switch-card h2 {
  margin: 0;
  font-size: var(--text-h3-size, 16px);
  font-weight: var(--text-h3-weight, 600);
}
.plat-preset-switch-card p {
  margin: 0;
  font-size: var(--text-body-size, 14px);
  color: var(--muted);
}
.plat-preset-switch-ack {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: var(--text-body-size, 14px);
  color: var(--ink);
  cursor: pointer;
}
.plat-preset-switch-ack input {
  margin-top: 3px;
}
.plat-preset-switch-error {
  color: var(--danger, var(--yeja-crimson));
}
.plat-preset-switch-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2, 16px);
}

/*
 * Grid-size control — replicated directly from apps/experimental/styles.css's
 * real .segmented/.segmented__option (Components 6/7 there). Universal home
 * for the 1-5 column masonry control (My Studio redesign, 2026-07-14) —
 * shown only for apps that implement getGridColumns()/setGridColumns(),
 * see shell-module-federation.js's applyGridSizeVisibility().
 */
.topbar-avatar-panel-gridsize {
  padding: 12px 16px;
  /* Center the grid-size segmented control (backlog 008884bd,
   * 2026-08-02) — .segmented is itself display:inline-flex, so it hugs
   * the section's left edge by default. align-items:center also centers
   * the "Grid size" label above it (a direct sibling child of this same
   * section) — a centered label over a centered control reads better
   * than a left-aligned label over a centered one, so this is left as
   * the natural combined result rather than singled out further. */
  display: flex;
  flex-direction: column;
  align-items: center;
}
.segmented {
  display: inline-flex;
  gap: 4px;
  background: var(--surface-alt);
  border-radius: var(--radius-pill, 999px);
  padding: 4px;
}
.segmented__option {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border: none;
  background: transparent;
  border-radius: var(--radius-pill, 999px);
  color: var(--muted);
  cursor: pointer;
  transition: background 0.15s cubic-bezier(0.4, 0, 0.2, 1), color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}
.segmented__option[aria-pressed="true"] {
  background: var(--ink);
  color: var(--paper);
}

/*
 * Signature Outline Pill Button — Master Design Guide §4. Compliance pass
 * 2026-07-07: this was previously a solid-fill black/white square block
 * (border-radius: 0, background: var(--ink)) with no basis in the guide at
 * all — the real spec is a light-grey capsule with a 2px hard black/white
 * border and a 24px pill radius. Matches .yeja-pill-btn in
 * apps/shared/design-tokens.css (already used correctly by Galleries/
 * Fundraisers/Auctions) — kept as .button/.icon-action/.account-chip/
 * .logout-chip here since those class names are used across ~40+ call
 * sites in My Studio/Social/the login page and renaming them all is a much
 * larger, separate change than fixing the declaration.
 */
.icon-action,
.account-chip,
.logout-chip,
.button {
  min-height: 48px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1, 8px);
  /* Signature Outline Pill Button — deprecated per the v2026.3 design
   * guide (scheduled for removal in Phase 4), but pointed at the real
   * shared --pill-btn-* tokens now instead of raw hex, so Phase 4's
   * eventual cleanup/removal has one edit point instead of scattered
   * literals matching this exact deprecated shape by coincidence. */
  border: 2px solid var(--pill-btn-border, #000000);
  background: var(--pill-btn-bg, #EAEAEA);
  color: var(--ink);
  cursor: pointer;
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  padding: 0 1.5rem;
  text-transform: uppercase;
  white-space: nowrap;
  border-radius: var(--radius-pill, 24px);
  transition: background 0.15s ease-in-out, color 0.15s ease-in-out;
}

.button:hover {
  background: var(--yeja-active-hover, #FFFFFF);
}

html[data-theme="dark"] .icon-action,
html[data-theme="dark"] .account-chip,
html[data-theme="dark"] .logout-chip,
html[data-theme="dark"] .button {
  /* Same deprecated pill-button shape's dark-mode variant — pointed at
   * --pill-btn-* tokens, matching the light-mode rule above. */
  border-color: var(--pill-btn-border, #FFFFFF);
  background: var(--pill-btn-bg, #2D2D30);
  color: var(--paper);
}

html[data-theme="dark"] .button:hover {
  background: var(--yeja-active-hover, #2D2D30);
}

/*
 * Sidebar overhaul 2026-07-07: .yeja-theme-control moved to
 * apps/shared/design-tokens.css — it's a genuinely shared component (same
 * "yeja-" prefix convention as .yeja-pill-btn), and the theme control is
 * moving out of the sidebar's Settings submenu into the Themes app itself
 * (apps/themes doesn't load this stylesheet, only design-tokens.css).
 */

.button.secondary {
  background: transparent;
  color: var(--ink);
}

.button.secondary:hover {
  background: var(--yeja-active-hover, #FFFFFF);
}

html[data-theme="dark"] .button.secondary {
  color: var(--paper);
}
html[data-theme="dark"] .button.secondary:hover {
  background: var(--yeja-active-hover, #2D2D30);
}

/* .button.danger — added 2026-07-13 (Phase 3, My Studio retrofit): no
 * matching selector existed for this class anywhere, despite real
 * consumers (e.g. apps/my_studio/app.js's delete-confirmation dialog,
 * `class="button danger"`) — those buttons rendered as a plain
 * .button with no red/destructive signal at all, a real pre-existing
 * gap found while auditing this file for the design migration. */
.button.danger {
  background: var(--yeja-crimson);
  border-color: var(--yeja-crimson);
  color: #FFFFFF;
}
.button.danger:hover {
  opacity: 0.85;
  background: var(--yeja-crimson);
}
/* BUG FIXED (found via CDP verification): html[data-theme="dark"] .button
 * (line 773, specificity 0,2,1 — a type selector + attribute selector +
 * class) beat .button.danger's 0,2,0 regardless of source order, so the
 * dark-mode gray override always won and the destructive action was
 * visually indistinguishable from a normal button in dark mode. Needs
 * the same html[data-theme="dark"] prefix .button.secondary already
 * uses above, for equal (0,3,1) specificity that wins on source order. */
html[data-theme="dark"] .button.danger {
  background: var(--yeja-crimson);
  border-color: var(--yeja-crimson);
  color: #FFFFFF;
}
html[data-theme="dark"] .button.danger:hover {
  opacity: 0.85;
  background: var(--yeja-crimson);
}

/* Disabled state — Master Design Guide §4 "Accessibility and System
 * States": 50% opacity + pointer-events: none, not a separate greyed
 * color scheme (that was the prior behavior here). */
.button.disabled,
.button:disabled {
  opacity: 0.5;
  pointer-events: none;
}

.icon-action {
  width: 42px;
  padding: 0;
  background: transparent;
  color: var(--ink);
}

.logout-chip {
  background: transparent;
  color: var(--ink);
}

.icon-action span {
  width: 16px;
  height: 20px;
  border: 2px solid currentColor;
  border-radius: 10px 10px 6px 6px;
  position: relative;
}

.icon-action span::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -7px;
  width: 7px;
  height: 2px;
  background: currentColor;
  transform: translateX(-50%);
}

.app-main {
  min-height: calc(100vh - var(--topbar-height));
  padding: clamp(1rem, 2.2vw, 2rem);
}

/* Full-bleed layouts (My Studio, etc.) — no padding, fixed height */
.app-main.studio-mode {
  padding: 0;
  min-height: 0;
  height: calc(100vh - var(--topbar-height));
  overflow: hidden;
}

.page-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1rem;
}

.eyebrow {
  margin: 0 0 0.45rem;
  color: var(--rust);
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

h1,
h2,
h3,
p {
  margin-top: 0;
}

h1 {
  margin-bottom: 0;
  font-family: var(--font-family-base, "Inter", system-ui, sans-serif);
  font-size: clamp(2.2rem, 4vw, 4.6rem);
  font-weight: 700;
  letter-spacing: 0;
  line-height: 1;
}

h2 {
  margin-bottom: 0.75rem;
  font-family: var(--font-family-base, "Inter", system-ui, sans-serif);
  font-size: clamp(1.7rem, 2.4vw, 2.8rem);
  font-weight: 700;
  letter-spacing: 0;
  line-height: 1.05;
}

h3 {
  margin-bottom: 0.55rem;
  font-size: 1rem;
}

.lede {
  max-width: 54rem;
  color: var(--muted);
  font-size: 1rem;
}

.suite-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  border: 1px solid var(--line);
  background: var(--line);
}

.front-hero {
  min-height: min(720px, calc(100vh - 116px));
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(360px, 0.72fr);
  align-items: stretch;
  gap: clamp(1rem, 3vw, 2rem);
  border-bottom: 1px solid var(--line);
  padding-bottom: clamp(1.5rem, 4vw, 3rem);
}

.front-copy {
  display: grid;
  align-content: center;
  justify-items: start;
  min-height: 460px;
}

.front-copy h1 {
  max-width: 13ch;
  font-size: clamp(3.2rem, 7vw, 7.6rem);
}

.front-copy .lede {
  max-width: 42rem;
  margin-top: 1rem;
  font-size: clamp(1rem, 1.4vw, 1.2rem);
}

.front-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 1.4rem;
}

.front-artwork {
  position: relative;
  min-height: 520px;
  display: block;
  overflow: hidden;
  background: var(--charcoal);
}

.front-artwork img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
}

.front-artwork span {
  position: absolute;
  right: 1rem;
  bottom: 1rem;
  left: 1rem;
  display: grid;
  gap: 0.2rem;
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  color: var(--ink);
  padding: 1rem;
}

.front-artwork strong,
.front-categories {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  border: 1px solid var(--line);
  border-top: 0;
  background: var(--surface);
}

.front-categories a {
  min-height: 58px;
  display: grid;
  place-items: center;
  border-right: 1px solid var(--line);
  color: var(--muted);
  font-size: 0.78rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.front-categories a:last-child {
  border-right: 0;
}

.front-categories a:hover {
  background: var(--charcoal);
  /* was #fffdf8, the pre-warm-ramp cream that --yeja-gray-0 replaced
     (backlog be492b49). Foreground on the charcoal hover fill. */
  color: var(--yeja-gray-0);
}

html[data-theme="dark"] .front-categories a:hover {
  background: var(--surface-alt);
  color: var(--ink);
}

.front-section {
  padding: clamp(2rem, 5vw, 4.5rem) 0 1rem;
}

.front-section h2 {
  max-width: 14ch;
  font-size: clamp(2rem, 4vw, 4.8rem);
}

.front-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
  gap: 1rem;
}

.front-split .muted {
  max-width: 46rem;
}

.featured-strip {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1px;
  border: 1px solid var(--line);
  background: var(--line);
}

.featured-work {
  min-height: 390px;
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  background: var(--surface);
}

.featured-work img {
  width: 100%;
  height: 100%;
  min-height: 300px;
  object-fit: cover;
}

.featured-work div {
  padding: 1rem;
}

.featured-work:hover {
  background: var(--ink);
  color: var(--paper);
}

.featured-work:hover .muted {
  color: color-mix(in srgb, var(--paper) 76%, transparent);
}

.front-suite-grid {
  margin-top: 1rem;
}

.product-card {
  position: relative;
}

.product-badge {
  position: absolute;
  top: 1rem;
  right: 1rem;
  min-width: 44px;
  min-height: 28px;
  display: inline-grid;
  place-items: center;
  border: 1px solid var(--line);
  color: var(--rust);
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.editorial-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.72fr);
  grid-auto-rows: minmax(210px, auto);
  gap: 1px;
  border: 1px solid var(--line);
  background: var(--line);
  margin-top: clamp(2rem, 5vw, 4rem);
}

.suite-card,
.panel,
.metric,
.reward-card,
.rfp-row,
.influencer-card,
.event-card,
.gate-panel,
.feature-band article {
  background: var(--surface);
}

.suite-card {
  min-height: 220px;
  display: grid;
  align-content: space-between;
  gap: 1rem;
  padding: 1rem;
}

.suite-card p,
.metric span,
.muted {
  color: var(--muted);
}

.app-layout {
  display: grid;
  gap: 1rem;
}

.three-pane {
  grid-template-columns: 260px minmax(0, 1fr) 330px;
  align-items: stretch;
}

.two-pane {
  grid-template-columns: minmax(0, 1.1fr) minmax(300px, 0.55fr);
}

.panel {
  border: 1px solid var(--line);
  padding: 1rem;
}

.folder-list,
.tag-list,
.bid-ledger,
.calendar-list,
.rfp-list,
.kanban-column {
  display: grid;
  gap: 0.45rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.folder-list li,
.tag-list li,
.calendar-list li,
.bid-ledger li {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  color: var(--muted);
  font-size: 0.86rem;
}

.asset-table {
  width: 100%;
  border-collapse: collapse;
  background: var(--surface);
}

.asset-table th,
.asset-table td {
  border-bottom: 1px solid var(--line);
  padding: 0.7rem;
  text-align: left;
  vertical-align: middle;
}

.asset-table th {
  color: var(--muted);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.thumb {
  width: 54px;
  aspect-ratio: 1;
  background: var(--surface-alt);
  object-fit: cover;
}

.inspector-image,
.hero-media,
.inspector-image img,
.hero-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.field-stack {
  display: grid;
  gap: 0.8rem;
  margin: 1rem 0;
}

.field-stack label {
  display: grid;
  gap: 0.35rem;
  color: var(--muted);
  font-size: 0.78rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.field-stack input,
.field-stack textarea,
.filter-row select {
  min-height: 40px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  padding: 0.6rem;
}

.gallery-filters,
.metrics-row,
.influencer-grid,
.events-row,
.reward-stack {
  display: grid;
  gap: 1rem;
}

.gallery-filters {
  grid-template-columns: repeat(4, minmax(0, 1fr));
  position: sticky;
  top: 68px;
  z-index: 4;
  border: 1px solid var(--line);
  background: var(--paper);
  padding: 0.75rem;
}

.filter-row {
  display: grid;
  gap: 0.35rem;
  color: var(--muted);
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.masonry {
  columns: 4 220px;
  column-gap: 1rem;
}

.masonry figure {
  break-inside: avoid;
  margin: 0 0 1rem;
}

.masonry img {
  width: 100%;
  background: var(--surface-alt);
}

.masonry figcaption {
  padding-top: 0.4rem;
  color: var(--muted);
  font-size: 0.86rem;
}

.modal-preview {
  display: grid;
  grid-template-columns: 3fr 1fr;
  min-height: 360px;
  border: 1px solid var(--line);
  background: var(--surface);
}

.modal-art {
  background: var(--charcoal);
}

.modal-art img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.modal-meta {
  padding: 1rem;
}

.metrics-row {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

.metric {
  border: 1px solid var(--line);
  padding: 1rem;
}

.metric strong {
  display: block;
  font-size: 1.7rem;
}

.metric small {
  display: block;
  color: var(--rust);
  font-size: 0.74rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.sparkline {
  height: 38px;
  margin-top: 0.75rem;
  background: linear-gradient(135deg, transparent 45%, var(--blue) 46%, var(--blue) 51%, transparent 52%);
  background-size: 38px 38px;
}

.calendar-grid {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  border: 1px solid var(--line);
  background: var(--line);
  gap: 1px;
}

.calendar-day {
  min-height: 132px;
  background: var(--surface);
  padding: 0.75rem;
}

.calendar-day strong {
  display: block;
  margin-bottom: 0.45rem;
}

.influencer-grid {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

.influencer-card,
.event-card,
.reward-card,
.rfp-row {
  border: 1px solid var(--line);
  padding: 1rem;
}

.auction-live {
  grid-template-columns: minmax(0, 1.25fr) minmax(320px, 0.6fr);
}

.countdown {
  font-size: clamp(2.8rem, 6vw, 6rem);
  font-weight: 800;
  line-height: 1;
}

.current-bid {
  color: #f4c177;
  font-size: 2rem;
  font-weight: 800;
}

.bid-ledger li {
  color: rgba(255, 253, 248, 0.74);
}

.events-row {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

.rfp-board {
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
}

.rfp-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 1rem;
}

.kanban {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1px;
  border: 1px solid var(--line);
  background: var(--line);
}

.kanban-column {
  min-height: 360px;
  background: var(--surface);
  padding: 0.75rem;
}

.kanban-card {
  border: 1px solid var(--line);
  background: var(--paper);
  padding: 0.75rem;
}

.campaign-layout {
  grid-template-columns: minmax(0, 1fr) minmax(300px, 360px);
}

.campaign-hero {
  background: var(--surface);
  border: 1px solid var(--line);
}

.campaign-copy {
  padding: 1rem;
}

.progress {
  height: 12px;
  overflow: hidden;
  background: var(--surface-alt);
}

.progress span {
  display: block;
  height: 100%;
  background: var(--olive);
}

.reward-stack {
  align-content: start;
}

.feature-band {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  border: 1px solid var(--line);
  background: var(--line);
  margin: 1rem 0;
}

.feature-band.tight {
  margin-top: 0;
}

.feature-band article {
  min-height: 150px;
  padding: 1rem;
}

.gate-panel {
  display: grid;
  gap: 0.65rem;
  border: 1px solid var(--line);
  margin: 1rem 0;
  padding: 1rem;
}

.gate-panel h3 {
  margin-bottom: 0;
}

.verified-inline {
  display: grid;
  gap: 0.15rem;
  border: 1px solid rgba(89, 107, 86, 0.45);
  background: rgba(89, 107, 86, 0.1);
  color: var(--olive);
  margin: 1rem 0;
  padding: 0.8rem;
}

.verified-inline span,
.verification-badge span {
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.profile-hero,
.profile-grid,
.dashboard-section {
  margin-bottom: 1rem;
}

.profile-hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(240px, 320px);
  gap: 1rem;
  align-items: stretch;
}

.verification-badge {
  display: grid;
  align-content: center;
  gap: 0.3rem;
  border: 1px solid var(--line);
  background: var(--surface);
  padding: 1rem;
}

.verification-badge strong {
  font-family: var(--font-family-base, "Inter", system-ui, sans-serif);
  font-size: 1.8rem;
  font-weight: 700;
  letter-spacing: 0;
  line-height: 1.05;
}

.verification-badge.is-verified {
  border-color: rgba(89, 107, 86, 0.45);
  background: rgba(89, 107, 86, 0.1);
  color: var(--olive);
}

.profile-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(320px, 0.7fr);
  gap: 1rem;
}

.field-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.8rem;
}

.field-grid label,
.check-row {
  display: grid;
  gap: 0.35rem;
  color: var(--muted);
  font-size: 0.78rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.field-grid input,
.field-grid select {
  min-width: 0;
  min-height: 42px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  padding: 0.65rem;
}

.checklist {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.65rem;
  margin: 1rem 0;
}

.check-row {
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  border: 1px solid var(--line);
  background: var(--paper);
  padding: 0.75rem;
  text-transform: none;
  letter-spacing: 0;
}

.check-row input {
  width: 18px;
  height: 18px;
  margin-top: 0.15rem;
  accent-color: var(--olive);
}

.check-row small {
  display: block;
  margin-top: 0.2rem;
  color: var(--muted);
  font-weight: 500;
}

.profile-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.65rem;
}

.unlock-list,
.revenue-list,
.asset-performance {
  display: grid;
  gap: 0.65rem;
}

.unlock-list article,
.revenue-list div,
.asset-performance div {
  border: 1px solid var(--line);
  background: var(--paper);
  padding: 0.75rem;
}

.unlock-list article.unlocked {
  border-color: rgba(89, 107, 86, 0.45);
  background: rgba(89, 107, 86, 0.1);
}

.revenue-list div {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
}

.revenue-list span {
  color: var(--muted);
}

.asset-performance div {
  position: relative;
  padding-right: 4rem;
}

.asset-performance span {
  position: absolute;
  top: 0.75rem;
  right: 0.75rem;
  width: 42px;
  height: 42px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line);
  border-radius: 50%;
  color: var(--blue);
  font-weight: 800;
}

.dashboard-section {
  border: 1px solid var(--line);
  background: var(--surface);
  padding: 1rem;
}

@media (max-width: 1100px) {
  .suite-grid,
  .front-hero,
  .three-pane,
  .two-pane,
  .auction-live,
  .rfp-board,
  .campaign-layout,
  .profile-hero,
  .profile-grid {
    grid-template-columns: 1fr;
  }

  .metrics-row,
  .front-categories,
  .featured-strip,
  .gallery-filters,
  .influencer-grid,
  .events-row,
  .kanban,
  .editorial-grid,
  .feature-band {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .front-artwork {
    min-height: 420px;
  }
}

@media (max-width: 760px) {
  /* Shell breakout (2026-07-14): app switching lives in the avatar
   * dropdown (not a top-bar row) — the top bar wraps to two rows on
   * narrow viewports instead (brand+L2-tabs on row 1, search on row 2),
   * matching Experimental's own @media (max-width: 640px) behavior of
   * hiding/collapsing .search-wrap rather than trying to keep a 3-zone
   * single row at small widths. */
  .topbar {
    flex-wrap: wrap;
  }
  .search-wrap {
    order: 3;
    flex: 1 1 100%;
    max-width: none;
    margin: 8px 0 0;
  }

  #app-canvas {
    background-attachment: scroll !important;
  }

  .icon-action,
  .account-chip,
  .logout-chip,
  .platform-theme-control {
    justify-self: start;
  }

  .page-head {
    align-items: flex-start;
    flex-direction: column;
  }

  .front-hero {
    min-height: auto;
    padding-bottom: 1.25rem;
  }

  .front-copy {
    min-height: auto;
  }

  .front-copy h1 {
    max-width: 11ch;
  }

  .front-artwork {
    min-height: 360px;
  }

  .front-split {
    grid-template-columns: 1fr;
    align-items: start;
  }

  .metrics-row,
  .front-categories,
  .featured-strip,
  .gallery-filters,
  .influencer-grid,
  .events-row,
  .kanban,
  .editorial-grid,
  .feature-band,
  .field-grid,
  .checklist {
    grid-template-columns: 1fr;
  }

  .front-categories a {
    min-height: 48px;
  }

  .featured-work {
    min-height: 300px;
  }
}

/* ── My Studio ──────────────────────────────────────────────────────────────── */

.studio-layout {
  display: grid;
  grid-template-columns: 1fr 0px;
  grid-template-rows: 1fr;
  height: 100%;
  overflow: hidden;
  transition: grid-template-columns 0.22s ease;
}
.studio-layout.detail-open {
  grid-template-columns: 1fr 340px;
}

/* Sidebar */
.studio-sidebar {
  border-right: 1px solid var(--line);
  overflow-y: auto;
  padding: 1.25rem 0.875rem;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.folder-tree {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.folder-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 0.4rem 0.6rem;
  border-radius: 6px;
  border: none;
  background: transparent;
  color: var(--ink);
  font-size: 0.825rem;
  font-family: inherit;
  cursor: pointer;
  text-align: left;
  transition: background 0.12s;
}
.folder-item:hover      { background: var(--surface-alt); }
.folder-item.active     { background: var(--surface-alt); font-weight: 600; }
.folder-item span       { font-size: 0.75rem; color: var(--muted); }
.folder-add {
  margin-top: 4px;
  padding: 0.35rem 0.6rem;
  border: 1px dashed var(--line);
  border-radius: 6px;
  background: transparent;
  color: var(--muted);
  font-size: 0.8rem;
  font-family: inherit;
  cursor: pointer;
  text-align: left;
  width: 100%;
}
.folder-add:hover { border-color: var(--gold); color: var(--gold); }

.sidebar-section h4 {
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--muted);
  margin-bottom: 0.5rem;
}

.filter-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.chip {
  padding: 0.25rem 0.6rem;
  border-radius: 20px;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--muted);
  font-size: 0.75rem;
  font-family: inherit;
  cursor: pointer;
  transition: all 0.12s;
}
.chip:hover  { border-color: var(--ink); color: var(--ink); }
.chip.active { background: var(--ink); color: var(--paper); border-color: var(--ink); }

.tag-cloud { display: flex; flex-wrap: wrap; gap: 4px; }
.tag-chip {
  padding: 0.2rem 0.5rem;
  border-radius: 20px;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--muted);
  font-size: 0.72rem;
  font-family: inherit;
  cursor: pointer;
}
.tag-chip span { opacity: 0.6; }
.tag-chip:hover { border-color: var(--gold); color: var(--gold); }

/* Center pane */
.studio-center {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.studio-toolbar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.75rem 1.25rem;
  border-bottom: 1px solid var(--line);
  flex-shrink: 0;
}
.studio-search-input {
  flex: 1;
  min-width: 0;
  padding: 0.4rem 0.75rem;
  border-radius: 6px;
  border: 1px solid var(--line);
  background: var(--surface-alt);
  color: var(--ink);
  font-size: 0.875rem;
  font-family: inherit;
}
.studio-search-input:focus { outline: none; border-color: var(--gold); }
.studio-toolbar select {
  padding: 0.4rem 0.6rem;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface);
  color: var(--ink);
  font-size: 0.8rem;
  font-family: inherit;
  cursor: pointer;
}
.view-toggle { display: flex; gap: 2px; }
.view-toggle button {
  padding: 0.35rem 0.55rem;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--muted);
  font-size: 0.9rem;
  border-radius: 5px;
  cursor: pointer;
}
.view-toggle button.active { background: var(--ink); color: var(--paper); border-color: var(--ink); }

/* Grid */
.studio-grid {
  flex: 1;
  overflow-y: auto;
  padding: 1.25rem;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 0.875rem;
  align-content: start;
  position: relative;
}
.studio-grid.drag-over {
  outline: 2px dashed var(--gold);
  outline-offset: -4px;
  background: color-mix(in srgb, var(--gold) 5%, transparent);
}
.studio-grid.list-view {
  grid-template-columns: 1fr;
  gap: 0;
}

.thumb-placeholder {
  width: 100%; height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2rem;
  font-family: var(--font-family-base, "Inter", system-ui, sans-serif);
  font-weight: 700;
  color: var(--muted);
  background: var(--surface-alt);
  aspect-ratio: 4/3;
}

/* List view */
.list-thumb {
  width: 48px; height: 36px;
  border-radius: 4px;
  overflow: hidden;
  flex-shrink: 0;
  background: var(--surface-alt);
}
.list-thumb img { width: 100%; height: 100%; object-fit: cover; }
.list-thumb .thumb-placeholder {
  width: 48px; height: 36px;
  font-size: 1rem;
  aspect-ratio: unset;
}
.list-meta {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.list-meta strong { font-size: 0.85rem; }
.list-meta span   { font-size: 0.75rem; color: var(--muted); }
.list-right {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-shrink: 0;
}
.list-right small { font-size: 0.72rem; color: var(--muted); }

/* .status-chip -> apps/shared/components.css's .yeja-status-chip (Phase
 * 4, 2026-07-19). This block was a byte-identical duplicate of My
 * Studio's own local copy (apps/my_studio/styles.css) — since THIS
 * file is always linked in apps/platform/index.html (never
 * conditionally injected, unlike every app's own styles.css), it was
 * the actual real winner of the cross-app .status-chip collision
 * platform-wide the whole time, not just a contributor to it. Removed
 * along with My Studio's copy; both now use studioStatusChip()'s
 * bucket mapping in apps/my_studio/app.js. */

/* Skeleton */
.studio-skeletons {
  display: contents;
}
@keyframes shimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* Empty state */
.studio-empty {
  grid-column: 1 / -1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  padding: 4rem 2rem;
  color: var(--muted);
  text-align: center;
}

/* Detail panel */
.studio-detail {
  border-left: 1px solid var(--line);
  overflow-y: auto;
  padding: 1.25rem;
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0;
}
.detail-close {
  position: absolute;
  top: 0.875rem; right: 0.875rem;
  border: none;
  background: transparent;
  color: var(--muted);
  font-size: 0.85rem;
  cursor: pointer;
  padding: 0.25rem 0.4rem;
  border-radius: 4px;
}
.detail-close:hover { background: var(--surface-alt); color: var(--ink); }

.detail-thumb {
  border-radius: 8px;
  overflow: hidden;
  background: var(--surface-alt);
  margin-bottom: 1rem;
}
.detail-thumb img { width: 100%; object-fit: contain; max-height: 220px; }
.detail-thumb-placeholder {
  height: 180px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 3rem;
  font-family: var(--font-family-base, "Inter", system-ui, sans-serif);
  font-weight: 700;
  color: var(--muted);
}

.detail-tabs {
  display: flex;
  gap: 2px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 1rem;
}
.detail-tab {
  padding: 0.45rem 0.75rem;
  border: none;
  background: transparent;
  color: var(--muted);
  font-size: 0.8rem;
  font-family: inherit;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.detail-tab.active { color: var(--ink); border-bottom-color: var(--gold); font-weight: 600; }

.detail-tab-content {
  flex: 1;
  overflow-y: auto;
  padding-top: 0.5rem;
}

/* Detail panel header */
.detail-title {
  font-family: inherit;
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.3;
  margin-bottom: 0.35rem;
  word-break: break-word;
}
.detail-header {
  margin-bottom: 0.75rem;
}
.detail-badges {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.25rem;
}

/* Detail form */
#detail-form label,
#artwork-edit-form label,
#share-form label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 0.78rem;
  color: var(--muted);
  margin-bottom: 0.6rem;
}
#detail-form input,
#detail-form select,
#detail-form textarea,
#artwork-edit-form input,
#artwork-edit-form select,
#artwork-edit-form textarea,
#share-form input,
#share-form select,
#share-form textarea {
  padding: 0.4rem 0.6rem;
  border-radius: 5px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font-size: 0.85rem;
  font-family: inherit;
}
#detail-form input:focus,
#detail-form textarea:focus,
#artwork-edit-form input:focus,
#artwork-edit-form textarea:focus,
#share-form input:focus { outline: none; border-color: var(--gold); }
#detail-form textarea,
#artwork-edit-form textarea { resize: vertical; min-height: 72px; }

.dim-row {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 4px;
}
.toggle-row {
  flex-direction: row !important;
  align-items: center;
  gap: 0.5rem !important;
}
.detail-actions,
.detail-actions-row {
  display: flex;
  gap: 0.5rem;
  margin-top: 0.75rem;
  flex-wrap: wrap;
}
.detail-file-info { margin: 0.5rem 0; }
.mint-section { margin-top: 1rem; padding-top: 1rem; border-top: 1px solid var(--line); }

/* Share list */
.share-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.6rem 0;
  border-bottom: 1px solid var(--line);
}
.share-row strong { display: block; font-size: 0.825rem; }
.share-row small  { display: block; font-size: 0.72rem; color: var(--muted); }
.share-actions    { display: flex; gap: 4px; flex-shrink: 0; }

/* Activity log */
.activity-log {
  list-style: none;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0;
}
.activity-log li {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  padding: 0.55rem 0;
  border-bottom: 1px solid var(--line);
}
.log-icon { font-size: 0.9rem; flex-shrink: 0; padding-top: 1px; }
.log-meta strong { display: block; font-size: 0.8rem; }
.log-meta small  { display: block; font-size: 0.72rem; color: var(--muted); }

/* Upload queue */
.upload-queue {
  position: fixed;
  bottom: 1.5rem;
  right: 1.5rem;
  width: 300px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 0.875rem 1rem;
  box-shadow: 0 8px 32px rgba(0,0,0,0.12);
  z-index: 300;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}
.queue-item {
  display: flex;
  justify-content: space-between;
  font-size: 0.8rem;
  padding: 0.2rem 0;
}
.queue-item span:first-child {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1;
  padding-right: 0.5rem;
}
.qi-status { color: var(--muted); flex-shrink: 0; }

/* Toasts */
.studio-toast-container {
  position: fixed;
  bottom: 1.5rem;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  z-index: 400;
  pointer-events: none;
}
.studio-toast {
  padding: 0.55rem 1.1rem;
  border-radius: 20px;
  font-size: 0.825rem;
  font-weight: 500;
  animation: toast-in 0.2s ease;
  pointer-events: none;
}
.studio-toast-success { background: var(--ink); color: var(--paper); }
.studio-toast-error   { background: var(--yeja-crimson, #E53935); color: #fff; }
.studio-toast-info    { background: var(--gold); color: #fff; }
@keyframes toast-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}


/* ── Section layout (shared by Gallery, Broadcast, Auctions, Commissions, Campaigns, Profile) ── */

.section-layout {
  display: grid;
  grid-template-columns: 1fr;
  height: 100%;
  overflow: hidden;
}
.section-layout.two-pane {
  grid-template-columns: 220px 1fr;
}

.section-sidebar {
  border-right: 1px solid var(--line);
  overflow-y: auto;
  padding: 1.25rem 0.875rem;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.section-center {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.section-toolbar {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem 1.25rem;
  border-bottom: 1px solid var(--line);
  flex-shrink: 0;
}
.section-title {
  font-size: 1rem;
  font-weight: 600;
  flex: 1;
}

/* ── Content grid (Gallery, Broadcast influencer cards) ── */

.content-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 1rem;
  padding: 1.25rem;
  overflow-y: auto;
  align-content: start;
}
.content-grid.cols-3 {
  grid-template-columns: repeat(3, 1fr);
}

.card-sub {
  font-size: 0.75rem;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.card-price {
  font-size: 0.825rem;
  font-weight: 600;
  color: var(--ink);
  margin-top: 2px;
}

/* ── Metrics strip (Broadcast) ── */

.metrics-strip {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0;
  border-bottom: 1px solid var(--line);
  flex-shrink: 0;
}
.metric-tile {
  padding: 1rem 1.25rem;
  border-right: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.metric-tile:last-child { border-right: none; }
.metric-tile span  { font-size: 0.72rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; }
.metric-tile strong { font-size: 1.35rem; font-weight: 700; font-family: var(--font-family-base, "Inter", system-ui, sans-serif); }
.metric-tile small  { font-size: 0.72rem; font-weight: 500; }
.trend-up   { color: var(--yeja-mint, #43A047); }
.trend-down { color: var(--yeja-crimson, #E53935); }

/* ── Queue list (Broadcast schedule) ── */

.queue-list {
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  padding: 0 1.25rem;
}
.queue-row {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.75rem 0;
  border-bottom: 1px solid var(--line);
}
.queue-day {
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--muted);
  width: 48px;
  flex-shrink: 0;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.queue-body {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
  flex-wrap: wrap;
}
.queue-type {
  font-size: 0.7rem;
  font-weight: 600;
  padding: 0.15rem 0.45rem;
  border-radius: 4px;
  background: var(--surface-alt);
  color: var(--muted);
  flex-shrink: 0;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.queue-text {
  font-size: 0.85rem;
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.queue-channel {
  font-size: 0.72rem;
  color: var(--muted);
  flex-shrink: 0;
}
.filter-chips.vertical {
  flex-direction: column;
  gap: 2px;
}
.filter-chips.vertical .chip {
  text-align: left;
  border-radius: 6px;
}

/* ── Auction live panel ── */

.auction-live-panel {
  display: grid;
  grid-template-columns: 1fr 280px;
  flex: 1;
  overflow: hidden;
}
.live-stage {
  overflow-y: auto;
  padding: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.875rem;
}
.live-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--yeja-crimson, #E53935);
  padding: 0.3rem 0.7rem;
  border-radius: 20px;
  border: 1px solid currentColor;
  width: fit-content;
  animation: pulse-badge 2s ease infinite;
}
@keyframes pulse-badge {
  0%, 100% { opacity: 1; }
  50%       { opacity: 0.65; }
}
.live-artwork {
  border-radius: 10px;
  overflow: hidden;
  background: var(--surface-alt);
  max-height: 360px;
}
.live-artwork img {
  width: 100%;
  max-height: 360px;
  object-fit: contain;
  display: block;
}
.live-info { display: flex; flex-direction: column; gap: 0.4rem; }
.live-info h2 { margin: 0; font-size: 1.25rem; }
.live-timer {
  font-size: 2.5rem;
  font-family: var(--font-family-base, "Inter", system-ui, sans-serif);
  font-weight: 700;
  color: var(--gold);
  letter-spacing: -0.02em;
  line-height: 1;
  margin: 0.25rem 0;
}
.current-bid {
  font-size: 1.75rem;
  font-weight: 700;
  font-family: var(--font-family-base, "Inter", system-ui, sans-serif);
  letter-spacing: -0.02em;
  color: var(--ink);
  margin: 0;
}
.bid-ledger-panel {
  border-left: 1px solid var(--line);
  padding: 1.25rem;
  overflow-y: auto;
}
.bid-ledger-panel h4 {
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--muted);
  margin-bottom: 0.75rem;
}
.bid-ledger-list {
  list-style: none;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0;
}
.bid-ledger-list li {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.55rem 0;
  border-bottom: 1px solid var(--line);
  font-size: 0.82rem;
}
.bid-ledger-list li:first-child { background: color-mix(in srgb, var(--gold) 6%, transparent); border-radius: 4px; }
.bid-id { flex: 1; color: var(--muted); }
.bid-ledger-list strong { font-weight: 600; }
.bid-ledger-list small  { font-size: 0.7rem; color: var(--muted); flex-shrink: 0; }

/* ── RFP list (Public Art Commissions) ── */

.rfp-list-new {
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  padding: 0 1.25rem 1.25rem;
}
.rfp-card {
  border-bottom: 1px solid var(--line);
  cursor: pointer;
  transition: background 0.12s;
}
.rfp-card:hover { background: var(--surface-alt); margin: 0 -1.25rem; padding: 0 1.25rem; }
.rfp-card-body {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.875rem 0;
}
.rfp-title {
  display: block;
  font-size: 0.925rem;
  font-weight: 600;
  margin-bottom: 3px;
}
.rfp-meta {
  display: block;
  font-size: 0.75rem;
  color: var(--muted);
}
.rfp-right {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
  flex-shrink: 0;
}
.rfp-right strong { font-size: 0.925rem; font-weight: 600; }

/* ── Campaign list (Fundraisers) ── */

.campaign-list {
  display: flex;
  flex-direction: column;
  gap: 0;
  overflow-y: auto;
  padding: 0 1.25rem 1.25rem;
}
.campaign-card {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 1rem 0;
  border-bottom: 1px solid var(--line);
  cursor: pointer;
}
.campaign-card:hover .campaign-thumb img { transform: scale(1.04); }
.campaign-thumb {
  width: 80px;
  height: 60px;
  border-radius: 6px;
  overflow: hidden;
  flex-shrink: 0;
  background: var(--surface-alt);
}
.campaign-thumb img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 0.2s;
}
.campaign-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}
.campaign-progress { display: flex; flex-direction: column; gap: 4px; }
.progress-bar {
  height: 4px;
  border-radius: 2px;
  background: var(--line);
  overflow: hidden;
}
.progress-fill {
  height: 100%;
  border-radius: 2px;
  background: var(--gold);
  transition: width 0.4s ease;
}
.progress-meta {
  display: flex;
  justify-content: space-between;
  font-size: 0.72rem;
  color: var(--muted);
}
.progress-meta strong { color: var(--ink); }

/* ── Profile sidebar ── */

.profile-identity {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 0.4rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid var(--line);
}
.profile-identity strong { font-size: 0.925rem; font-weight: 600; }
.profile-avatar {
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: var(--gold);
  color: var(--paper);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.25rem;
  font-family: var(--font-family-base, "Inter", system-ui, sans-serif);
  font-weight: 700;
  flex-shrink: 0;
}
.unlock-list-small {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.unlock-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.8rem;
  color: var(--muted);
  padding: 0.25rem 0;
}
.unlock-row.unlocked { color: var(--ink); }
.unlock-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--line);
  flex-shrink: 0;
}
.unlock-row.unlocked .unlock-dot { background: var(--gold); }

/* ── Profile center panels ── */

.profile-panels {
  display: grid;
  grid-template-columns: 1fr 300px;
  gap: 0;
  flex: 1;
  overflow: hidden;
}
.profile-form-card {
  border-right: 1px solid var(--line);
  overflow-y: auto;
  padding: 1.5rem;
}
.profile-form-card h3 {
  font-size: 0.875rem;
  font-weight: 600;
  margin-bottom: 0.75rem;
}
.profile-stats-card {
  overflow-y: auto;
  padding: 1.5rem;
}
.profile-stats-card h3 {
  font-size: 0.875rem;
  font-weight: 600;
  margin-bottom: 0.75rem;
}
.revenue-list {
  display: flex;
  flex-direction: column;
  gap: 0;
}
.revenue-list div {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.55rem 0;
  border-bottom: 1px solid var(--line);
  font-size: 0.825rem;
}
.revenue-list div span  { color: var(--muted); }
.revenue-list div strong { font-weight: 600; }

/* ── Section layout mobile ── */

@media (max-width: 768px) {
  .section-layout.two-pane {
    grid-template-columns: 1fr;
  }
  .section-layout.two-pane .section-sidebar {
    display: none;
  }
  .auction-live-panel {
    grid-template-columns: 1fr;
  }
  .bid-ledger-panel {
    border-left: none;
    border-top: 1px solid var(--line);
  }
  .metrics-strip {
    grid-template-columns: 1fr 1fr;
  }
  .profile-panels {
    grid-template-columns: 1fr;
  }
  .profile-form-card {
    border-right: none;
    border-bottom: 1px solid var(--line);
  }
  .content-grid.cols-3 {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* ── Context menu ── */

.context-menu {
  position: fixed;
  z-index: 1000;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0,0,0,.14);
  padding: 0.25rem;
  min-width: 160px;
  animation: ctx-appear 80ms ease;
}

@keyframes ctx-appear {
  from { opacity: 0; transform: scale(0.96); }
  to   { opacity: 1; transform: scale(1); }
}

.ctx-header {
  padding: 0.4rem 0.75rem;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--muted);
}

.ctx-item {
  display: block;
  width: 100%;
  background: none;
  border: none;
  border-radius: 5px;
  padding: 0.45rem 0.75rem;
  text-align: left;
  font-size: 0.875rem;
  color: var(--ink);
  cursor: pointer;
  transition: background 0.1s;
}
.ctx-item:hover { background: var(--paper); }
.ctx-item.danger { color: var(--yeja-crimson, #E53935); }
/* was #fff0f0 (backlog be492b49): a cool pink that sat off against the warm
   ramp and, being a literal, did NOT adapt in dark mode — a pale pink fill
   behind crimson text on a dark menu. --yeja-error-bg is the semantic
   danger-surface token and themes correctly (#FDECEA / #3B1717). */
.ctx-item.danger:hover { background: var(--yeja-error-bg); }

.ctx-divider {
  height: 1px;
  background: var(--line);
  margin: 0.25rem 0;
}

/* ── Nested folders ── */

.folder-node { width: 100%; }

.folder-row {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  border-radius: 6px;
  padding-right: 0.25rem;
  transition: background 0.1s;
}
.folder-row:hover { background: color-mix(in srgb, var(--accent) 8%, transparent); }
.folder-row.active { background: color-mix(in srgb, var(--accent) 14%, transparent); }

.folder-chevron {
  background: none;
  border: none;
  font-size: 0.65rem;
  width: 1.2rem;
  flex-shrink: 0;
  cursor: pointer;
  color: var(--muted);
  padding: 0;
  line-height: 1;
}
.folder-chevron.invisible { visibility: hidden; pointer-events: none; }

.folder-name-btn {
  background: none;
  border: none;
  flex: 1;
  text-align: left;
  padding: 0.4rem 0.25rem;
  font-size: 0.875rem;
  cursor: pointer;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.folder-count {
  font-size: 0.75rem;
  color: var(--muted);
  flex-shrink: 0;
}

.folder-rename,
.folder-delete-btn,
.folder-move-here {
  background: none;
  border: none;
  cursor: pointer;
  font-size: 0.75rem;
  opacity: 0;
  padding: 0.2rem 0.3rem;
  border-radius: 4px;
  transition: opacity 0.1s, background 0.1s;
}
.folder-row:hover .folder-rename,
.folder-row:hover .folder-delete-btn,
.folder-row:hover .folder-move-here { opacity: 1; }
/* was #fff0f0 — same non-theming pink as .ctx-item.danger:hover above. */
.folder-delete-btn:hover { background: var(--yeja-error-bg); color: var(--yeja-crimson, #E53935); }
.folder-move-here { opacity: 1; color: var(--accent); font-weight: 600; }

.folder-children { width: 100%; }

/* ── Bulk bar select-all ── */

.bulk-select-all {
  display: flex;
  align-items: center;
  cursor: pointer;
}
.bulk-select-all input[type="checkbox"] {
  width: 1rem;
  height: 1rem;
  accent-color: var(--gold, var(--accent));
  cursor: pointer;
}

/* ── Lightbox theater preview ─────────────────────────────────────────────── */

.studio-lightbox {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.93);
  z-index: 2000;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* ── Inline dialogs (replace browser prompt/confirm) ─────────────────────── */

.studio-dialog-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  z-index: 3000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
}

.studio-dialog {
  background: var(--surface, #FCFBFA);
  border: 1px solid var(--line, #DEDEDE);
  border-radius: 10px;
  padding: 1.5rem;
  width: 100%;
  max-width: 360px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.18);
  display: flex;
  flex-direction: column;
  gap: 0.875rem;
}

.studio-dialog-label {
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--ink);
  margin: 0;
  line-height: 1.45;
}

.studio-dialog-input {
  width: 100%;
  padding: 0.45rem 0.65rem;
  border: 1px solid var(--line, #DEDEDE);
  border-radius: 6px;
  font-size: 0.9rem;
  background: var(--surface);
  color: var(--ink);
  box-sizing: border-box;
}
.studio-dialog-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 20%, transparent);
}

.studio-dialog-actions {
  display: flex;
  gap: 0.5rem;
  justify-content: flex-end;
}

/* ── Recents section in sidebar ───────────────────────────────────────────── */

#recents-list { display: flex; flex-direction: column; gap: 0.25rem; margin-top: 0.3rem; }

.recent-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.3rem 0.4rem;
  border: none;
  background: none;
  border-radius: 6px;
  cursor: pointer;
  width: 100%;
  text-align: left;
  transition: background 0.12s;
}
.recent-item:hover { background: color-mix(in srgb, var(--accent) 8%, transparent); }

.recent-thumb {
  width: 2rem;
  height: 2rem;
  object-fit: cover;
  border-radius: 4px;
  flex-shrink: 0;
}

.recent-thumb-placeholder {
  width: 2rem;
  height: 2rem;
  background: var(--line, #DEDEDE);
  border-radius: 4px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--muted);
}

.recent-label {
  font-size: 0.8rem;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── List view column headers ────────────────────────────────────────────── */

.list-header {
  display: flex;
  align-items: center;
  padding: 0 0.5rem;
  border-bottom: 1px solid var(--line, #DEDEDE);
  background: var(--surface);
  position: sticky;
  top: 0;
  z-index: 2;
  gap: 0.5rem;
}

.list-header .list-thumb { width: 2.5rem; flex-shrink: 0; }

.col-sort-btn {
  background: none;
  border: none;
  padding: 0.45rem 0.35rem;
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--muted);
  cursor: pointer;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  border-radius: 4px;
  transition: color 0.12s, background 0.12s;
  white-space: nowrap;
}
.col-sort-btn:hover { color: var(--ink); background: color-mix(in srgb, var(--accent) 8%, transparent); }
.col-sort-btn.active { color: var(--ink); }

/* ── Feature: Folder colors ─────────────────────────────────────────────────── */
.folder-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-right: 4px;
  flex-shrink: 0;
  vertical-align: middle;
}
.folder-color-picker {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  padding: 6px 8px;
  background: var(--surface-alt, #FFFFFF);
  border-top: 1px solid var(--line, #DEDEDE);
  border-bottom: 1px solid var(--line, #DEDEDE);
}
.folder-color-swatch {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 2px solid transparent;
  cursor: pointer;
  padding: 0;
  flex-shrink: 0;
  transition: border-color 0.12s, transform 0.1s;
}
.folder-color-swatch:hover { transform: scale(1.2); border-color: var(--ink) !important; }

/* ── Feature: Search typeahead dropdown ─────────────────────────────────────── */
.search-wrap { position: relative; }
.search-dropdown {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 500;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 0 0 8px 8px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.12);
  max-height: 320px;
  overflow-y: auto;
}
.search-result-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  width: 100%;
  border: none;
  background: transparent;
  cursor: pointer;
  text-align: left;
}
.search-result-item:hover { background: var(--surface-alt, #FFFFFF); }
.search-result-thumb {
  width: 32px;
  height: 32px;
  border-radius: 4px;
  object-fit: cover;
  flex: 0 0 32px;
}
.search-result-placeholder {
  background: var(--surface-alt, #FFFFFF);
  display: grid;
  place-items: center;
  font-size: 0.8rem;
  font-weight: 600;
}
.search-result-title {
  flex: 1;
  font-size: 0.8rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── Feature: Notes (artwork comments) ─────────────────────────────────────── */
.notes-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.note-item {
  background: var(--surface-alt, #FFFFFF);
  border-radius: 6px;
  padding: 8px 10px;
}
.note-body {
  font-size: 0.82rem;
  white-space: pre-wrap;
  word-break: break-word;
  margin: 0;
}
.note-meta {
  font-size: 0.7rem;
  color: var(--muted);
  margin-top: 4px;
  display: flex;
  align-items: center;
}

/* ── Feature: Pagination (load more) ───────────────────────────────────────── */
.load-more-row {
  display: flex;
  justify-content: center;
  padding: 1.5rem;
  grid-column: 1 / -1;
}

/* ── Feature: File requests panel ──────────────────────────────────────────── */
.requests-panel h2 { font-size: 1.1rem; font-weight: 700; }
.request-list { display: flex; flex-direction: column; gap: 10px; }
.request-row {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 12px 14px;
  background: var(--surface-alt, #FFFFFF);
  border-radius: 8px;
  border: 1px solid var(--line, #DEDEDE);
}
.request-info { flex: 1; min-width: 0; }
.request-actions { display: flex; gap: 6px; flex-shrink: 0; align-items: center; }

/* ── Drag & drop ── */
.folder-grid-item.drag-over,
.folder-row.drag-over { box-shadow: inset 0 0 0 2px var(--accent, #1E88E5); background: var(--surface-alt); border-radius: 6px; }

/* ── Folder thumbnail collage ── */
.folder-thumb-collage {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
  width: 100%;
  height: 100%;
  overflow: hidden;
}
.folder-thumb-collage img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.folder-thumb-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  font-size: 2.8rem;
  background: var(--surface-alt);
  color: var(--muted);
}
.folder-item-count {
  font-weight: 400;
  color: var(--muted);
  font-size: 0.78em;
}

/* ── Uppy: hide persistent status bar outside modal ── */
#uppy-mount { position: fixed; inset: 0; pointer-events: none; z-index: 9999; }
#uppy-mount .uppy-Dashboard-overlay,
#uppy-mount .uppy-Dashboard { pointer-events: auto; }
#uppy-mount .uppy-StatusBar:not([class*="isUploading"]):not([class*="isComplete"]) { display: none; }

/* ════════════════════════════════════════════════════════════════════════════════ */
/* ─────────────────── COMMON ROOM: Reddit-Style Community ──────────────────────── */
/* ════════════════════════════════════════════════════════════════════════════════ */

.cr-shell { display: flex; flex-direction: column; height: 100vh; }
.cr-topbar {
  display: flex; justify-content: space-between; align-items: center;
  padding: 16px 24px; background: var(--surface); border-bottom: 1px solid var(--line);
  gap: 20px;
}
.cr-brand { display: flex; align-items: center; }
.cr-logo {
  font-weight: 700; font-size: 0.95rem; line-height: 1.1; color: var(--ink);
  text-align: left;
}
.cr-logo span { display: block; font-size: 0.65rem; color: var(--muted); margin-top: 2px; }
.cr-sort select {
  padding: 6px 10px; border: 1px solid var(--line); border-radius: 4px;
  background: var(--surface); color: var(--ink); font-size: 0.85rem; cursor: pointer;
}
.cr-sort select:focus { outline: none; border-color: var(--accent); }

.cr-body { display: flex; flex: 1; overflow: hidden; gap: 0; }
.cr-main { flex: 1; display: flex; flex-direction: column; overflow-y: auto; border-right: 1px solid var(--line); }
.cr-featured {
  padding: 20px 24px; border-bottom: 1px solid var(--line); background: var(--surface-alt);
}
.cr-featured h3 { margin: 0 0 12px; font-size: 0.75rem; text-transform: uppercase; color: var(--muted); font-weight: 600; }
.cr-featured-grid {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px;
}
.cr-featured-item {
  padding: 12px; background: var(--surface); border: 1px solid var(--line); border-radius: 6px; font-size: 0.85rem;
}
.cr-featured-label { font-weight: 600; color: var(--ink); margin-bottom: 4px; }
.cr-featured-item p { margin: 4px 0; color: var(--muted); font-size: 0.75rem; }
.cr-featured-item .button { font-size: 0.7rem; padding: 4px 8px; margin-top: 8px; }

.cr-feed { flex: 1; overflow-y: auto; padding: 20px 24px; }
.cr-composer {
  margin-bottom: 20px; padding-bottom: 16px; border-bottom: 1px solid var(--line);
}
.cr-compose-trigger {
  width: 100%; padding: 12px 16px; text-align: left; background: var(--surface-alt);
  border: 1px solid var(--line); border-radius: 20px; color: var(--muted); cursor: pointer;
  font-size: 0.9rem; transition: all 0.2s;
}
.cr-compose-trigger:hover { background: var(--line); }

.cr-thread-card {
  display: flex; gap: 12px; margin-bottom: 16px; padding: 12px; background: var(--surface);
  border: 1px solid var(--line); border-radius: 6px; transition: all 0.2s;
}
.cr-thread-card:hover { background: var(--surface-alt); border-color: var(--accent); }

.cr-vote-bar {
  display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 0;
  min-width: 40px;
}
.cr-vote {
  background: none; border: none; color: var(--muted); cursor: pointer; font-size: 1.2rem;
  padding: 2px 4px; transition: color 0.2s;
}
.cr-vote:hover { color: var(--accent); }
.cr-vote.active { color: var(--accent); }
.cr-score { font-size: 0.85rem; font-weight: 600; color: var(--ink); }
.cr-score.upvoted { color: #FF4500; }
.cr-score.downvoted { color: #818E8E; }

.cr-thread-content { flex: 1; }
.cr-community-link {
  font-size: 0.75rem; color: var(--muted); text-decoration: none; font-weight: 600;
  transition: color 0.2s;
}
.cr-community-link:hover { color: var(--accent); }
.cr-thread-title {
  margin: 6px 0; font-size: 0.95rem; font-weight: 600; color: var(--ink); line-height: 1.3;
}
.cr-thread-title a { color: var(--ink); text-decoration: none; transition: color 0.2s; }
.cr-thread-title a:hover { color: var(--accent); }
.cr-thread-image { width: 100%; max-height: 180px; border-radius: 6px; margin: 8px 0; object-fit: cover; }
.cr-thread-meta { margin: 8px 0 0; font-size: 0.75rem; color: var(--muted); }
.cr-reply-count { margin-left: 8px; }

.cr-empty {
  text-align: center; padding: 40px 20px; color: var(--muted); font-size: 0.9rem;
}

.cr-sidebar {
  width: 280px; background: var(--surface-alt); border-left: 1px solid var(--line);
  display: flex; flex-direction: column; overflow-y: auto;
}
.cr-sidebar > * { padding: 0 16px; }
.cr-communities, .cr-news {
  border-bottom: 1px solid var(--line); padding: 16px !important;
}
.cr-communities h4, .cr-news h4 {
  margin: 0 0 12px; font-size: 0.75rem; text-transform: uppercase; color: var(--muted);
  font-weight: 600; letter-spacing: 0.5px;
}
.cr-community-list { display: flex; flex-direction: column; gap: 4px; }
.cr-community-item {
  padding: 8px 10px; border-radius: 4px; text-decoration: none; color: var(--ink);
  font-size: 0.85rem; transition: all 0.2s; border-left: 3px solid transparent;
}
.cr-community-item:hover { background: var(--surface); color: var(--accent); }
.cr-community-item.active { background: var(--accent-light); color: var(--accent); border-left-color: var(--accent); font-weight: 600; }
.cr-comm-name { display: block; font-weight: 600; }
.cr-comm-title { display: block; font-size: 0.75rem; color: var(--muted); }

.cr-news-item {
  padding: 12px 0; border-bottom: 1px solid var(--line); font-size: 0.8rem;
}
.cr-news-item:last-child { border-bottom: none; }
.cr-news-title { color: var(--ink); font-weight: 500; margin-bottom: 4px; cursor: pointer; transition: color 0.2s; }
.cr-news-title:hover { color: var(--accent); }
.cr-news-time { color: var(--muted); font-size: 0.7rem; }

.cr-thread-detail {
  padding: 20px; background: var(--surface); border: 1px solid var(--line); border-radius: 8px;
  margin-bottom: 20px;
}
.cr-back-btn { color: var(--accent); text-decoration: none; font-size: 0.9rem; margin-bottom: 16px; display: inline-block; }
.cr-back-btn:hover { text-decoration: underline; }
.cr-thread-header { margin-bottom: 16px; }
.cr-thread-header h2 { margin: 0 0 8px; font-size: 1.2rem; color: var(--ink); }
.cr-thread-main { margin-bottom: 24px; }
.cr-thread-full-image { width: 100%; max-height: 400px; border-radius: 6px; margin-bottom: 16px; object-fit: cover; }
.cr-thread-body { margin: 16px 0; line-height: 1.6; color: var(--ink); }
.cr-thread-stats { margin: 16px 0; font-size: 0.9rem; color: var(--muted); }
.cr-replies { border-top: 1px solid var(--line); padding-top: 16px; }
.cr-replies h3 { margin: 0 0 16px; font-size: 0.95rem; }

/* ──────────────────── COMMON ROOM: Thread Composer & Replies ──────────────────── */

.cr-composer-overlay {
  position: fixed; inset: 0; background: rgba(0,0,0,0.5); display: flex;
  align-items: center; justify-content: center; z-index: 1000; padding: 20px;
}
.cr-composer-overlay[hidden] { display: none !important; }

.cr-composer-modal {
  background: var(--surface); border: 1px solid var(--line); border-radius: 8px;
  width: 100%; max-width: 500px; box-shadow: 0 20px 60px rgba(0,0,0,0.3);
}

.cr-composer-header {
  display: flex; justify-content: space-between; align-items: center;
  padding: 16px 20px; border-bottom: 1px solid var(--line);
}
.cr-composer-header h2 { margin: 0; font-size: 1.1rem; }
.cr-composer-close {
  background: none; border: none; font-size: 1.2rem; cursor: pointer;
  color: var(--muted); transition: color 0.2s;
}
.cr-composer-close:hover { color: var(--ink); }

.cr-composer-body {
  padding: 20px; display: flex; flex-direction: column; gap: 12px;
}

.cr-community-select {
  display: flex; flex-direction: column; gap: 6px; font-size: 0.9rem;
}
.cr-community-select label { font-weight: 600; color: var(--ink); }
.cr-community-select select {
  padding: 8px 10px; border: 1px solid var(--line); border-radius: 4px;
  background: var(--surface); color: var(--ink); cursor: pointer;
}

.cr-composer-input {
  padding: 10px 12px; border: 1px solid var(--line); border-radius: 4px;
  background: var(--surface); color: var(--ink); font-size: 0.95rem; font-weight: 600;
}
.cr-composer-input:focus { outline: none; border-color: var(--accent); }

.cr-composer-textarea {
  padding: 10px 12px; border: 1px solid var(--line); border-radius: 4px;
  background: var(--surface); color: var(--ink); font-size: 0.9rem; min-height: 120px;
  font-family: inherit; resize: vertical;
}
.cr-composer-textarea:focus { outline: none; border-color: var(--accent); }

.cr-composer-actions {
  display: flex; gap: 8px; justify-content: flex-end; padding-top: 8px;
}

.cr-post-card {
  padding: 12px; background: var(--surface); border: 1px solid var(--line);
  border-radius: 6px; display: flex; gap: 12px; margin-bottom: 12px;
}

.cr-post-content { flex: 1; }
.cr-post-meta { margin: 0; font-size: 0.75rem; color: var(--muted); }
.cr-post-body { margin: 6px 0; line-height: 1.5; color: var(--ink); }
.cr-post-image { width: 100%; max-height: 200px; border-radius: 4px; margin: 8px 0; object-fit: cover; }

.cr-post-actions {
  display: flex; gap: 12px; margin-top: 8px; font-size: 0.8rem;
}
.cr-reply-btn { background: none; border: none; color: var(--muted); cursor: pointer; transition: color 0.2s; }
.cr-reply-btn:hover { color: var(--accent); }

.cr-reply-form {
  padding: 12px; background: var(--surface-alt); border: 1px solid var(--line);
  border-radius: 4px; margin: 12px 0;
}

.cr-reply-textarea {
  width: 100%; padding: 10px; border: 1px solid var(--line); border-radius: 4px;
  background: var(--surface); color: var(--ink); font-family: inherit; font-size: 0.9rem;
  resize: vertical; min-height: 80px;
}
.cr-reply-textarea:focus { outline: none; border-color: var(--accent); }

.cr-thread-detail { padding: 20px 0; }
.cr-thread-detail .cr-back-btn {
  display: inline-block; margin-bottom: 16px; color: var(--accent); text-decoration: none; font-size: 0.9rem;
}
.cr-thread-detail .cr-back-btn:hover { text-decoration: underline; }

.cr-thread-main { margin-bottom: 24px; }
.cr-thread-header h2 { margin: 0 0 8px; font-size: 1.3rem; color: var(--ink); }
.cr-thread-body { margin: 12px 0; line-height: 1.6; color: var(--ink); }
.cr-thread-full-image { width: 100%; max-height: 400px; border-radius: 6px; margin: 12px 0; object-fit: cover; }
.cr-thread-stats { margin: 12px 0; font-size: 0.9rem; color: var(--muted); }

.cr-replies { border-top: 1px solid var(--line); padding-top: 16px; margin-top: 20px; }
.cr-replies h3 { margin: 0 0 12px; font-size: 0.95rem; }

/*
 * Progression locking (PROG-P2, backlog e3adc737).
 *
 * Deliberately NOT reusing .app-link-disabled above: that sets
 * pointer-events:none, and a locked app must stay CLICKABLE so the click
 * lands on the explainer pane (renderLockedAppPane) instead of doing
 * nothing. "Show-but-disable beats hide" only works if the disabled thing
 * can still tell you why — a silent no-op is the dead end this avoids.
 *
 * Dimmed less than .app-link-disabled's 0.5 for the same reason: this is
 * an earnable state the user is meant to notice and act on, not a
 * permanently unavailable one.
 */
.app-link-locked {
  opacity: 0.65;
}

.app-link-locked .app-link-lock-icon {
  font-size: 1em;
  margin-inline-start: 0.35em;
  vertical-align: -0.15em;
  opacity: 0.9;
}

/* The locked-app landing pane. */
.progression-locked-pane {
  max-width: 46ch;
  margin: 0 auto;
  padding: var(--space-4) var(--space-3);
  text-align: center;
  color: var(--ink);
}

.progression-locked-icon {
  font-size: 40px;
  color: var(--muted);
}

.progression-locked-title {
  margin: var(--space-2) 0 var(--space-1);
  font-size: 1.375rem;
}

.progression-locked-reason {
  margin: 0 0 var(--space-2);
  color: var(--ink);
  font-weight: 600;
}

.progression-locked-desc {
  margin: 0 0 var(--space-3);
  color: var(--muted);
  line-height: 1.55;
}

.progression-locked-cta {
  display: inline-block;
}

/* ── PROG-P3 · "Platform Layout" progression rail (backlog 2341f1ac) ────
 *
 * Native <details>/<summary> disclosure. No accordion primitive exists in
 * apps/platform or apps/shared (verified before building), and the row is
 * explicit that native disclosure is accessible by default while "using
 * ARIA incorrectly can make things worse" — so this styles the native
 * element rather than reimplementing it with ARIA on divs.
 *
 * Every colour is a token. This panel sits in the avatar menu, which
 * themes with the rest of the shell, so a literal hex here would break
 * dark mode outright. */
.topbar-avatar-panel-progression {
  padding: 8px 16px;
}

.prog-rail {
  width: 100%;
}

/* list-style:none + ::marker both needed: Safari/WebKit paints the
 * disclosure triangle via ::-webkit-details-marker, Firefox/Chrome via
 * ::marker. The chevron span replaces it so the control can carry a real
 * rotation state. */
.prog-rail-summary {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 0;
  cursor: pointer;
  list-style: none;
  border-radius: 6px;
}
.prog-rail-summary::-webkit-details-marker { display: none; }
.prog-rail-summary::marker { content: ''; }

/* The focus ring must live on the SUMMARY, which is the real focusable
 * control — <details> itself is not focusable. 2px cobalt at 2px offset,
 * per the design guide. */
.prog-rail-summary:focus-visible {
  outline: 2px solid var(--yeja-cobalt);
  outline-offset: 2px;
}

.prog-rail-summary-icon {
  font-size: 20px;
  color: var(--yeja-cobalt, var(--accent));
  flex-shrink: 0;
}

.prog-rail-summary-text {
  display: flex;
  flex-direction: column;
  line-height: 1.3;
  flex: 1;
  min-width: 0;
}

.prog-rail-summary-title {
  font-size: var(--text-label-size, 12px);
  color: var(--muted);
}

.prog-rail-summary-level {
  font-size: var(--text-body-size, 14px);
  color: var(--ink);
  font-weight: 600;
}

.prog-rail-summary-chevron {
  font-size: 20px;
  color: var(--muted);
  flex-shrink: 0;
  transition: transform 160ms ease;
}
.prog-rail[open] .prog-rail-summary-chevron {
  transform: rotate(180deg);
}

.prog-rail-body {
  padding: 4px 0 8px;
}

.prog-rail-next {
  margin: 0 0 10px;
  font-size: var(--text-label-size, 12px);
  color: var(--ink);
  font-weight: 600;
}

.prog-rail-levels {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.prog-rail-level {
  display: flex;
  gap: 10px;
  align-items: flex-start;
}

.prog-rail-level-icon {
  font-size: 18px;
  flex-shrink: 0;
  color: var(--muted);
  margin-top: 1px;
}

/* Three states, distinguished by more than colour alone (the icon itself
 * differs — future levels carry a lock ligature), so the rail still reads
 * correctly for a user who can't distinguish the hues. */
.prog-rail-level.is-past .prog-rail-level-icon {
  color: var(--yeja-cobalt, var(--accent));
}
.prog-rail-level.is-current .prog-rail-level-icon {
  color: var(--yeja-cobalt, var(--accent));
}
.prog-rail-level.is-future {
  opacity: 0.65;
}

.prog-rail-level-body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.prog-rail-level-name {
  font-size: var(--text-body-size, 14px);
  color: var(--ink);
}
.prog-rail-level.is-current .prog-rail-level-name {
  font-weight: 600;
}

.prog-rail-level-blurb,
.prog-rail-level-unlocks {
  font-size: var(--text-label-size, 12px);
  color: var(--muted);
  line-height: 1.45;
}

.prog-rail-earned {
  margin: 12px 0 0;
  font-size: var(--text-label-size, 12px);
  color: var(--muted);
  line-height: 1.45;
}

@media (prefers-reduced-motion: reduce) {
  .prog-rail-summary-chevron {
    transition: none;
  }
}
