/* Tentaguiden — laddningstillstånd.

   Ersätter orden "Laddar…" och "Läser in" med en yta som har samma form som
   innehållet som är på väg in. Formen bär informationen: den säger vad som
   kommer och gör att layouten inte hoppar när det kommer. Svepet över ytan
   säger att något pågår. Ordet behövs bara för skärmläsare och ligger i
   .tg-dold.

   Färgerna härleds ur currentColor i stället för ur namngivna tokens, så
   filen fungerar oförändrad i huvudsajtens alla teman, i labbets egen
   uppsättning (--ink i stället för --text) och i verktygens shared.css. */

/* Väntan under ungefär en femtedels sekund ska aldrig synas. Fördröjningen
   gör att skelettet hinner ersättas av riktigt innehåll innan det tonat
   fram, i stället för att blinka förbi vid varje cacheträff. */
.tg-laddar {
  display: block;
  animation: tg-fram .32s cubic-bezier(.2,.7,.2,1) .18s both;
}
@keyframes tg-fram { from { opacity: 0; } to { opacity: 1; } }

.tg-sk {
  position: relative;
  overflow: hidden;
  background: rgba(128, 128, 128, .15);
  background: color-mix(in srgb, currentColor 10%, transparent);
  border-radius: 999px;
}

/* Svepet ligger drygt en tredjedel av cykeln utanför ytan. Utan pausen läser
   ögat rörelsen som ett blinkande i stället för som något pågående. */
.tg-sk::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, rgba(128, 128, 128, .2), transparent);
  background: linear-gradient(90deg, transparent,
              color-mix(in srgb, currentColor 9%, transparent) 50%, transparent);
  transform: translateX(-101%);
  animation: tg-svep 1.6s cubic-bezier(.4, .05, .25, 1) infinite;
  animation-delay: calc(var(--tg-i, 0) * .09s);
}
@keyframes tg-svep {
  0%        { transform: translateX(-101%); }
  62%, 100% { transform: translateX(101%); }
}

/* ── Textrader ──────────────────────────────────────────────────────────
   Måtten är i em och ärver därför värdelementets egen typografi: samma
   markup ger rubrikhöga staplar i en h1 och brödtexthöga i ett stycke.
   Gap och padding räknas ur radhöjden så att n staplar tar exakt lika
   mycket plats som n rader text, annars hoppar sidan när texten kommer. */
.tg-sk-text {
  --tg-lh: 1.35;
  display: grid;
  gap: calc((var(--tg-lh) - .62) * 1em);
  padding: calc((var(--tg-lh) - .62) / 2 * 1em) 0;
}
.tg-sk-text > .tg-sk { height: .62em; border-radius: .31em; }

/* ── Block ──────────────────────────────────────────────────────────────
   Rader, kort och listposter. Höjd, radie och mellanrum sätts av den sida
   som använder skelettet, så att formen matchar det som ska in. */
.tg-sk-block { display: grid; gap: var(--tg-gap, 8px); }
.tg-sk-block > .tg-sk {
  height: var(--tg-h, 64px);
  border-radius: var(--tg-r, 12px);
}

/* ── Märket ─────────────────────────────────────────────────────────────
   För väntan där innehållet inte har någon form att härma: en canvas som
   ska renderas, ett tal som ska räknas fram. Stapelvågen går åt samma håll
   som läsningen och vilar mellan varven. */
.tg-mark {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: inherit;
}
.tg-mark > span {
  display: block;
  width: 3px;
  height: var(--tg-mark-h, 16px);
  border-radius: 999px;
  background: currentColor;
  opacity: .22;
  transform: scaleY(.5);
  animation: tg-puls 1.3s cubic-bezier(.4, 0, .2, 1) infinite;
}
.tg-mark > span:nth-child(2) { animation-delay: .09s; }
.tg-mark > span:nth-child(3) { animation-delay: .18s; }
.tg-mark > span:nth-child(4) { animation-delay: .27s; }
.tg-mark > span:nth-child(5) { animation-delay: .36s; }
@keyframes tg-puls {
  0%, 58%, 100% { opacity: .22; transform: scaleY(.5); }
  20%           { opacity: 1;   transform: scaleY(1); }
}

/* ── Övergången ─────────────────────────────────────────────────────────
   Bara opacitet. En transform här skulle göra behållaren till containing
   block för position: sticky och fixed inuti, och stickyrubrikerna i
   ämnesguiderna och muntasidan skulle glappa under animationen. */
.tg-in { animation: tg-in .38s cubic-bezier(.2, .7, .2, 1) both; }
@keyframes tg-in { from { opacity: 0; } to { opacity: 1; } }

/* Väntan finns kvar för skärmläsare även när den inte längre står i bild. */
.tg-dold {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

@media (prefers-reduced-motion: reduce) {
  .tg-laddar { animation: none; }
  .tg-sk::after { animation: none; opacity: 0; }
  .tg-mark > span { animation: none; opacity: .45; transform: none; }
  .tg-in { animation: none; }
}
