/* ============================================================
   canon-components.css — styles for the shared canonical set.
   Phase 2 of the legal-vertical spin-up (renderer parity).

   TOKEN DISCIPLINE. Every colour, space, radius, duration and
   breakpoint below reads a token from tokens/tokens.css (or
   tokens/base.css + a theme layer). There is not one literal
   colour in this file, so a vertical theme recolours the whole
   component set without touching a component.

   THE THREE STATES are styled to be unmistakably distinct:
     [data-state="skeleton"]  shimmering value blocks, real labels
     [data-state="empty"]     frozen surface + honest copy, no numeral
     [data-state="filled"]    the real thing

   RESPONSIVE (tested at 375px and 768px):
     KPI strip   auto-fit grid -> horizontal scroll-snap rail <=768px
     Sections    auto-fit grid -> single column <=768px
     Detail      right-hand panel -> bottom sheet <=768px

   MOTION: mount + state change animate 150–250ms via the
   --duration-mount / --duration-state tokens. Both collapse to 0ms
   under prefers-reduced-motion (tokens.css zeroes the scale), and
   the shimmer + slide are additionally switched off by name below,
   because a 0ms duration does not stop a keyframe loop.
   ============================================================ */

/* ── layout root ─────────────────────────────────────────── */

.cc-root {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--space-md);
  align-items: start;
}
/* The three main slots stack inside ONE grid child. They were sibling grid
   rows with the detail panel spanning all three, which let the panel's
   height distribute into the row gaps and opened a large void under the
   ribbon. A nested flex column cannot do that. */
.cc-main {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  min-width: 0;
}
.cc-main > .cc-slot        { min-width: 0; }
.cc-main > .cc-slot:empty  { display: none; }
.cc-root > .cc-slot-detail { min-width: 0; }

/* ── screen-reader-only ──────────────────────────────────── */

.cc-sr {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ── mount + state transition ────────────────────────────── */

.cc-enter {
  animation: cc-enter var(--duration-mount) var(--ease-out) both;
  animation-delay: var(--cc-stagger, 0ms);
}
@keyframes cc-enter {
  from { opacity: 0; transform: translateY(var(--cc-enter-shift)); }
  to   { opacity: 1; transform: none; }
}

/* State CHANGE (skeleton -> empty/filled) cross-fades the body rather
   than snapping. Transform is untouched so nothing reflows. */
.cc-kpi-body, .cc-sec-body, .cc-detail-body, .cc-ribbon-list, .cc-ribbon-empty {
  transition: opacity var(--duration-state) var(--ease-out);
}

/* ── skeleton primitive ──────────────────────────────────── */

.cc-shim {
  display: block;
  border-radius: var(--skeleton-radius);
  height: var(--skeleton-line-h);
  width: var(--cc-shim-w, 100%);
  max-width: 100%;
  background:
    linear-gradient(90deg,
      var(--skeleton-bg) 0%,
      var(--skeleton-highlight) 50%,
      var(--skeleton-bg) 100%);
  background-size: 200% 100%;
  animation: cc-shimmer var(--skeleton-shimmer-dur) var(--ease-in-out) infinite;
}
.cc-shim + .cc-shim { margin-top: var(--space-xs); }
.cc-shim-value { height: var(--skeleton-value-h); }
.cc-shim-sub   { height: calc(var(--skeleton-line-h) * 0.8); opacity: 0.65; }

@keyframes cc-shimmer {
  from { background-position: 200% 0; }
  to   { background-position: -200% 0; }
}

/* ── 1 · KPI TILE STRIP ──────────────────────────────────── */

.cc-kpi-strip {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(var(--kpi-min-w), 1fr));
  gap: var(--space-sm);
}
.cc-kpi-cell { min-width: 0; }

.cc-kpi {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  height: 100%;
  padding: var(--space-md);
  background: var(--surface-card-bg);
  border: 1px solid var(--surface-card-border);
  border-radius: var(--radius-lg);
}
.cc-kpi[data-cc-clickable='true'] { cursor: pointer; }
.cc-kpi[data-cc-clickable='true']:hover {
  background: var(--surface-card-bg-hover);
  border-color: var(--color-border-default);
}
.cc-kpi:focus-visible,
.cc-kpi-info:focus-visible,
.cc-sec-open:focus-visible,
.cc-detail-tab:focus-visible,
.cc-detail-close:focus-visible,
.cc-ribbon-btn:focus-visible {
  outline: 2px solid var(--focus-ring-color, var(--color-accent));
  outline-offset: 2px;
}

