/* ==========================================================================
   SKELETON PLACEHOLDERS

   Replaces the spinner-and-dim pattern with a shape that matches whatever is
   about to arrive. A spinner says "something is happening"; a skeleton says
   "a table with six rows is happening", which is the difference between
   waiting and knowing what you are waiting for.

   Two rules this file exists to enforce:

   1. A skeleton must match the real content's geometry — same column count,
      same row height, same card padding. A placeholder that is the wrong
      shape causes a visible jolt when the real thing lands, which is worse
      than no placeholder at all. The builders in assets/js/skeleton.js read
      the live DOM to get this right rather than guessing.

   2. It is decorative. Screen readers are told the region is busy, not read
      a wall of empty boxes — see aria-busy in skeleton.js.
   ========================================================================== */

:root {
  --skeleton-base: rgba(15, 23, 42, 0.07);
  --skeleton-sheen: rgba(15, 23, 42, 0.13);
  --skeleton-radius: 6px;
}

.skeleton {
  position: relative;
  overflow: hidden;
  background: var(--skeleton-base);
  border-radius: var(--skeleton-radius);
  /* Nothing inside a skeleton is real text, so never let it be selected or
     copied — a user dragging across one should get the page, not a run of
     empty boxes. */
  user-select: none;
  pointer-events: none;
}

/* The sheen is a moving highlight rather than a pulsing opacity: pulsing the
   whole block reads as the page flashing, which is exactly the jank the
   250ms delay elsewhere exists to avoid. */
.skeleton::after {
  content: "";
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(
    90deg,
    transparent 0%,
    var(--skeleton-sheen) 50%,
    transparent 100%
  );
  animation: skeleton-sheen 1.25s ease-in-out infinite;
}

@keyframes skeleton-sheen {
  100% { transform: translateX(100%); }
}

/* --------------------------------------------------------------------------
   Primitives
   -------------------------------------------------------------------------- */
.skeleton-line {
  height: 0.75em;
  margin: 0.28em 0;
}

.skeleton-line-sm { height: 0.62em; }
.skeleton-line-lg { height: 1em; }

/* Widths are varied deliberately. A column of identical bars reads as a
   loading graphic; ragged ends read as text that has not arrived yet. */
.skeleton-w-25 { width: 25%; }
.skeleton-w-40 { width: 40%; }
.skeleton-w-55 { width: 55%; }
.skeleton-w-70 { width: 70%; }
.skeleton-w-85 { width: 85%; }
.skeleton-w-full { width: 100%; }

.skeleton-pill {
  height: 1.35em;
  width: 5.5em;
  border-radius: 999px;
}

.skeleton-circle {
  border-radius: 50%;
  flex: 0 0 auto;
}

.skeleton-btn {
  height: 30px;
  width: 30px;
  border-radius: 8px;
}

/* --------------------------------------------------------------------------
   Table rows — the main use. The cells carry the same padding as the real
   .data-table so the placeholder occupies the same height, and the table
   does not jump when the rows are swapped in.
   -------------------------------------------------------------------------- */
.skeleton-row td {
  padding: 0.85rem 0.65rem;
  border-bottom: 1px solid rgba(15, 23, 42, 0.06);
  vertical-align: middle;
}

.skeleton-actions {
  display: flex;
  gap: 0.25rem;
}

/* --------------------------------------------------------------------------
   Message thread — sits inside the real .message-wrapper, so the placeholder
   inherits the widget's own left/right alignment instead of restating it.
   -------------------------------------------------------------------------- */
/* Heights match the real bubbles: a single-line reply and a wrapped
   two-line one, measured from an actual thread rather than guessed. */
/* The wrapper must span the thread, or a percentage width resolves
   against a box that has already shrunk to fit the bubble inside it —
   which is why the first version came out a third narrower than the
   real bubbles it was standing in for. */
.skeleton-msg {
  width: 100%;
}

.skeleton-bubble {
  height: 38px;
  border-radius: 12px;
  /* No max-width here: .message-wrapper already caps the column at 82%,
     and the real .message-bubble fills it. Adding another 80% inside that
     compounded to 65% and made every placeholder a third too narrow. */
}

.skeleton-bubble-tall {
  height: 56px;
}

.skeleton-bubble-time {
  width: 3.2em;
  height: 0.55em;
  margin-top: 0.3em;
}

/* --------------------------------------------------------------------------
   Card / detail placeholder, for regions that are not tables.
   -------------------------------------------------------------------------- */
.skeleton-card {
  padding: 1.1rem 1.25rem;
  background: var(--color-white, #fff);
  border: 1px solid var(--color-border, rgba(15, 23, 42, 0.1));
  border-radius: 10px;
  margin-bottom: 0.75rem;
}

.skeleton-card-head {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  margin-bottom: 0.9rem;
}

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

@media (min-width: 1200px) {
  .skeleton-fields { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* --------------------------------------------------------------------------
   A skeleton is a hint, not an animation showcase. With reduced motion the
   sheen stops and the blocks simply sit there — still communicating shape,
   which is the part that carries the meaning.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .skeleton::after {
    animation: none;
    display: none;
  }
}
