/* ============================================================
   Motiva branded loader — the "build" animation

   Geometry is NOT drawn here. It is measured off the Motiva
   wordmark in Client/wwwroot/images/motiva-logo.png — the mark is
   the "o" of that logo — and lives in MotivaLoaderMark.razor.
   Read the header there before changing any number in this file;
   it explains why the two SVGs in wwwroot/assets/loader/ are NOT
   the source (they miss the logo badly) and how the composition
   is put together.

   What matters here:

     purple #591AE0  bottom + left arm   (draws first)
     teal   #02A0A6  top + right arm     (follows)

   Both halves sit on one shared centreline rectangle 453 x 368,
   corner radius 152, stroke 100. Each arm stops short of the
   corner the other one owns, which is what opens the two seams —
   171.6 units between the facing ends. The strokes must never
   touch at ANY frame of the loop, peak thickness included; that
   is a hard requirement of the mark, and it is what caps the
   animated stroke-width below.

   The two halves are the same length (515.8), so the draw reads
   at one speed across the colour change.

   WHY THIS IS A GLOBAL STYLESHEET rather than the .razor.css that
   the rest of Components/ uses: index.html's pre-boot splash needs
   the identical loader before Blazor — and therefore before CSS
   isolation — exists. One global file is the only way index.html
   and the Razor components can share a single set of rules instead
   of keeping two copies in sync.
   ============================================================ */

.motiva-loader {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 14px;
}

/* ---------- the mark ---------------------------------------- */

.motiva-loader-mark {
    display: block;
    flex: none;
    width: 56px;
    /* Matches the viewBox in the markup — which is the exact ink bounds at
       the animated peak, so there is no padding to shrink the mark inside
       its box, and the ratio is the logo's own (1.180 against the wordmark's
       measured 1.184). Never let these two drift apart. */
    aspect-ratio: 558 / 473;
    height: auto;
}

.motiva-loader-path {
    fill: none;
    /* 100 against a 453-wide centreline rectangle is 0.22, the wordmark's own
       stroke-to-width ratio. The mark used to be stroked at 0.31 of its
       width, which is what made the loader read as far heavier than the
       logo it is supposed to be. */
    stroke-width: 100;
    stroke-linecap: round;
    stroke-linejoin: round;

    /* A dash of 1000 and a gap of 1000 over the normalised
       pathLength="1000" on each <path>. Sweeping the offset
       1000 → 0 draws the stroke forward from its start; carrying the
       same sweep on to −1000 retracts the tail from that same start.
       So one monotonic offset does both the draw and the clear, and
       the clear continues the stroke's own direction of travel
       instead of snapping off. */
    stroke-dasharray: 1000 1000;
    stroke-dashoffset: 1000;

    animation: motiva-loader-draw 1.2s cubic-bezier(.45, 0, .2, 1) infinite;
}

/* Purple leads. Blue follows 0.2s later — 17% of the 1.2s loop — which
   is the moment purple's head has crossed the top-left seam, so teal reads
   as the continuation of one stroke rather than a second thing starting.
   The seam is a gap, never a joint: the handoff is a matter of timing, not
   of the two ends meeting. Shortening the loop shortened this in step: the
   stagger is a fraction of the draw, not a fixed wait, so the handoff
   still lands at the same point in the movement. */
.motiva-loader-purple { stroke: #591AE0; animation-delay: 0s; }
.motiva-loader-blue   { stroke: #02A0A6; animation-delay: 0.2s; }

@keyframes motiva-loader-draw {
    /* Percentages, not seconds, so the phases keep their proportions if the
       loop length changes.

       0→30%   draw          (thickens to 105 — 5% over 100 — while the head
                              is actually moving, then settles back just after
                              the path completes. 5% is deliberately the
                              faintest weight change that still reads: the
                              mark's job is to match the logo, and thickness
                              is the one axis where it most easily drifts off
                              it. The two facing ends are 171.6 apart, so 100
                              leaves 71.6 units of white and 105 leaves 66.6 —
                              about two thirds of a stroke either way.
                              Anything approaching 171 would close the seams,
                              which the mark is not allowed to do.)
       30→62%  hold complete (32% > the 17% stagger, so there is a real window
                              where both halves are whole — this is the frame
                              that has to match the static logo)
       62→92%  clear
       92→100% rest */
    0%   { stroke-dashoffset: 1000;  stroke-width: 100; }
    8%   {                           stroke-width: 105; }
    26%  {                           stroke-width: 105; }
    30%  { stroke-dashoffset: 0; }
    36%  {                           stroke-width: 100; }
    62%  { stroke-dashoffset: 0; }
    92%  { stroke-dashoffset: -1000; }
    100% { stroke-dashoffset: -1000; stroke-width: 100; }
}

/* ---------- the label --------------------------------------- */

.motiva-loader-label {
    margin: 0;
    font-family: Heebo, 'Assistant', 'Helvetica Neue', Helvetica, Arial, sans-serif;
    font-weight: 500;
    font-size: var(--motiva-font-size-body, 14px);
    line-height: 1.4;
    letter-spacing: -0.01em;
    color: var(--motiva-text-primary, #1e293b);
    text-align: center;
    /* The app sets RTL through the CSS `direction` property rather than a
       dir attribute, and this component is also rendered by index.html
       before any of that cascade exists. Stating it locally is what keeps
       the trailing "..." on the correct side in both situations —
       `isolate` stops the dots being re-ordered by whatever encloses the
       loader. The mark above is geometry, not text, so it is untouched by
       either declaration and never mirrors. */
    direction: rtl;
    unicode-bidi: isolate;
}

/* ---------- size modifiers ---------------------------------- */

.motiva-loader-sm { gap: 10px; }
.motiva-loader-sm .motiva-loader-mark  { width: 32px; }
.motiva-loader-sm .motiva-loader-label { font-size: var(--motiva-font-size-meta, 12.5px); }

.motiva-loader-lg { gap: 18px; }
.motiva-loader-lg .motiva-loader-mark  { width: 88px; }
.motiva-loader-lg .motiva-loader-label { font-size: var(--motiva-font-size-lg, 15px); }

/* ---------- pre-boot splash (index.html) --------------------- */

.motiva-loader-boot {
    min-height: 100vh;
    min-height: 100dvh;
}

/* ---------- reduced motion ----------------------------------- */

@media (prefers-reduced-motion: reduce) {
    .motiva-loader-path {
        animation: none;
        /* The finished mark, held: offset 0 with the base weight. This is
           the state that has to be indistinguishable from the logo. */
        stroke-dashoffset: 0;
        stroke-width: 100;
    }
}

/* ---------- standalone mark sizes ---------------------------- */

/* For a host that already owns the status role and the visible label and so
   renders MotivaLoaderMark on its own, without the .motiva-loader wrapper the
   modifiers above hang off. MLoadingState's Block variant is the one such
   host today. Declared after the base .motiva-loader-mark width so that, at
   equal specificity, these win. */
.motiva-loader-mark-sm { width: 32px; }
.motiva-loader-mark-md { width: 44px; }
.motiva-loader-mark-lg { width: 88px; }