.cc-kpi-hd {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  justify-content: space-between;
}
.cc-kpi-label { color: var(--text-secondary); min-width: 0; overflow-wrap: anywhere; }
.cc-kpi-info {
  display: inline-flex;
  align-items: center; justify-content: center;
  /* WCAG 2.5.8 target size (minimum) is 24x24. The GLYPH stays 12px — the
     hit area is what the criterion measures, and at 1.25rem this rendered
     19x19 and failed. Negative margin keeps the larger target from
     changing the header's optical alignment. */
  width: var(--touch-min-inline); height: var(--touch-min-inline);
  margin: calc(var(--touch-min-inline) / -8);
  flex: 0 0 auto;
  border-radius: var(--radius-circle);
  color: var(--text-tertiary);
  cursor: help;
}
.cc-kpi-info:hover { color: var(--text-secondary); }

.cc-kpi-value { color: var(--text-primary); overflow-wrap: anywhere; }
.cc-kpi-sub   { color: var(--text-secondary); font-size: var(--fs-sm); }
.cc-kpi-trend { font-size: var(--fs-xs); color: var(--text-tertiary); }
.cc-kpi-trend[data-trend='up']   { color: var(--status-ok); }
.cc-kpi-trend[data-trend='down'] { color: var(--status-danger); }

/* EMPTY — confidence-frozen. No numeral, no dash. The value slot names
   the measure as unobserved and the subtext says what would end that. */
.cc-kpi[data-state='empty'] {
  background: var(--frozen-surface);
  border-style: dashed;
  border-color: var(--frozen-border);
}
.cc-kpi-value-frozen {
  color: var(--frozen-text);
  font-style: normal;
  display: inline-flex; align-items: center; gap: var(--space-xs);
}
.cc-kpi-value-frozen::before {
  content: '';
  width: 0.5rem; height: 0.5rem;
  flex: 0 0 auto;
  border-radius: var(--radius-circle);
  border: 1px dashed var(--frozen-border);
}
.cc-kpi-sub-frozen { color: var(--text-tertiary); font-size: var(--fs-xs); }

/* SKELETON */
.cc-kpi[data-state='skeleton'] .cc-kpi-label { opacity: 0.85; }

.cc-kpi-unconfigured {
  margin: 0;
  padding: var(--space-md);
  color: var(--text-secondary);
  font-size: var(--fs-sm);
  background: var(--frozen-surface);
  border: 1px dashed var(--surface-card-border);
  border-radius: var(--radius-lg);
}

/* ── 2 · ATTENTION RIBBON ────────────────────────────────── */

.cc-ribbon {
  padding: var(--space-md);
  background: var(--surface-card-bg);
  border: 1px solid var(--surface-card-border);
  border-radius: var(--radius-lg);
}
.cc-ribbon-hd {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--space-sm);
  margin-bottom: var(--space-sm);
}
.cc-ribbon-title { color: var(--text-secondary); }
.cc-ribbon-count { color: var(--text-tertiary); }

.cc-ribbon-list {
  list-style: none; margin: 0; padding: 0;
  display: flex; gap: var(--space-sm);
  overflow-x: auto;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
}
.cc-ribbon-item {
  scroll-snap-align: start;
  flex: 1 1 clamp(14rem, 30%, 22rem);
  min-width: 0;
}
.cc-ribbon-item-skel {
  display: flex; align-items: center; gap: var(--space-sm);
  padding: var(--space-sm);
  border: 1px solid var(--surface-card-border);
  border-radius: var(--radius-md);
}
.cc-ribbon-item-skel .cc-ribbon-text { flex: 1 1 auto; min-width: 0; }
.cc-ribbon-item-skel .cc-ribbon-dot { width: 0.5rem; height: 0.5rem; border-radius: var(--radius-circle); }

