/* ═══════════════════════════════════════════════════════════════
   enlightenMEnt Live — Shared Desktop Design System (DESIGN-1 pilot)
   Desktop-sized versions of mobile's stat-tile / card / row visual
   language, extracted from public/mobile-ux.css's .m-stat-* rules and
   buildMobileStatGrid() (public/mobile-ux.js). Same colors, same
   typography, same shadow/radius treatment as mobile — different
   proportions for a wider, multi-column desktop layout.

   Deliberately reuses mobile's existing --m-* CSS custom properties
   (defined in mobile-ux.css's :root / [data-theme="dark"] blocks,
   already loaded globally, already theme-aware) rather than inventing
   a second color palette that could drift from mobile's over time.
   mobile-ux.css loads before this file (see index.html), so those
   variables are guaranteed to be defined by the time these rules apply.

   All classes are prefixed `ds-` (Design System) to guarantee zero
   collision with mobile's `m-`/`mob-` classes or desktop's existing
   `.stat-card`/`.card`/`.stats-row` classes — this file only ever adds
   new, opt-in classes. Nothing here is Analytics-specific; any desktop
   page can adopt these classes.

   ── STANDING RULE (DESIGN-2) ──────────────────────────────────────
   Every .ds-stat-* tile applied to a desktop page must have a real
   click handler leading to actual data — this is a standing
   requirement, the same as mobile's tappable-tile rule (every mobile
   stat tile drills into something real via _mobDrill/openTierModal/
   etc., see mobile-ux.js). Do not apply this visual style to a tile
   without also wiring its click-through in the same commit.

   In practice: add class="ds-clickable" (cursor + hover lift, defined
   below) and a data-drill="<key>" attribute to each .ds-stat-card, then
   after the container's innerHTML is set, wire real listeners:

     el.querySelectorAll('.ds-stat-card[data-drill]').forEach(function(card) {
       card.addEventListener('click', function() {
         // dispatch on card.getAttribute('data-drill') to whatever
         // opens the real filtered data — reuse mobile's existing
         // drill-down functions (_mobDrill, openTierEmployeeModal,
         // openAvgScoreBreakdown, etc. in mobile-ux.js) where the same
         // data is already surfaced there; they're plain api()+
         // openModal() calls with no isMob() gate, so they work
         // identically from a desktop click. Only write a new handler
         // if no equivalent mobile drill-down already exists.
       });
     });

   Never wire this with inline onclick="..." carrying embedded JSON or
   complex data — use addEventListener + data-* attributes (or a plain
   window._function('literal') call with no dynamic data), the same
   anti-pattern rule that caused JUL31-K's SyntaxError bug.
   ═══════════════════════════════════════════════════════════════ */

/* ── STAT GRID / STAT CARD ─────────────────────────────────────── */
.ds-stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 16px;
  margin-bottom: 20px;
}

.ds-stat-card {
  border-radius: var(--m-radius, 14px);
  padding: 20px 22px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  min-height: 112px;
  position: relative;
  overflow: hidden;
  transition: transform .15s, box-shadow .15s;
}

.ds-stat-card.ds-clickable { cursor: pointer; }
.ds-stat-card.ds-clickable:hover {
  transform: translateY(-2px);
  box-shadow: var(--m-shadow, 0 4px 16px rgba(0,0,0,.08));
}

.ds-stat-icon {
  position: absolute;
  top: 16px;
  right: 16px;
  opacity: .22;
  font-size: 34px;
  line-height: 1;
}

.ds-stat-label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .08em;
  opacity: .65;
  font-family: 'DM Sans', sans-serif;
}

.ds-stat-value {
  font-family: 'Fraunces', serif;
  font-size: 38px;
  font-weight: 500;
  line-height: 1;
  margin: 6px 0 3px;
}

/* FIX-2 (Aug 2026): several pages keep the legacy `stat-val` class
   alongside `ds-stat-value` (some intentionally, so an old mobile
   ghost-render scraper can still find the number by its old class name
   — see CPR's _mobCprFormat in mobile-ux.js). style.css's `.stat-val`
   sets an explicit color:var(--forest) (green) meant for the OLD
   white-background stat-card pattern; that explicit rule beats mere
   inheritance from a `.ds-stat-*` color variant every time, regardless
   of stylesheet load order, so any tile carrying both classes rendered
   green text — invisible on the green tile, wrong on every other color.
   This selector is more specific than a bare `.stat-val`, so it always
   wins and restores the correct inherited color (white on the colored
   variants, dark on .ds-stat-soft) without requiring every page's
   markup to be touched. */
