/* ============================================================================
   rloader.css — the Repark branded loading mark.

   ONE component for "something is happening". The favicon mark performing a
   single backwards flip: a jump arc, a full backwards rotation, and a squash
   on takeoff and landing. No ground shadow — deliberately.

   WHY THE MARK IS INLINE SVG AND NOT AN <img>
     The first consumer is the boot splash, which paints before the app boots.
     An <img src> there is a network round-trip at exactly the moment the user
     is already waiting on one. The SVG is inlined into the markup instead —
     literally in index.html for the splash, and by rloader.js for every later
     consumer. Nothing here fetches anything.

   GEOMETRY IS NOT FREE-HAND. It is favicon.svg's, as recorded in
   scripts/generate-pwa-icons.js:21 — corner radius 15/64 of the side, glyph
   font-size 38/64, baseline 13/64 below centre, Arial weight 900. The animated
   mark and the browser-tab favicon appear on screen within a second of each
   other during boot, so any drift between the two is directly visible.

   MOTION TOKENS ONLY. motion.css:10-14 forbids raw ms values and raw
   cubic-beziers. Every duration and easing below is a --t-* / --e-* token.

   THREE NEW KEYFRAMES — rload-hop, rload-flip, rload-squash.
   motion.css:13 forbids a new keyframe for shimmer / spin / pop / fade /
   pulse. A flip is none of those five: it is a vertical arc plus a rotation
   plus a non-uniform scale, and no existing keyframe in the app animates any
   of them. All three names were verified free against public/css/*.css AND
   the 35 keyframes injected from JS before being used.

   SIZE. Nothing below declares --rload-size. Every reference carries its own
   72px fallback, so an instance either sets --rload-size inline or gets 72px,
   and no specificity fight with a later stylesheet is possible.

   NO FORM CONTROLS, NO TABLE. style.css:1 styles bare <button>, <input>,
   <select>, <textarea>, <table>, <th> and <td> with unscoped element
   selectors, and any <table> inside a .tab is card-ified under 1180px by
   mobileEnhance.js:283 plus four global rules in responsive.css. This
   component is <div>/<svg>/<span> only, which inherits nothing but body's
   font and the box-sizing reset.
   ========================================================================== */

/* Sentinel — rloader.js reads this back to prove the stylesheet actually
   loaded. If the <link> 404s this is empty and the boot line says MISSING. */
:root{ --rload-css:"20260910a"; }

/* ── The stage ───────────────────────────────────────────────────────────────
   Reserves the full travel of the animation so nothing around it reflows as
   the mark jumps. Width is 2.2x the mark because a square's bounding box grows
   to 1.41x mid-rotation; height is 2x because the arc peaks at 1.02x. */
.rload{
  display:flex; align-items:flex-end; justify-content:center;
  position:relative;
  width:calc(var(--rload-size,72px) * 2.2);
  height:calc(var(--rload-size,72px) * 2);
}

/* Three nested elements, not one. They cannot be collapsed: the arc, the
   rotation and the squash each need their own timing function, and the squash
   needs transform-origin at the feet while the rotation needs it at the
   centre. One element cannot hold two transform-origins. */
.rload-hop,
.rload-spin{ display:block; }
.rload-squash{ display:block; transform-origin:50% 100%; }

.rload-mk{
  display:block;
  width:var(--rload-size,72px);
  height:var(--rload-size,72px);
}
/* The inline <svg> also carries width/height attributes, so if this stylesheet
   fails to load the mark still paints at its intrinsic 64px rather than
   collapsing to a zero-height box. */
.rload-mk > svg{ display:block; width:100%; height:100%; }

.rload .rload-hop{ animation:rload-hop var(--t-pulse) infinite; }
.rload .rload-spin{ animation:rload-flip var(--t-pulse) infinite; }
.rload .rload-squash{ animation:rload-squash var(--t-pulse) infinite; }

/* ── The keyframes ───────────────────────────────────────────────────────────
   Per-step timing functions: the takeoff is --e-out (fast off the floor), the
   airtime is --e-in-out (it decelerates into the peak and accelerates out).
   Landing holds from 88% so the mark is still for a beat before the next hop —
   without that pause it reads as a frantic bounce rather than one deliberate
   flip per cycle. */
@keyframes rload-hop{
  0%   { transform:translateY(0); animation-timing-function:var(--e-out); }
  10%  { transform:translateY(0); animation-timing-function:var(--e-out); }
  50%  { transform:translateY(calc(var(--rload-size,72px) * -1.02)); animation-timing-function:var(--e-in-out); }
  88%,
  100% { transform:translateY(0); }
}
/* Backwards: the rotation is negative. The +10deg at 10% is the wind-up — the
   mark tips slightly forward before throwing itself back, which is what makes
   it read as a jump rather than a spin that happens to move up. */
@keyframes rload-flip{
  0%   { transform:rotate(0); }
  10%  { transform:rotate(10deg); animation-timing-function:var(--e-in-out); }
  88%,
  100% { transform:rotate(-360deg); }
}
/* Squash on takeoff (wide and short), stretch just after (narrow and tall),
   neutral at the peak, then the same pair inverted on landing. */