.cc-ribbon-btn {
  display: flex; align-items: flex-start; gap: var(--space-sm);
  width: 100%;
  min-height: var(--touch-min);
  padding: var(--space-sm);
  text-align: left;
  background: var(--surface-glass-bg, transparent);
  border: 1px solid var(--surface-card-border);
  border-left: 3px solid var(--ribbon-quiet);
  border-radius: var(--radius-md);
  color: inherit;
  font: inherit;
  cursor: pointer;
}
.cc-ribbon-btn:hover { background: var(--surface-card-bg-hover); }
.cc-ribbon-item[data-severity='critical'] .cc-ribbon-btn { border-left-color: var(--ribbon-critical); }
.cc-ribbon-item[data-severity='warn']     .cc-ribbon-btn { border-left-color: var(--ribbon-warn); }
.cc-ribbon-item[data-severity='info']     .cc-ribbon-btn { border-left-color: var(--ribbon-info); }

.cc-ribbon-dot {
  width: 0.5rem; height: 0.5rem;
  margin-top: 0.4rem;
  flex: 0 0 auto;
  border-radius: var(--radius-circle);
  background: var(--ribbon-quiet);
}
.cc-ribbon-item[data-severity='critical'] .cc-ribbon-dot { background: var(--ribbon-critical); }
.cc-ribbon-item[data-severity='warn']     .cc-ribbon-dot { background: var(--ribbon-warn); }
.cc-ribbon-item[data-severity='info']     .cc-ribbon-dot { background: var(--ribbon-info); }

.cc-ribbon-text { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.cc-ribbon-subject { color: var(--text-primary); overflow-wrap: anywhere; }
.cc-ribbon-detail  { color: var(--text-secondary); overflow-wrap: anywhere; }

/* EMPTY — honest quiet. An open ring, not a zero badge. */
.cc-ribbon[data-state='empty'] {
  background: var(--frozen-surface);
  border-style: dashed;
  border-color: var(--frozen-border);
}
.cc-ribbon-empty {
  display: flex; align-items: flex-start; gap: var(--space-sm);
  padding: var(--space-xs) 0;
}
.cc-ribbon-empty-mark {
  width: 0.625rem; height: 0.625rem;
  margin-top: 0.3rem;
  flex: 0 0 auto;
  border-radius: var(--radius-circle);
  border: 1px dashed var(--frozen-border);
}
.cc-ribbon-empty-text { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.cc-ribbon-empty-title { color: var(--frozen-text); }
.cc-ribbon-empty-body  { color: var(--text-tertiary); }

/* ── 3 · SECTION GRID ────────────────────────────────────── */

.cc-sec-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(var(--sec-min-w), 1fr));
  gap: var(--space-sm);
}
.cc-sec-cell { min-width: 0; }

.cc-sec {
  display: flex; flex-direction: column;
  gap: var(--space-sm);
  height: 100%;
  padding: var(--space-md);
  background: var(--surface-card-bg);
  border: 1px solid var(--surface-card-border);
  border-radius: var(--radius-lg);
}
.cc-sec-hd { display: flex; align-items: center; gap: var(--space-xs); }
.cc-sec-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.75rem; height: 1.75rem;
  flex: 0 0 auto;
  border-radius: var(--radius-md);
  background: var(--accent-soft, var(--surface-glass-bg));
  color: var(--accent);
  font-size: var(--fs-sm);
}
.cc-sec-title { margin: 0; color: var(--text-primary); min-width: 0; overflow-wrap: anywhere; }
.cc-sec-body  { flex: 1 1 auto; }
.cc-sec-value { color: var(--text-primary); }
.cc-sec-sub   { color: var(--text-secondary); }

.cc-sec[data-state='empty'] {
  background: var(--frozen-surface);
  border-style: dashed;
  border-color: var(--frozen-border);
}
.cc-sec-empty { display: flex; flex-direction: column; gap: 0.25rem; }
.cc-sec-empty-title { margin: 0; color: var(--frozen-text); }
.cc-sec-empty-body  { margin: 0; color: var(--text-tertiary); }

.cc-sec-ft { margin-top: auto; }
.cc-sec-open {
  display: inline-flex; align-items: center;
  min-height: var(--touch-min);
  padding: 0 var(--space-md);
  background: transparent;
  border: 1px solid var(--surface-card-border);
  border-radius: var(--radius-pill);
  color: var(--text-secondary);
  font: inherit; font-size: var(--fs-sm);
  cursor: pointer;
}
.cc-sec-open:hover { color: var(--text-primary); border-color: var(--color-border-default); }

