/* =====================================================================
   loader.css — TestMacher canonical loader system
   =====================================================================
   Two variants exported by this file:

   1) Full-page / panel loader  →  .tm-loader   (110 x 110 SVG with shield,
      T crossbar/stem stroke draw-in, paper fade, nib drop, breather pop).
      Use for initial app loads, route transitions, blocking operations.

   2) Inline button + chip loader → .tm-inline  (22 x 22 SVG with just the
      T crossbar + stem). Place inside <button>, <a>, or <span class="chip">
      to show a "loading…/saving…" state without breaking the surrounding
      flex layout.

   Pair the markup with the partials in Qbuild/templates/Qbuild/partials/:
       _tm_loader.html   (full)
       _tm_inline.html   (inline button/chip variant)

   ===================================================================== */

/* ─────────── Full-page / panel loader ─────────── */
.tm-loader {
  width: 110px;
  height: 110px;
  position: relative;
  display: inline-block;
}
.tm-loader svg { width: 100%; height: 100%; }

.tm-loader .shield {
  transform-origin: center;
  animation: tm-pulse 3s ease-in-out infinite;
}
.tm-loader .shield-border {
  stroke-dasharray: 130;
  stroke-dashoffset: 130;
  animation: tm-border 3s cubic-bezier(0.5, 0, 0.5, 1) infinite;
}
.tm-loader .paper {
  opacity: 0.15;
  animation: tm-paper 3s ease-in-out infinite;
}
.tm-loader .crossbar {
  stroke-dasharray: 22;
  stroke-dashoffset: 22;
  animation: tm-cross 3s ease-in-out infinite;
}
.tm-loader .stem {
  stroke-dasharray: 18;
  stroke-dashoffset: 18;
  animation: tm-stem 3s ease-in-out infinite;
  animation-delay: 0.3s;
}
.tm-loader .nib {
  opacity: 0;
  transform-origin: 31px 36px;
  transform-box: fill-box;
  animation: tm-nib 3s ease-in-out infinite;
  animation-delay: 1.0s;
}
.tm-loader .breather {
  opacity: 0;
  animation: tm-breather 3s ease-in-out infinite;
  animation-delay: 1.4s;
}

@keyframes tm-border {
  0%, 5%   { stroke-dashoffset: 130; }
  85%, 92% { stroke-dashoffset: 0; }
  100%     { stroke-dashoffset: 0; opacity: 0; }
}
@keyframes tm-cross {
  0%, 8%   { stroke-dashoffset: 22; }
  30%, 80% { stroke-dashoffset: 0; }
  92%      { stroke-dashoffset: 0; opacity: 1; }
  100%     { stroke-dashoffset: 0; opacity: 0; }
}
@keyframes tm-stem {
  0%, 12%  { stroke-dashoffset: 18; }
  35%, 80% { stroke-dashoffset: 0; }
  92%      { stroke-dashoffset: 0; opacity: 1; }
  100%     { stroke-dashoffset: 0; opacity: 0; }
}
@keyframes tm-nib {
  0%, 32%  { opacity: 0; transform: translateY(-3px) scale(0.6); }
  45%, 80% { opacity: 1; transform: translateY(0) scale(1); }
  92%      { opacity: 1; }
  100%     { opacity: 0; transform: translateY(0) scale(1); }
}
@keyframes tm-breather {
  0%, 45%  { opacity: 0; transform: scale(0); }
  55%, 80% { opacity: 1; transform: scale(1); }
  92%      { opacity: 1; }
  100%     { opacity: 0; transform: scale(1); }
}
@keyframes tm-pulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.02); }
}
@keyframes tm-paper {
  0%, 12%  { opacity: 0; }
  30%, 92% { opacity: 0.15; }
  100%     { opacity: 0; }
}

/* Status text underneath the full loader (optional) */
.tm-loader-status {
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 18px;
  font-weight: 500;
  text-align: center;
  margin-top: 18px;
  min-height: 26px;
  letter-spacing: -0.005em;
  color: #0F172A;
}
.tm-loader-status .dots::after {
  content: '';
  display: inline-block;
  width: 14px;
  text-align: left;
  animation: tm-dots 1.4s steps(4, end) infinite;
}
@keyframes tm-dots {
  0%, 25%   { content: ''; }
  25%, 50%  { content: '.'; }
  50%, 75%  { content: '..'; }
  75%, 100% { content: '...'; }
}
.tm-loader-sub {
  font-size: 12px;
  color: #475569;
  text-align: center;
  margin-top: 4px;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
}

/* Centred page-overlay variant — full viewport with dim backdrop */
.tm-loader--overlay {
  position: fixed;
  inset: 0;
  z-index: 9999;
  background: rgba(248, 250, 252, 0.92);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
}
.tm-loader--overlay .tm-loader { margin: 0 auto; }

/* ─────────── Inline (button + chip) loader ─────────── */
.tm-inline {
  width: 18px;
  height: 18px;
  display: inline-block;
  vertical-align: middle;
  flex-shrink: 0;
}
.tm-inline svg {
  width: 100%;
  height: 100%;
  display: block;
}
.tm-inline .crossbar {
  stroke-dasharray: 16;
  stroke-dashoffset: 16;
  animation: tm-cross-mini 1.6s ease-in-out infinite;
}
.tm-inline .stem {
  stroke-dasharray: 14;
  stroke-dashoffset: 14;
  animation: tm-stem-mini 1.6s ease-in-out infinite;
  animation-delay: 0.2s;
}
@keyframes tm-cross-mini {
  0%, 8%   { stroke-dashoffset: 16; }
  35%, 80% { stroke-dashoffset: 0; }
  100%     { stroke-dashoffset: 0; opacity: 0; }
}
@keyframes tm-stem-mini {
  0%, 12%  { stroke-dashoffset: 14; }
  40%, 80% { stroke-dashoffset: 0; }
  100%     { stroke-dashoffset: 0; opacity: 0; }
}

/* Hidden by default — show only when host element has .is-loading */
.tm-inline { display: none; }
.is-loading .tm-inline,
button.is-loading .tm-inline,
.chip.is-loading .tm-inline { display: inline-block; }

/* When loading, soften text colour slightly so the spinner reads */
.is-loading .tm-inline + * { opacity: 0.85; }
