/* ==========================================================================
   states.css — what a surface looks like before, instead of, and when it
   fails to show its data.
   --------------------------------------------------------------------------
   Phase 6 of docs/UI_FACELIFT_PROJECT_PLAN.md. Three shapes, one vocabulary:

     .oc-sk     a skeleton — the shape of the content that is coming
     .oc-state  an empty or error state — what happened, and what to do next
     .oc-reveal progressive disclosure — summary first, evidence on demand

   Before this, "loading" was the literal word "Loading…" in about thirty
   places and a shimmer bar keyed to four hardcoded class names in desk.css.
   A skeleton is not decoration: it holds the layout still, so the arriving
   data does not shove the page (Phase 5's CLS work is undone by a 20px
   "Loading…" that becomes an 80px table).
   ========================================================================== */

/* --------------------------------------------------------------- skeleton */

@keyframes oc-sk-sweep {
  from { background-position: 200% 0; }
  to   { background-position: -200% 0; }
}

.oc-sk {
  display: flex;
  flex-direction: column;
  gap: var(--oc-sk-gap, 8px);
  width: 100%;
}

.oc-sk-line {
  display: block;
  height: var(--oc-sk-h, 10px);
  width: var(--w, 100%);
  border-radius: 4px;
  background-color: var(--bg-elevated-2);
  background-image: linear-gradient(
    90deg,
    var(--bg-elevated-2) 0%,
    color-mix(in srgb, var(--accent) 9%, var(--bg-elevated-2)) 50%,
    var(--bg-elevated-2) 100%
  );
  background-size: 200% 100%;
  animation: oc-sk-sweep var(--dur-shimmer) linear infinite;
  /* Each line starts a little later than the one above, so the sweep reads as
     one wave crossing the block rather than n bars flashing in unison. A
     negative delay starts each line already part-way through the loop. */
  animation-delay: calc(var(--i, 0) * var(--dur-shimmer-step) * -1);
}

.oc-sk-line:nth-child(1) { --i: 0; }
.oc-sk-line:nth-child(2) { --i: 1; }
.oc-sk-line:nth-child(3) { --i: 2; }
.oc-sk-line:nth-child(4) { --i: 3; }
.oc-sk-line:nth-child(5) { --i: 4; }
.oc-sk-line:nth-child(6) { --i: 5; }
.oc-sk-line:nth-child(7) { --i: 6; }
.oc-sk-line:nth-child(8) { --i: 7; }

/* Variants for the three shapes that actually occur in this app. */
.oc-sk--title .oc-sk-line { --oc-sk-h: 14px; }
.oc-sk--row   { --oc-sk-gap: 10px; }
.oc-sk--row .oc-sk-line { --oc-sk-h: 12px; }
.oc-sk--dense { --oc-sk-gap: 6px; }
.oc-sk--dense .oc-sk-line { --oc-sk-h: 8px; }

/* A skeleton inside a table cell must not stretch the row. */
td > .oc-sk, th > .oc-sk { --oc-sk-gap: 6px; }

/* Reserve the height the real content will take, so nothing jumps when it
   arrives. Callers set --oc-sk-min to the measured resting height. */
.oc-sk[style*="--oc-sk-min"] { min-height: var(--oc-sk-min); }

@media (prefers-reduced-motion: reduce) {
  .oc-sk-line { animation: none; background-image: none; }
}

/* ---------------------------------------------------- empty / error state */

.oc-state {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  padding: 18px 4px;
  color: var(--text-secondary);
  font-size: 12.5px;
  line-height: 1.5;
}

.oc-state-title {
  color: var(--text-primary);
  font-weight: 600;
  font-size: 13px;
}

.oc-state-body { max-width: 52ch; }

/* "What is still available" — the part that turns a dead end into a detour. */
.oc-state-note {
  color: var(--text-tertiary, var(--text-secondary));
  font-size: 11.5px;
}

.oc-state-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 4px;
}

/* The actions reuse the app-wide kit in controls.css; only the size is local. */
.oc-state-btn {
  font-size: 11.5px;
  padding: 4px 10px;
  min-height: 26px;
}

.oc-state--error .oc-state-title { color: var(--price-down, var(--text-primary)); }

.oc-state--center {
  align-items: center;
  text-align: center;
  padding: 28px 12px;
}

/* ------------------------------------------------- progressive disclosure */

/* Summary first, evidence on demand, source last: the brief's "Research
   Reveal". Built on <details> so it works with no JS, is keyboard-operable
   for free, and is findable by in-page search on engines that support it. */
.oc-reveal {
  border-top: 1px solid var(--border-subtle, var(--border-default));
  padding: 8px 0 0;
}

.oc-reveal > summary {
  display: flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  list-style: none;
  color: var(--text-secondary);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.02em;
  padding: 4px 0;
  user-select: none;
}

.oc-reveal > summary::-webkit-details-marker { display: none; }

.oc-reveal > summary::before {
  content: "";
  width: 0;
  height: 0;
  border: 4px solid transparent;
  border-left-color: currentColor;
  transition: transform var(--motion-move);
  transform-origin: 25% 50%;
}

.oc-reveal[open] > summary::before { transform: rotate(90deg); }

.oc-reveal > summary:hover { color: var(--text-primary); }
.oc-reveal > summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 3px;
}

.oc-reveal-body { padding: 6px 0 10px; }

/* The disclosure animates open on engines that can interpolate to auto.
   Everywhere else it simply appears — which is what it does today. */
@supports (interpolate-size: allow-keywords) and (selector(::details-content)) {
  .oc-reveal { interpolate-size: allow-keywords; }
  .oc-reveal::details-content {
    block-size: 0;
    overflow: hidden;
    transition:
      block-size var(--dur-ui) var(--ease-soft-spring),
      content-visibility var(--dur-ui) allow-discrete;
  }
  .oc-reveal[open]::details-content { block-size: auto; }
}

/* The disclosure's timing is collapsed app-wide by reduced_motion.css; only
   the marker's rotation needs saying here, because "no motion" for a caret
   means it should simply be pointing the right way. */
@media (prefers-reduced-motion: reduce) {
  .oc-reveal > summary::before { transition: none; }
}