.cc-sec-none {
  margin: 0; padding: var(--space-md);
  color: var(--text-secondary); font-size: var(--fs-sm);
  background: var(--frozen-surface);
  border: 1px dashed var(--surface-card-border);
  border-radius: var(--radius-lg);
}

/* ── 4 · RICH DETAIL PANEL ───────────────────────────────── */

.cc-detail {
  width: var(--detail-w);
  max-width: 100%;
  position: sticky;
  top: var(--space-md);
}
.cc-detail-sheet {
  display: flex; flex-direction: column;
  gap: var(--space-sm);
  padding: var(--space-md);
  background: var(--surface-card-bg);
  border: 1px solid var(--surface-card-border);
  border-radius: var(--radius-lg);
}
.cc-detail-hd { display: flex; align-items: center; justify-content: space-between; gap: var(--space-sm); }
.cc-detail-title { margin: 0; color: var(--text-primary); min-width: 0; overflow-wrap: anywhere; }
.cc-detail-close {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--touch-min); height: var(--touch-min);
  flex: 0 0 auto;
  margin: calc(var(--space-xs) * -1);
  background: transparent; border: 0;
  border-radius: var(--radius-md);
  color: var(--text-secondary);
  font-size: var(--fs-lg);
  cursor: pointer;
}
.cc-detail-close:hover { color: var(--text-primary); background: var(--surface-card-bg-hover); }

.cc-detail-pin {
  display: flex; flex-direction: column; gap: var(--space-xs);
  padding: var(--space-sm);
  background: var(--surface-glass-bg);
  border: 1px solid var(--surface-card-border);
  border-radius: var(--radius-md);
}
.cc-detail-pin-hd { margin: 0; color: var(--text-tertiary); }
.cc-detail-pin-row { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; }
.cc-detail-pin-label { color: var(--text-tertiary); }
.cc-detail-pin-value { color: var(--text-primary); overflow-wrap: anywhere; }
.cc-detail-pin-frozen { margin: 0; color: var(--text-tertiary); }

.cc-detail-tabs {
  display: flex; gap: var(--space-xs);
  overflow-x: auto;
  scroll-snap-type: x proximity;
  border-bottom: 1px solid var(--surface-card-border);
  /* The archetype tab list routinely overflows the panel width (matters
     declares five). Fade the trailing edge so the last label reads as
     "scroll for more" rather than as a label clipped mid-word.
     The #000 below is an ALPHA stop, not a colour: a mask reads only the
     alpha channel, so no brand value is being hardcoded here. */
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 2rem), transparent 100%);
          mask-image: linear-gradient(to right, #000 calc(100% - 2rem), transparent 100%);
}
.cc-detail-tab {
  scroll-snap-align: start;
  flex: 0 0 auto;
  min-height: var(--touch-min);
  padding: 0 var(--space-sm);
  background: transparent;
  border: 0;
  border-bottom: 2px solid transparent;
  color: var(--text-secondary);
  font: inherit; font-size: var(--fs-sm);
  white-space: nowrap;
  cursor: pointer;
}
.cc-detail-tab[aria-selected='true'] { color: var(--text-primary); border-bottom-color: var(--accent); }
.cc-detail-tab:hover { color: var(--text-primary); }

.cc-detail-body  { min-height: 6rem; }
.cc-detail-lines { display: flex; flex-direction: column; gap: var(--space-xs); }

.cc-detail[data-state='empty'] .cc-detail-sheet {
  background: var(--frozen-surface);
  border-style: dashed;
  border-color: var(--frozen-border);
}
.cc-detail-empty {
  display: flex; flex-direction: column; align-items: center;
  gap: var(--space-xs);
  padding: var(--space-lg) var(--space-sm);
  text-align: center;
}
.cc-detail-empty-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2.5rem; height: 2.5rem;
  border-radius: var(--radius-circle);
  border: 1px dashed var(--frozen-border);
  color: var(--frozen-mark);
}
.cc-detail-empty-title { margin: 0; color: var(--frozen-text); }
.cc-detail-empty-body  { margin: 0; color: var(--text-tertiary); max-width: 32ch; }

