/* ==========================================================================
   DS Matrix — CoachOS Design System
   Editorial-style matrix primitive. Extension of components/tables.css —
   cells provide ALL borders directly (border-bottom on every cell, border-left
   on non-first columns, border-top on header, border-right on last column),
   and the 4 corner cells carry the border-radius. NO outer container border,
   NO overflow:hidden corner-clipping (unreliable per CLAUDE.md Lesson 8).
   Selected state = accent-subtle background + inset shadow (never border swap).

   Variants:
     • .ds-matrix             — interactive matrix (radio / checkbox cells).
                                Used by GRID_SINGLE_CHOICE, GRID_MULTIPLE_CHOICE,
                                CUSTOM_GRID_CHOICE answering.
     • .ds-matrix--rubric     — single-row rubric. Cells are level cards
                                (score + name + description). Used by RUBRIC.
     • .ds-matrix--readonly   — aggregation companion modifier. Cells render
                                pick counts; cells with picks adopt
                                .ds-matrix__cell--has-picks for emphasis.

   Unified table matrix at all breakpoints (compact padding + ellipsis below
   768px). .ds-matrix--rubric keeps its stacked mobile card layout.
   ========================================================================== */

/* ── Container ─────────────────────────────────────────────────────────── */

.ds-matrix {
  display: block;
  background-color: var(--surface-base);
  --ds-matrix-row-label-width: 7rem;
  --ds-matrix-min-col: 2.75rem;
  --ds-matrix-cols: 4;
  /* When col count × min width exceeds the viewport, scroll inside the
     matrix frame (header + rows move together). Matches .table--sticky-wrap. */
  overflow-x: auto;
  overflow-y: visible;
  -webkit-overflow-scrolling: touch;
  border-radius: var(--radius-lg);
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.ds-matrix::-webkit-scrollbar {
  display: none;
}

/* Comfortable separation when Answer Element stacks multiple matrices
   (e.g. CUSTOM_GRID_CHOICE planning summaries — one record per answer). */
.ds-matrix + .ds-matrix {
  margin-top: var(--space-4);
}

@media (min-width: 768px) {
  .ds-matrix {
    --ds-matrix-row-label-width: 150px;
  }
}

/* ── Header row ────────────────────────────────────────────────────────── */

.ds-matrix__header {
  display: grid;
  grid-template-columns: var(--ds-matrix-row-label-width)
    repeat(var(--ds-matrix-cols), minmax(var(--ds-matrix-min-col), 1fr));
  gap: 0;
  min-width: max(100%, calc(var(--ds-matrix-row-label-width) + var(--ds-matrix-cols) * var(--ds-matrix-min-col)));
}

.ds-matrix__header-cell {
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: var(--space-2);
  text-align: center;
  background-color: var(--surface-sunken);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
  border-top: 1px solid var(--border-default);
  border-bottom: 1px solid var(--border-default);
  border-left: 1px solid var(--border-default);
}

.ds-matrix__header-cell:first-child {
  position: sticky;
  left: 0;
  z-index: calc(var(--z-sticky) + 1);
  text-align: left;
  border-top-left-radius: var(--radius-lg);
}

.ds-matrix__header-cell:last-child {
  border-right: 1px solid var(--border-default);
  border-top-right-radius: var(--radius-lg);
}

@media (min-width: 768px) {
  .ds-matrix__header-cell {
    padding: var(--space-3);
  }
}

/* ── Row ───────────────────────────────────────────────────────────────── */

.ds-matrix__row {
  display: grid;
  grid-template-columns: var(--ds-matrix-row-label-width)
    repeat(var(--ds-matrix-cols), minmax(var(--ds-matrix-min-col), 1fr));
  gap: 0;
  min-width: max(100%, calc(var(--ds-matrix-row-label-width) + var(--ds-matrix-cols) * var(--ds-matrix-min-col)));
  background-color: transparent;
  border: 0;
  border-radius: 0;
  padding: 0;
}

/* ── Row label ─────────────────────────────────────────────────────────── */

.ds-matrix__row-label {
  position: sticky;
  left: 0;
  z-index: var(--z-sticky);
  display: flex;
  align-items: center;
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
  padding: var(--space-2);
  border-bottom: 1px solid var(--border-default);
  border-left: 1px solid var(--border-default);
  background-color: var(--surface-base);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

@media (min-width: 768px) {
  .ds-matrix__row-label {
    padding: var(--space-3);
  }

  /* Bottom-left corner of the matrix: last row's row-label. */
  .ds-matrix__row:last-child .ds-matrix__row-label {
    border-bottom-left-radius: var(--radius-lg);
  }

  /* If there is no header row, the FIRST row's row-label carries top border + radius. */
  .ds-matrix:not(:has(.ds-matrix__header)) .ds-matrix__row:first-child .ds-matrix__row-label {
    border-top: 1px solid var(--border-default);
    border-top-left-radius: var(--radius-lg);
  }
}

/* ── Cells container ───────────────────────────────────────────────────── */

.ds-matrix__cells {
  display: contents;
}

/* ── Cell ──────────────────────────────────────────────────────────────── */

.ds-matrix__cell {
  /* position: relative is REQUIRED — anchors the visually-hidden
     .ds-matrix__input child (radio/checkbox) so label-click focus does
     not scroll the document root. See DS Conventions →
     "Visually-hidden form inputs" at /a/design-system/contribute. */
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  padding: var(--space-2);
  border-radius: 0;
  background-color: var(--surface-base);
  cursor: pointer;
  transition:
    background-color var(--duration-fast) var(--ease-out),
    box-shadow var(--duration-fast) var(--ease-out);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  color: var(--text-secondary);
  border-bottom: 1px solid var(--border-default);
  border-left: 1px solid var(--border-default);
}

.ds-matrix__cell:last-child {
  border-right: 1px solid var(--border-default);
}

/* Bottom-right corner of the matrix: last row's last cell. */
.ds-matrix__row:last-child .ds-matrix__cell:last-child {
  border-bottom-right-radius: var(--radius-lg);
}

/* If there is no header, the first row's cells need a top border + radii. */
.ds-matrix:not(:has(.ds-matrix__header)) .ds-matrix__row:first-child .ds-matrix__cell {
  border-top: 1px solid var(--border-default);
}

.ds-matrix:not(:has(.ds-matrix__header)) .ds-matrix__row:first-child .ds-matrix__cell:last-child {
  border-top-right-radius: var(--radius-lg);
}

.ds-matrix__row:last-child .ds-matrix__row-label {
  border-bottom-left-radius: var(--radius-lg);
}

@media (min-width: 768px) {
  .ds-matrix__cell {
    padding: var(--space-3);
    font-size: var(--text-sm);
  }
}

/* Hover bg rules across this file scope to non-picked cells via
   :not(:is(--has-picks, --on, :has(:checked))). The picked-state rule
   (lower in this file) is the single source of truth for picked
   appearance — hover never overrides it. */
.ds-matrix__cell:not(:is(.ds-matrix__cell--has-picks, .ds-matrix__cell--on, :has(.ds-matrix__input:checked))):hover {
  background-color: var(--surface-hover);
  color: var(--text-primary);
}

.ds-matrix__cell:has(.ds-matrix__input:focus-visible) {
  outline: 2px solid var(--border-focus, var(--accent-primary));
  outline-offset: 2px;
}

/* Picked state — single source of truth for all three picked markers:
     :has(.ds-matrix__input:checked) — interactive picked (Q-Web)
     .ds-matrix__cell--on            — interactive picked (manual modifier)
     .ds-matrix__cell--has-picks     — readonly picked (A-Web aggregation)
   Identical visual treatment across all three so coaches see exactly the
   same emphasis on a readonly aggregation that participants see while
   answering. Background fill + matching text color + inset accent ring. */
.ds-matrix__cell:has(.ds-matrix__input:checked),
.ds-matrix__cell--on,
.ds-matrix__cell--has-picks {
  background-color: var(--accent-subtle);
  color: var(--accent-primary);
  box-shadow: inset 0 0 0 1.5px var(--accent-primary);
}

/* Column labels live in the header row on all breakpoints; keep chip markup
   for aria-labelledby wiring but hide visually to avoid duplicate labels. */
.ds-matrix__cell-label {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  border: 0;
}

/* ── Hidden input ──────────────────────────────────────────────────────── */

.ds-matrix__input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  border: 0;
}

/* ── Mark (radio/checkbox indicator) ───────────────────────────────────── */

.ds-matrix__mark {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1.5px var(--border-strong);
  transition:
    box-shadow var(--duration-fast) var(--ease-out),
    background-color var(--duration-fast) var(--ease-out);
  flex-shrink: 0;
}

.ds-matrix__cell:has(.ds-matrix__input:checked) .ds-matrix__mark,
.ds-matrix__cell--on .ds-matrix__mark {
  box-shadow: inset 0 0 0 6px var(--accent-primary);
}

/* Square mark (checkbox variant) */
.ds-matrix__mark--square {
  border-radius: 4px;
  position: relative;
}

.ds-matrix__cell:has(.ds-matrix__input:checked) .ds-matrix__mark--square,
.ds-matrix__cell--on .ds-matrix__mark--square {
  box-shadow: inset 0 0 0 1.5px var(--accent-primary);
  background-color: var(--accent-primary);
}

.ds-matrix__cell:has(.ds-matrix__input:checked) .ds-matrix__mark--square::after,
.ds-matrix__cell--on .ds-matrix__mark--square::after {
  content: "✓";
  color: var(--text-on-accent);
  font-size: 13px;
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}

/* ==========================================================================
   .ds-matrix--rubric — single-row rubric variant
   Each cell holds a level (score + name + description). Same outer chrome
   and selection treatment.
   ========================================================================== */

.ds-matrix--rubric .ds-matrix__cells {
  /* Mobile: rubric levels always stack 1-up regardless of desktop col count.
     Zero the inherited gap so cells touch — otherwise the picked cell's accent
     treatment leaves a white strip above and below it. */
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
}

/* Mobile rubric: cells stack inside a single bordered card with 1px
   border-bottom hairline dividers between levels. */
.ds-matrix--rubric .ds-matrix__row {
  display: flex;
  flex-direction: column;
  background-color: var(--surface-base);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  padding: 0;
  gap: 0;
  overflow: hidden;
  min-width: auto;
}
.ds-matrix--rubric .ds-matrix__cell {
  border-top: 0;
  border-left: 0;
  border-right: 0;
  border-bottom: 1px solid var(--border-default);
  border-radius: 0;
}
.ds-matrix--rubric .ds-matrix__cells > .ds-matrix__cell:last-child {
  border-bottom: 0;
  border-right: 0;
}
/* Background rules exclude every picked-state marker so the picked accent
   treatment survives:
     :has(.ds-matrix__input:checked) — interactive picked (Q-Web rubric)
     .ds-matrix__cell--on             — interactive picked (manual modifier)
     .ds-matrix__cell--has-picks      — readonly picked (A-Web rubric)
   Without the full exclusion, the rubric scope (specificity 0,2,0) beats
   the picked rules (0,2,0 same source order, but later picked rules win
   in source ONLY when this rubric rule doesn't outrank them) — so picked
   cells would render white instead of accent-subtle in either Q or A view. */
.ds-matrix--rubric .ds-matrix__cell:not(:is(.ds-matrix__cell--has-picks, .ds-matrix__cell--on, :has(.ds-matrix__input:checked))) {
  background-color: var(--surface-base);
}
.ds-matrix--rubric .ds-matrix__cell:not(:is(.ds-matrix__cell--has-picks, .ds-matrix__cell--on, :has(.ds-matrix__input:checked))):hover {
  background-color: var(--surface-hover);
}

@media (min-width: 768px) {
  /* Desktop: a single row with N columns (no row label, no header). */
  .ds-matrix--rubric .ds-matrix__row {
    display: grid;
    grid-template-columns: repeat(var(--ds-matrix-cols, 3), minmax(var(--ds-matrix-min-col, 2.75rem), 1fr));
    min-width: max(100%, calc(var(--ds-matrix-cols) * var(--ds-matrix-min-col, 2.75rem)));
    background-color: transparent;
    border: 0;
    border-radius: 0;
    overflow: visible;
  }

  .ds-matrix--rubric .ds-matrix__cells {
    display: contents;
  }
  /* No header + no row-label means the rubric row IS the entire matrix.
     Each cell needs full outer border treatment. The mobile rule above zeroes
     border-left/right for vertical stacking; on desktop the cells sit in a row,
     so restore the vertical dividers (border-left on every cell = internal
     dividers + the matrix's own left edge; border-right on the last cell = the
     right edge). Without this the scale reads as top/bottom rails with no
     column separation. */
  .ds-matrix--rubric .ds-matrix__cell {
    border-top: 1px solid var(--border-default);
    border-left: 1px solid var(--border-default);
  }
  .ds-matrix--rubric .ds-matrix__cell:first-child {
    border-top-left-radius: var(--radius-lg);
    border-bottom-left-radius: var(--radius-lg);
  }
  .ds-matrix--rubric .ds-matrix__cell:last-child {
    border-top-right-radius: var(--radius-lg);
    border-bottom-right-radius: var(--radius-lg);
  }
  /* Restore the bottom + right borders on the rightmost cell — the mobile rule
     above strips both on the last child because mobile cells stack vertically.
     On desktop the cells are arranged horizontally, so the last cell's bottom
     border IS the matrix bottom and its right border IS the matrix right edge. */
  .ds-matrix--rubric .ds-matrix__cells > .ds-matrix__cell:last-child {
    border-bottom: 1px solid var(--border-default);
    border-right: 1px solid var(--border-default);
  }
}

.ds-matrix--rubric .ds-matrix__cell {
  flex-direction: column;
  align-items: stretch;
  justify-content: flex-start;
  gap: var(--space-2);
  padding: var(--space-4);
  text-align: left;
}

@media (min-width: 768px) {
  .ds-matrix--rubric .ds-matrix__cell {
    padding: var(--space-4);
  }
}

.ds-matrix__rubric-head {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
}

.ds-matrix__rubric-score {
  font-size: var(--text-xl);
  font-weight: var(--weight-bold);
  color: var(--accent-primary);
  line-height: var(--leading-none);
  font-variant-numeric: tabular-nums;
}

.ds-matrix__rubric-name {
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
  line-height: var(--leading-snug);
}

.ds-matrix__rubric-desc {
  font-size: var(--text-xs);
  color: var(--text-secondary);
  line-height: var(--leading-snug);
}

/* Answer count pill — inline at the right edge of the rubric head. Renders
   only when the parent collection has more than one answer (per the
   "single-answer is obvious from style alone" rule). On --has-picks cells,
   adopts the saturated accent treatment. */
.ds-matrix__rubric-count {
  margin-left: auto;
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  color: var(--text-secondary);
  padding: 2px var(--space-2);
  border-radius: var(--radius-full);
  background-color: var(--surface-sunken);
  font-variant-numeric: tabular-nums;
  line-height: 1.4;
}
.ds-matrix__cell--has-picks .ds-matrix__rubric-count {
  background-color: var(--accent-primary);
  color: var(--text-on-accent);
}

/* ==========================================================================
   .ds-matrix--readonly — aggregation companion modifier
   Reuses every structural rule above. Cells render pick counts via
   .ds-matrix__count; cells with picks adopt .ds-matrix__cell--has-picks
   (background-only accent-subtle, no inset ring).
   ========================================================================== */

/* Read-only is informative, not deactivated — the cell looks identical to
   the interactive resting state with two surgical changes: cursor signals
   non-interactivity, and hover collapses to resting (no color/background
   shift). The interactive variants' picked treatment (--has-picks +
   accent-subtle bg) carries through unchanged so coaches see exactly the
   same visual emphasis on selected cells that participants will see. */
.ds-matrix--readonly .ds-matrix__cell {
  cursor: not-allowed;
}

/* Read-only hover stays at resting state on all breakpoints. */
.ds-matrix--readonly .ds-matrix__cell:not(:is(.ds-matrix__cell--has-picks, .ds-matrix__cell--on, :has(.ds-matrix__input:checked))):hover {
  background-color: var(--surface-base);
}
.ds-matrix--rubric.ds-matrix--readonly .ds-matrix__cell:not(:is(.ds-matrix__cell--has-picks, .ds-matrix__cell--on, :has(.ds-matrix__input:checked))):hover {
  background-color: var(--surface-base);
}

/* Picked readonly cells inherit the canonical picked-state rule near the
   top of this file (.ds-matrix__cell--has-picks is in that selector list).
   Hover behavior is locked because that rule has no :hover modifier and
   the readonly cell hover override below is scoped to non-picked cells. */

/* Pick count display inside readonly cells. */
.ds-matrix__count {
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}

.ds-matrix__cell--has-picks .ds-matrix__count {
  color: var(--accent-primary);
}

/* Cell voice follows the soul — TYPOGRAPHY ONLY. The rubric is a canonical DS
   matrix: cells share single hairline borders and ONLY the four corner cells are
   rounded (the :first-child / :last-child radius rules in the desktop block
   above). A per-cell `border-radius` here — added by e75c3552's soul
   distribution ("rubric controls keep rounded corners") — rounded EVERY level
   into a separate card with corner gaps, breaking the grid. Removed so the
   rubric matches every other .ds-matrix grid. */
.ds-matrix__cell-label, .ds-matrix__row-label,
.ds-matrix--rubric .ds-matrix__rubric-name { font-family: var(--soul-font-answer); }

/* ==========================================================================
   .ds-matrix--scored — Answer Grid scored comparison modifier
   Used by Elements::AnswerGrid. Each cell receives its tint color INLINE at
   runtime from the render (saturated_fill / soft_wash / neutral_dot styles).
   This modifier is purely structural: it clears the default --surface-sunken
   background so the inline tint reads true, and ensures cells have a
   comfortable minimum height.
   ========================================================================== */

/* Scored cells: clear the default sunken background so inline color tints
   are not diluted by a competing background. Keep centering, add min-height
   for comfortable data display. Non-interactive (read-only by nature). */
.ds-matrix--scored .ds-matrix__cell {
  background-color: transparent;
  min-height: var(--space-12);
  cursor: default;
  flex-direction: column;
  gap: var(--space-1);
}

/* Hover suppressed on scored cells — they are informational, not interactive. */
.ds-matrix--scored .ds-matrix__cell:hover {
  background-color: transparent;
}

@media (min-width: 768px) {
  .ds-matrix--scored .ds-matrix__cell:not(:is(.ds-matrix__cell--has-picks, .ds-matrix__cell--on, :has(.ds-matrix__input:checked))) {
    background-color: transparent;
  }
  .ds-matrix--scored .ds-matrix__cell:not(:is(.ds-matrix__cell--has-picks, .ds-matrix__cell--on, :has(.ds-matrix__input:checked))):hover {
    background-color: transparent;
  }
}

/* Score number span — mirrors .ds-matrix__count typography; tabular-nums for
   alignment across columns. Used inside scored cells by the Answer Grid render. */
.ds-matrix__score {
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