@keyframes rload-squash{
  0%   { transform:scale(1,1); }
  9%   { transform:scale(1.13,.87); }
  22%  { transform:scale(.94,1.08); }
  50%  { transform:scale(1,1); }
  82%  { transform:scale(.96,1.05); }
  91%  { transform:scale(1.15,.85); }
  100% { transform:scale(1,1); }
}

/* ── Optional caption ────────────────────────────────────────────────────────
   Unused by the boot splash, which has its own wordmark and caption. This is
   for the later gap-site consumers (table refresh, the modules currently
   showing a bare "Loading..." string). */
.rload-wrap{ display:flex; flex-direction:column; align-items:center; justify-content:center; }
.rload-label{ margin-top:6px; font-size:13px; color:#51607a; text-align:center; }

/* ── Dark theme ──────────────────────────────────────────────────────────────
   dark.css loads 5th of 36, so it wins on specificity (html[data-theme] is
   0,2,0) rather than on order — a plain-class rule in a later stylesheet does
   NOT beat it. Anything here that must differ in dark is written at the same
   specificity on purpose.

   Only the caption needs an override. The mark is a #0369a1 tile with a white
   R, which carries on the dark surfaces (#162133 / #0f1e2e) as well as on
   white, so it is deliberately identical in both themes. */
html[data-theme="dark"] .rload-label{ color:#9fb0c4; }

/* ── Pause while the tab is hidden ───────────────────────────────────────────
   raiOrb.js:16-19 sets the precedent: an idle animation that lives on screen
   for a whole session must not composite in a background tab. rloader.js
   toggles the root class on visibilitychange. If that script never runs the
   animation simply keeps going — degraded, not broken. */
html.rload-paused .rload-hop,
html.rload-paused .rload-spin,
html.rload-paused .rload-squash{ animation-play-state:paused; }

/* ── The two size steps ──────────────────────────────────────────────────────
   72  splash        the full-screen boot splash
   44  panel/table   a table body or panel that has cleared >= 88px of space
   Callers pass one of these as --rload-size (rloader.js emits it inline).
   Nothing else is a step — an arbitrary size is a bug, not a tuning knob.

   A third step, 28px for a 90px-140px container, was defined and then removed:
   every container measured in this codebase clears 822px, and the small ones
   (table rows, cells, inline spans) sit UNDER 90px rather than inside that
   band. It had no consumer and no candidate. Deleted rather than kept on the
   chance something might use it — rmsSkeleton and rkClearSkeleton are already
   carried in mobileEnhance.js with zero callers, and neither got easier to
   remove for having waited. */

/* ── The slot a table-refresh loader sits in ─────────────────────────────────
   Reserves the row area so the table body does not collapse to nothing while
   it loads. 210px matches the signed-off prototype. */
.rload-slot{
  display:flex; align-items:center; justify-content:center;
  min-height:210px;
}
/* .rk-deskonly carries `display:none !important` below 1180px, and the
   unprefixed `display:flex` here deliberately does NOT, so the mobile rule
   still wins and the two treatments can never both paint. */

/* ── The delay threshold, in CSS ─────────────────────────────────────────────
   Screens like B&Q Orders and Easy Ship render by rebuilding an innerHTML
   string, so there is no element to hand a JS timer to — the markup either is
   or is not in that string. The threshold therefore has to live in CSS: the
   loader is in the DOM immediately but holds at opacity 0 for --t-slow, and a
   refresh that finishes first replaces it before it was ever visible.

   REUSES rms-fade (motion.css:78) rather than declaring a fade of its own,
   because motion.css:13 forbids a new keyframe for exactly this. `both` is
   load-bearing: it holds the `from` (opacity:0) during the delay.

   Under reduced motion the global guard clamps the DURATION to 1ms but leaves
   the DELAY alone, so the behaviour survives — nothing appears for --t-slow,
   then the mark appears without a fade. That is the correct outcome for both
   settings. */
.rload-defer{ animation:rms-fade var(--t-base) var(--e-out) var(--t-slow) both; }

/* ── Reduced motion ──────────────────────────────────────────────────────────
   motion.css:112-123 already clamps every animation in the app to 1ms / 1
   iteration with !important on *, so this cannot and does not try to override
   it. What it does instead is fix the RESTING STATE, which the global guard
   knows nothing about.

   Without this block the mark would sit at the bottom of a box twice its own
   height, with a large empty gap above it where the arc used to be — reading
   as a broken layout rather than a still one. Centring it and collapsing the
   reserved travel gives a mark that is simply upright and level.

   `animation:none` (rather than relying on the 1ms clamp) also removes the
   single-frame flash on entry. Same shape as the four fallbacks already in
   the app: index.html:93, mobile-kit.css:455-457, social.css:163-165,
   ui-kit.css:111 — neutralise the motion, keep the affordance. */
@media (prefers-reduced-motion:reduce){
  .rload{
    align-items:center;
    height:calc(var(--rload-size,72px) * 1.5);
  }
  .rload-hop,
  .rload-spin,
  .rload-squash{
    animation:none !important;
    transform:none !important;
  }
}