/* ── RESPONSIVE ──────────────────────────────────────────── */

/* <=768px — tablet/mobile. The detail panel leaves the grid and becomes
   a bottom sheet; the KPI strip becomes a scroll-snap rail; sections
   stack. Verified at 768px and 375px. */
@media (max-width: 768px) {
  .cc-root { grid-template-columns: minmax(0, 1fr); }

  .cc-kpi-strip {
    display: flex;
    gap: var(--space-sm);
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    /* bleed to the viewport edge so the rail reads as scrollable */
    margin-inline: calc(var(--space-md) * -1);
    padding-inline: var(--space-md);
    scroll-padding-inline: var(--space-md);
  }
  .cc-kpi-cell {
    flex: 0 0 var(--kpi-min-w-mobile);
    scroll-snap-align: start;
  }
  .cc-kpi-strip-unconfigured { display: block; margin-inline: 0; padding-inline: 0; }

  .cc-sec-grid { grid-template-columns: minmax(0, 1fr); }

  .cc-ribbon-list { flex-direction: column; }
  .cc-ribbon-item { flex: 1 1 auto; }

  /* Detail becomes a bottom sheet. Hidden until opened so it never
     covers the dashboard on a small screen. */
  .cc-slot-detail { position: static; }
  .cc-detail {
    position: fixed;
    inset: auto 0 0 0;
    width: 100%;
    max-height: var(--detail-sheet-max);
    z-index: var(--z-panel);
    transform: translateY(100%);
    transition: transform var(--duration-state) var(--ease-out),
                visibility 0s linear var(--duration-state);
    pointer-events: none;
    /* `visibility` — not transform alone — is what actually takes the closed
       sheet out of play. A translated-off sheet is still painted (it showed
       through the section cards in the 375px capture) and is still reachable
       by the screen reader and the tab order. visibility:hidden fixes all
       three, and the delayed transition keeps the slide-out animating before
       it disappears. */
    visibility: hidden;
  }
  .cc-detail-open {
    transform: none;
    pointer-events: auto;
    visibility: visible;
    transition: transform var(--duration-state) var(--ease-out),
                visibility 0s;
  }
  .cc-detail-sheet {
    max-height: var(--detail-sheet-max);
    overflow-y: auto;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    border-bottom: 0;
    box-shadow: var(--shadow-lg);
    padding-bottom: max(var(--space-md), env(safe-area-inset-bottom));
  }
  /* Grab affordance at the top of the sheet. */
  .cc-detail-sheet::before {
    content: '';
    width: 2.25rem; height: 0.25rem;
    align-self: center;
    border-radius: var(--radius-pill);
    background: var(--color-border-strong);
  }
}

/* <=375px — narrow phone. Tighten padding; never let anything overflow
   the page horizontally. */
@media (max-width: 375px) {
  .cc-kpi, .cc-sec, .cc-ribbon, .cc-detail-sheet { padding: var(--space-sm); }
  .cc-kpi-cell { flex-basis: 85%; }
  .cc-detail-empty { padding: var(--space-md) var(--space-xs); }
}

/* ── REDUCED MOTION ──────────────────────────────────────────
   tokens.css already zeroes the duration scale, which stops every
   transition above. Keyframe ANIMATIONS need switching off by name:
   a 0ms duration does not stop a running loop, and an infinite
   shimmer is exactly the vestibular trigger the media query exists
   for. The skeleton stays visible as a static plate. */
@media (prefers-reduced-motion: reduce) {
  .cc-shim {
    animation: none;
    background: var(--skeleton-bg);
  }
  .cc-enter {
    animation: none;
    opacity: 1;
    transform: none;
  }
  .cc-detail { transition: none; }
}

/* ── FORCED COLORS ───────────────────────────────────────────
   In forced-colors mode the frozen/dashed affordances must survive,
   because they are what distinguishes empty from filled. */
@media (forced-colors: active) {
  .cc-kpi, .cc-sec, .cc-ribbon, .cc-detail-sheet { border: 1px solid CanvasText; }
  .cc-kpi[data-state='empty'],
  .cc-sec[data-state='empty'],
  .cc-ribbon[data-state='empty'] { border-style: dashed; }
  .cc-shim { background: GrayText; }
}