.ds-stat-card .ds-stat-value { color: inherit; }

.ds-stat-sub {
  font-size: 11px;
  opacity: .6;
  font-weight: 500;
  font-family: 'DM Sans', sans-serif;
}

/* Color variants — identical treatment to mobile's .m-stat-green/gold/red/blue/purple */
.ds-stat-green  { background: var(--m-forest); color: #fff; }
.ds-stat-gold   { background: var(--m-gold);   color: #fff; }
.ds-stat-red    { background: var(--m-red);    color: #fff; }
.ds-stat-blue   { background: var(--m-blue);   color: #fff; }
.ds-stat-purple { background: var(--m-purple); color: #fff; }
.ds-stat-soft {
  background: var(--m-card, #fff);
  color: var(--m-tx1, #141412);
  border: 1px solid var(--m-bd, #e8e8e3);
  box-shadow: var(--m-shadow-sm, 0 1px 4px rgba(0,0,0,.06));
}
.ds-stat-soft .ds-stat-label,
.ds-stat-soft .ds-stat-sub { color: var(--m-tx3, #9a9a90); opacity: 1; }

/* ── CARD ──────────────────────────────────────────────────────── */
.ds-card {
  background: var(--m-card, #fff);
  border-radius: var(--m-radius, 14px);
  padding: 18px 20px;
  margin-bottom: 14px;
  box-shadow: var(--m-shadow-sm, 0 1px 4px rgba(0,0,0,.06));
  border: 1px solid var(--m-bd, #e8e8e3);
}
.ds-card-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 14px; }
.ds-card-title { font-size: 14px; font-weight: 700; color: var(--m-tx1, #141412); letter-spacing: -.01em; font-family: 'DM Sans', sans-serif; }
.ds-card-action { font-size: 12px; color: var(--m-forest); font-weight: 600; cursor: pointer; font-family: 'DM Sans', sans-serif; }

/* ── LIST ROW — denser than mobile's .m-row, for desktop's higher
   information density ─────────────────────────────────────────── */
.ds-row {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 9px 6px;
  border-bottom: 1px solid var(--m-bg2, #f4f4f1);
  border-radius: 8px;
  transition: background .1s;
}
.ds-row:last-child { border-bottom: none; }
.ds-row.ds-clickable { cursor: pointer; }
.ds-row.ds-clickable:hover { background: var(--m-bg2, #f4f4f1); }

.ds-row-avatar {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--m-forest-dim);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Fraunces', serif;
  font-size: 13px;
  font-weight: 500;
  color: var(--m-forest);
  flex-shrink: 0;
}

.ds-row-main { flex: 1; min-width: 0; }
.ds-row-name {
  font-size: 13px;
  font-weight: 600;
  color: var(--m-tx1, #141412);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-family: 'DM Sans', sans-serif;
}
.ds-row-sub { font-size: 11px; color: var(--m-tx3, #9a9a90); margin-top: 1px; font-family: 'DM Sans', sans-serif; }
.ds-row-right { flex-shrink: 0; text-align: right; }

/* ── PILL — same visual language as mobile's .m-pill ─────────────── */
.ds-pill {
  display: inline-flex;
  align-items: center;
  padding: 3px 10px;
  border-radius: 20px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .02em;
  text-transform: uppercase;
  font-family: 'DM Sans', sans-serif;
}
.ds-pill-green { background: var(--m-forest-dim); color: var(--m-forest); }
.ds-pill-gold  { background: var(--m-gold-dim);   color: #8a6a1a; }
.ds-pill-red   { background: var(--m-red-dim);    color: var(--m-red); }
.ds-pill-gray  { background: var(--m-bg2, #f4f4f1); color: var(--m-tx3, #9a9a90); }
.ds-pill-blue  { background: var(--m-blue-dim);   color: var(--m-blue); }
.ds-pill-purple{ background: var(--m-purple-dim); color: var(--m-purple); }

/* ═══════════════════════════════════════════════════════════════
   DESIGN-4 — dark hero banner + rich data table
   A second, additive pattern alongside .ds-stat-* above (does not
   replace it) — for list/table-style pages instead of tile-grid pages.
   Pilot: RoundTable Talks desktop (public/app-content.js).

   Hero gradient reuses the exact dark-green pairing already established
   for page-level hero banners in public/mobile.css's .mob-hero-banner
   (#0f2419 -> #28724f, 135deg) — not a new/guessed color, the same
   brand green (var(--m-forest) = #28724f) this whole file is built on.
   ═══════════════════════════════════════════════════════════════ */

/* ── HERO BANNER ──────────────────────────────────────────────── */
.ds-hero-banner {
  position: relative;
  background: linear-gradient(135deg, #0f2419 0%, #28724f 100%);
  border-radius: var(--m-radius-lg, 20px);
  padding: 24px 28px;
  margin-bottom: 20px;
  overflow: hidden;
  color: #fff;
}
/* Decorative only — low-opacity circles + a pie-glyph peeking from the
   edge, purely background texture, never carries information. */
.ds-hero-banner::before {
  content: '';
  position: absolute; top: -60px; right: -40px;
  width: 220px; height: 220px; border-radius: 50%;
  background: rgba(255,255,255,.045);
  pointer-events: none;
}
.ds-hero-banner::after {
  content: '';
  position: absolute; bottom: -50px; right: 100px;
  width: 130px; height: 130px; border-radius: 50%;
  background: rgba(255,255,255,.035);
  pointer-events: none;
}
.ds-hero-banner-glyph {
  position: absolute; bottom: -26px; right: -14px;
  width: 110px; height: 110px; border-radius: 50%;
  background: conic-gradient(rgba(255,255,255,.09) 0deg 130deg, transparent 130deg 360deg);
  pointer-events: none;
}
.ds-hero-banner-title {
  position: relative; z-index: 1;
  font-size: 10px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .12em; color: rgba(255,255,255,.5);
  margin-bottom: 16px; font-family: 'DM Sans', sans-serif;
}
.ds-hero-stats {
  position: relative; z-index: 1;
  display: flex; flex-wrap: wrap;
}
.ds-hero-stat {
  flex: 1; min-width: 110px; text-align: center;
  padding: 0 22px; border-right: 1px solid rgba(255,255,255,.14);
}
.ds-hero-stat:first-child { padding-left: 0; }
.ds-hero-stat:last-child { border-right: none; padding-right: 0; }
.ds-hero-stat-val {
  font-family: 'Fraunces', serif; font-size: 32px; font-weight: 600;
  line-height: 1; color: #fff;
}
.ds-hero-stat-lbl {
  font-size: 11px; color: rgba(255,255,255,.6); margin-top: 6px;
  font-family: 'DM Sans', sans-serif;
}

/* ── PILL TABS ─────────────────────────────────────────────────── */
.ds-pill-tabs { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 18px; }
.ds-pill-tab {
  padding: 8px 18px; border-radius: 20px; border: none; cursor: pointer;
  font-size: 13px; font-weight: 600; font-family: 'DM Sans', sans-serif;
  background: var(--m-bg2, #f4f4f1); color: var(--m-tx2, #4a4a44);
  transition: background .15s, color .15s;
}
.ds-pill-tab:hover { background: var(--m-bg3, #ebebeb); }
.ds-pill-tab.active { background: var(--m-forest); color: #fff; }

/* ── RICH DATA TABLE ───────────────────────────────────────────────
   STANDING RULE (same as .ds-stat-*'s in DESIGN-2): any table using
   .ds-table with sortable headers (.ds-sortable) must have real,
   working click-to-sort wired in the same commit — style and
   interaction ship together. Reuse an existing sort implementation
   where the page already has one (e.g. RoundTable's rtSortBy) instead
   of writing a second one; only add new sort logic where none exists.
   ──────────────────────────────────────────────────────────────── */
.ds-table-wrap {
  background: var(--m-card, #fff);
  border-radius: var(--m-radius, 14px);
  border: 1px solid var(--m-bd, #e8e8e3);
  box-shadow: var(--m-shadow-sm, 0 1px 4px rgba(0,0,0,.06));
  overflow: hidden;
}
.ds-table { width: 100%; border-collapse: collapse; font-family: 'DM Sans', sans-serif; }
.ds-table thead th {
  background: var(--m-bg2, #f4f4f1);
  text-align: left;
  padding: 10px 14px;
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em;
  color: var(--m-tx3, #9a9a90);
  border-bottom: 1px solid var(--m-bd, #e8e8e3);
  white-space: nowrap;
}
.ds-table th.ds-sortable { cursor: pointer; user-select: none; }
.ds-table th.ds-sortable:hover { color: var(--m-forest); }
.ds-table th .ds-sort-caret { display: inline-block; font-size: 9px; margin-left: 3px; opacity: .45; }
.ds-table th.ds-sort-active .ds-sort-caret { opacity: 1; color: var(--m-forest); }
.ds-table th .ds-info-icon { display: inline-block; margin-left: 4px; opacity: .4; cursor: help; font-size: 11px; font-weight: 400; text-transform: none; letter-spacing: 0; }
.ds-table tbody td {
  padding: 11px 14px; font-size: 13px; color: var(--m-tx1, #141412);
  border-bottom: 1px solid var(--m-bg2, #f4f4f1);
}
.ds-table tbody tr:last-child td { border-bottom: none; }
.ds-table tbody tr:nth-child(even) td { background: var(--m-bg2, #f4f4f1); }
.ds-table tbody tr:hover td { background: var(--m-forest-dim); }

/* ── METRIC PILL — percentage/fraction with a status dot ─────────
   Only use where the underlying data genuinely is a rate/percentage
   with a pass/fail-style threshold — don't force it onto data that
   isn't a percentage just to use the component. ────────────────── */
.ds-metric-pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px; border-radius: 20px;
  font-size: 12px; font-weight: 700; font-family: 'DM Sans', sans-serif;
}
.ds-metric-pill::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex-shrink: 0; }
.ds-metric-pill-green { background: var(--m-forest-dim); color: var(--m-forest); }
.ds-metric-pill-red   { background: var(--m-red-dim);    color: var(--m-red); }
.ds-metric-pill-gold  { background: var(--m-gold-dim);   color: #8a6a1a; }
.ds-metric-pill-frac  { opacity: .65; font-weight: 500; margin-left: 2px; }

/* ── STATUS BADGE — solid colored pill, right-aligned in a row ───
   Color variants are generic; map them to whatever page's real status
   vocabulary actually is — never the reference screenshot's statuses. */
.ds-status-badge {
  display: inline-flex; align-items: center;
  padding: 4px 12px; border-radius: 20px;
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em;
  font-family: 'DM Sans', sans-serif; color: #fff; white-space: nowrap;
}
.ds-status-green { background: var(--m-forest); }
.ds-status-blue  { background: var(--m-blue); }
.ds-status-gold  { background: var(--m-gold); }
.ds-status-red   { background: var(--m-red); }
.ds-status-purple{ background: var(--m-purple); }
.ds-status-gray  { background: var(--m-tx3, #9a9a90); }


/* ── ACCEL-5: Accelerate admin shell ─────────────────────────────────
   The Accelerate admin page is assembled by moving already-rendered
   sections into tab panels (see app-accelerate-shell.js), so these
   rules dress the shell itself and normalise the panels' spacing.
   Mobile-first: single-column below 700px, and the gradebook table
   scrolls sideways inside its own wrap rather than the page doing it. */
.accel5-shell { display: block; }
.accel5-panel > .ds-card,
.accel5-panel > .card { margin-bottom: 16px; }
.accel5-panel > div[id] { margin-bottom: 16px; }
.accel5-panel .section-header { margin-bottom: 12px; }

.accel5-filterbar {
  display: flex; gap: 10px; flex-wrap: wrap; align-items: center;
  padding: 12px 14px; margin-bottom: 14px;
}
.accel5-input {
  padding: 8px 12px; border: 1px solid var(--m-bd, #e8e8e3);
  border-radius: 8px; font-size: 13px; font-family: 'DM Sans', sans-serif;
  background: var(--m-card, #fff); color: var(--m-tx1, #141412);
  min-height: 38px;
}
.accel5-filterbar #jul27-search { flex: 1; min-width: 160px; }
.accel5-toggle {
  display: flex; align-items: center; gap: 7px;
  font-size: 13px; font-family: 'DM Sans', sans-serif; cursor: pointer;
  padding: 8px 12px; border-radius: 8px; background: var(--m-bg2, #f4f4f1);
  min-height: 38px;
}
.accel5-toggle input { width: 20px; height: 20px; flex: none; }

.accel5-groupchips { display: flex; gap: 6px; flex-wrap: wrap; }
.accel5-chip {
  padding: 8px 14px; border-radius: 20px; border: 1px solid var(--m-bd, #e8e8e3);
  background: var(--m-card, #fff); color: var(--m-tx2, #4a4a44);
  font-size: 12px; font-weight: 600; font-family: 'DM Sans', sans-serif;
  cursor: pointer; min-height: 38px;
}
.accel5-chip:hover { background: var(--m-bg2, #f4f4f1); }
.accel5-chip.active { background: var(--m-forest); border-color: var(--m-forest); color: #fff; }

.accel5-grads > .ds-card-header { margin-bottom: 10px; }

/* The tracker carries five columns including a date input and four action
   buttons — it scrolls within its own container instead of forcing the page
   wide on a narrow screen. */
#acc2-projects-body.ds-table-wrap { overflow-x: auto; }
#acc2-projects-body .ds-table { min-width: 720px; }

.accel5-textgroup-btns { display: flex; gap: 8px; flex-wrap: wrap; }
.accel5-textgroup-btns .accel5-chip { flex: 1; min-width: 96px; text-align: center; }

/* ── Phone (ACCEL-5 follow-up) ───────────────────────────────────────
   Accelerate no longer forks on viewport, so the whole admin page runs
   here. Everything stacks, every control clears a 44px touch target,
   and the tab row is sticky so switching sections never means scrolling
   back up a long roster. */
@media (max-width: 768px) {
  .accel5-filterbar { flex-direction: column; align-items: stretch; padding: 12px; }
  .accel5-filterbar #jul27-search,
  .accel5-filterbar #jul27-group,
  .accel5-groupchips { width: 100%; }
  .accel5-groupchips .accel5-chip { flex: 1; text-align: center; }
  .accel5-filterbar #jul27-count { margin-left: 0 !important; text-align: center; }
  .accel5-input, .accel5-toggle, .accel5-chip { min-height: 44px; }

  .accel5-shell .ds-stat-grid { grid-template-columns: 1fr 1fr; gap: 10px; }
  .accel5-shell .ds-stat-card { padding: 12px 14px; }
  .accel5-shell .ds-stat-value { font-size: 26px; }
  .accel5-shell .ds-stat-icon { display: none; }

  /* Sticky tab row — the roster is long, and the tabs are how you leave it. */
  #accel5-tabs {
    position: sticky; top: 0; z-index: 30;
    background: var(--m-bg, #faf9f6);
    padding: 8px 0; margin-bottom: 12px;
    gap: 6px;
  }
  .ds-pill-tab { flex: 1; text-align: center; padding: 11px 8px; font-size: 12px; min-height: 44px; }

  .accel5-panel > .ds-card,
  .accel5-panel > .card { margin-bottom: 12px; padding: 14px; }

  /* The cohort header's action buttons go full width rather than crowding. */
  #acc-cohort .section-header { flex-direction: column; align-items: stretch; gap: 10px; }
  #acc-cohort .section-header > div { display: flex; gap: 8px; }
  #acc-cohort .section-header .btn { flex: 1; min-height: 44px; }

  /* Participant cards: let the progress row wrap instead of squeezing. */
  .jul27-summary-card > div { flex-wrap: wrap; }
  .jul27-summary-card .btn { min-height: 38px; }

  /* Settings inputs are full-bleed and thumb-sized. */
  #acc-zoom-settings .form-input,
  #acc-footage-settings .form-input { width: 100%; min-height: 44px; }
  #acc-zoom-settings .btn,
  #acc-footage-settings .btn { min-height: 44px; }

  /* Schedule editor rows are a 5-column grid on desktop — stack them. */
  .acc-sched-row { grid-template-columns: 1fr 1fr !important; gap: 6px !important; }
  .acc-sched-row .acc-sched-title { grid-column: 1 / -1; }
  .acc-sched-row > div:last-child { grid-column: 1 / -1; display: flex; gap: 6px; }
  .acc-sched-row .acc-sched-link { flex: 1; max-width: none !important; }
}

@media (max-width: 420px) {
  .accel5-shell .ds-stat-grid { grid-template-columns: 1fr 1fr; }
  .ds-pill-tab { font-size: 11px; padding: 11px 4px; }
}
