/* ============================================================
   Make My — logo motion
   Source artwork: Branding/Logos/DIGITAL_RGB (unmodified paths)
   Every resting state is the delivered mark. Nothing is redrawn.

   Markup comes from inc/logo-motion.php — that file holds the only
   copy of the path data. The two `d: path(...)` values below are the
   one exception: CSS keyframes cannot read a PHP constant, so the
   square and rounded endpoints of the corner morph are stated here.
   They are generated from the documented geometry constants, and the
   asymmetric radius (bay ceiling meets a full-height upright at
   22.12, meets a shelf divider square) is encoded in them — if these
   are ever regenerated, that asymmetry has to survive.
   ============================================================ */

/* --- Homepage reveal: clockwise trace from top centre -------
   The outline is authored anti-clockwise, so the dash grows
   BACKWARDS from the top-centre point (89.805% along the square
   outline) to read as clockwise. 0.89805 is the measured fraction
   at which x = 320.655, y = 22.87 — if the path changes, re-measure
   with getPointAtLength(), do not estimate. Dash + gap must always
   sum to the full pathLength or the run from the top-left corner
   back to top centre never draws. pathLength="1" on the element is
   what makes these fractions work; keep it.                     */
@keyframes mm-trace-cw {
  from { stroke-dasharray: 0 1; stroke-dashoffset: -0.89805; }
  to   { stroke-dasharray: 1 0; stroke-dashoffset:  0.10195; }
}

/* --- Corners ease from square to the delivered radii --------
   Both endpoints share an identical command sequence, which is
   what makes the d interpolation legal.

   Animating `d` needs Chrome 88+, Safari 16.4+, Firefox 128+.
   Everywhere else the corners simply snap at the keyframe
   boundary — the fill and the resting frame are unaffected, so
   no fallback is required.                                     */
@keyframes mm-radius {
  from { d: path("M22.87 22.87V256.59H68.68V68.68A0 0 0 0 1 68.68 68.68H160.32A0 0 0 0 1 160.32 68.68V196.35H206.13V68.68A0 0 0 0 1 206.13 68.68H297.76A0 0 0 0 1 297.76 68.68V256.59H343.57V68.68A0 0 0 0 1 343.57 68.68H435.21A0 0 0 0 1 435.21 68.68V196.35H481.02V68.68A0 0 0 0 1 481.02 68.68H572.65A0 0 0 0 1 572.65 68.68V256.59H618.46V22.87A0 0 0 0 0 618.46 22.87H22.87A0 0 0 0 0 22.87 22.87Z"); }
  to   { d: path("M22.87 81.95V256.59H68.68V90.8A22.12 22.12 0 0 1 90.8 68.68H160.32A0 0 0 0 1 160.32 68.68V196.35H206.13V68.68A0 0 0 0 1 206.13 68.68H275.64A22.12 22.12 0 0 1 297.76 90.8V256.59H343.57V90.8A22.12 22.12 0 0 1 365.69 68.68H435.21A0 0 0 0 1 435.21 68.68V196.35H481.02V68.68A0 0 0 0 1 481.02 68.68H550.53A22.12 22.12 0 0 1 572.65 90.8V256.59H618.46V81.95A59.08 59.08 0 0 0 559.38 22.87H81.95A59.08 59.08 0 0 0 22.87 81.95Z"); }
}

@keyframes mm-fill     { to { fill-opacity: 1; } }
@keyframes mm-unstroke { to { stroke-opacity: 0; } }

/* --- Divider: line extends out from the mark ---------------- */
@keyframes mm-extend { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes mm-pop {
  0%   { opacity: 0; transform: scale(.4); }
  62%  { opacity: 1; transform: scale(1.09); }
  100% { opacity: 1; transform: scale(1); }
}

/* ---------- element classes ---------- */

/* Colours resolve through the theme's own tokens (--ink is Coal #231F1F,
   --paper is White) with the brand hex as the standalone fallback, so a
   reversed lockup stays a one-line colour change. */
.mm-reveal            { display: block; width: 100%; max-width: 400px; height: auto; color: var(--ink, #231F1F); }
.mm-reveal--reversed  { color: var(--paper, #FFFFFF); }

.mm-reveal__fill {
  fill: currentColor;
  fill-opacity: 0;
  animation: mm-fill .55s ease 3.15s forwards;
}
.mm-reveal__line {
  fill: none;
  stroke: currentColor;
  stroke-width: 4;              /* user units, not px — scales with the viewBox */
  animation:
    mm-trace-cw 2.1s cubic-bezier(.62, 0, .34, 1) forwards,
    mm-radius    .9s cubic-bezier(.33, 0, .2,  1) 2.15s forwards,
    mm-unstroke  .5s ease 3.2s forwards;
}

/* There is no in-page Trace LOADER here. The `.mm-loader` family and its
   `mm-loop` keyframe were deleted 2026-08-17 (efficiency #248) along with
   makemy_logo_loader(), which no template ever called. The two live Trace
   surfaces both hold their own rules by design: the configurator's WASM
   overlay injects `.replicad-loading-mark` from
   Plugin/core/src/replicad-shared/runtime/ProgressBar.js (the plugin is a
   separate release unit and must load on any theme), and the animated favicon
   strokes a canvas from the constants in inc/logo-motion.php. Don't add a
   theme-side loader back without markup that emits it. */

.mm-divider      { display: flex; align-items: center; gap: 26px; padding: 30px 0; color: var(--ink, #231F1F); }
.mm-divider__line {
  flex: 1; height: 1px; background: currentColor; opacity: .3;
  animation: mm-extend 1s cubic-bezier(.62, 0, .34, 1) both;
}
.mm-divider__line:first-child { transform-origin: right center; }
.mm-divider__line:last-child  { transform-origin: left center; }
.mm-divider__mark {
  width: 68px; height: auto; flex: none; fill: currentColor;
  animation: mm-pop .6s cubic-bezier(.2, 1.3, .4, 1) .6s both;
}
/* Held until scrolled into view. The PAUSED state is the animation start, so
   if logo-motion.js never runs the worst case is a static divider, never a
   blank gap. Do not invert this to "add a class to start". */
.mm-divider.is-pending .mm-divider__line,
.mm-divider.is-pending .mm-divider__mark { animation-play-state: paused; }

/* The block editor has no scroll observer running over the canvas, so show
   dividers settled there rather than frozen at their paused first frame. */
.editor-styles-wrapper .mm-divider.is-pending .mm-divider__line,
.editor-styles-wrapper .mm-divider.is-pending .mm-divider__mark { animation-play-state: running; }

/* animate: false — no is-pending, no observer, no animation: the end state is
   what paints. mm-extend and mm-pop only ever move `transform` and `opacity`,
   both of which fall back to the declarations above, so removing the animation
   is the whole of it. This is the SAME frame reduced motion resolves to below;
   it is not a second design. */
.mm-divider--static .mm-divider__line,
.mm-divider--static .mm-divider__mark { animation: none; }

/* --- Divider: the `through` rule -----------------------------
   One unbroken rule the full width with the mark over it, instead of the two
   lines and the 26px gap. It still scales out from the CENTRE, which is why the
   transform-origin has to beat the :first-child/:last-child pair above — the
   lone line matches both. */
.mm-divider--through { position: relative; justify-content: center; gap: 0; }
.mm-divider--through .mm-divider__line--through {
  position: absolute; left: 0; right: 0; top: 50%; flex: none;
  transform-origin: center center;
}
.mm-divider--through .mm-divider__mark { position: relative; }

/* --- Divider: `seam` placement -------------------------------
   The divider sits ON a tone change rather than inside a band. The wrapper's
   position comes from the block (see src/blocks/logo-divider/style.scss); what
   belongs to the component is that a seam rule crosses two tones at once, so it
   is stated as Rule Strong (Stone) — a structural border, §3.4 — rather than as
   Ink at 30%, which reads differently against Paper than against Pebble. Both
   pairings are measured in tests/js/Theme/design-contrast.test.js.

   Two classes deep on purpose: it has to outrank the reduced-motion reset below,
   which restates the in-band 30%.

   Unlike --ink/--paper above, the two rule tokens get NO standalone hex fallback:
   --rule is a color-mix derivation, so any literal here would be a colour the
   brand does not own. These two treatments need main.css, and always have it. */
.mm-divider--seam { padding: 0; }
.mm-divider--seam .mm-divider__line { background: var(--rule-strong); opacity: 1; }

/* --- Divider: the pre-footer walking mark --------------------
   The divider's mark on a horizontal axis, on the floor of the band that closes
   the page. It rocks onto each foot and walks the width of the band, once, off
   the right-hand edge — started by logo-motion.js when the band comes into view.

   THE RESTING FRAME IS THE START, as everywhere in this file: no animation is
   declared until .is-walking is on the band, so the mark stands upright at the
   left — where it has always stood — for a page with no script, no observer, or
   reduced motion asked for. Same paused-is-the-start rule as .is-pending above.
   Do not invert it into "JS adds the mark".

   TWO ELEMENTS, TWO TRANSFORMS. The traveller crosses, the mark inside it rocks.
   They cannot be one element: a single `transform` would have the two keyframe
   sets overwrite each other rather than compose.

   The band paints its own tone; the mark takes the tone of the band NEXT to it,
   which is why the fill is a surface token and not Ink at low opacity. It is
   aria-hidden, inert to the pointer, and sits under everything the band holds. */
.mm-walk { position: relative; overflow: hidden; }

/* left AND right, so the traveller spans the band and `translateX(100%)` is one
   band-width of travel — the mark starts at the left edge and clears the right.
   That is what makes the crossing pure CSS: nothing has to measure the band.

   The negative `bottom` seats the DRAWN feet on the band's floor. The viewBox
   carries 22.87/641.31 = 0.035657 of its width as clear space below the mark, so
   an un-nudged bottom: 0 floats the device that far above the edge. */
.mm-walk__traveller {
  --mm-walk-mark: 130px;
  position: absolute; left: 0; right: 0;
  bottom: calc(-0.035657 * var(--mm-walk-mark));
  pointer-events: none; z-index: 0;
}

/* --mm-walk-lift cancels the corner dip at full lean: the mark rocks about its
   bottom centre, so at 1.5deg its outer bottom corner swings BELOW the baseline
   by (drawnWidth / 2) x sin(1.5deg) — with the drawn mark at 595.59/641.31 of
   the box, that is markWidth x 0.01215. The lift puts it back, so the lowest
   point of the cycle is contact with the floor rather than a foot through it.
   CHANGE THE 1.5deg AND YOU MUST RECOMPUTE 0.01215, or the feet break the line. */
.mm-walk__mark {
  --mm-walk-lift: calc(var(--mm-walk-mark) * 0.01215);
  display: block; width: var(--mm-walk-mark); height: auto;
  fill: var(--paper-soft);
  transform-origin: 50% 100%;
}

/* Upright at 0/50/100% rather than at full lean, so the frame the mark rests on
   before the walk starts — and the one it is left in under reduced motion — is a
   device standing straight up. Same rock, phase-shifted. */
@keyframes mm-walk-cross {
  from { transform: translateX(0); }
  to   { transform: translateX(100%); }
}
@keyframes mm-walk-lean {
  0%, 50%, 100% { transform: translateY(0) rotate(0deg); }
  25%           { transform: translateY(calc(-1 * var(--mm-walk-lift))) rotate(-1.5deg); }
  75%           { transform: translateY(calc(-1 * var(--mm-walk-lift))) rotate(1.5deg); }
}

.mm-walk.is-walking .mm-walk__traveller { animation: mm-walk-cross 4s linear forwards; }
.mm-walk.is-walking .mm-walk__mark      { animation: mm-walk-lean .34s ease-in-out infinite; }

/* Once across is once across. logo-motion.js swaps the classes on animationend;
   the transform holds the mark off the right-hand edge without keeping a
   compositor animation — and the rock stops with it rather than pacing on out
   of sight for the rest of the visit. */
.mm-walk.has-walked .mm-walk__traveller { animation: none; transform: translateX(100%); }
.mm-walk.has-walked .mm-walk__mark      { animation: none; }

/* An absolutely positioned traveller paints over static inline content whatever
   its z-index, so the band's own children have to be lifted rather than the mark
   pushed down. The traveller is excluded by name — it is a child of the band
   too, and `position: relative` here would undo the absolute placement above. */
.mm-walk > *:not(.mm-walk__traveller) { position: relative; z-index: 1; }

/* The mark needs FLOOR to stand on. It is anchored to the band's bottom edge and
   stands ~0.36 of its own width tall (47px at the shipped 130px), so a band
   whose content runs to its bottom edge paints the last row straight over it and
   the device reads as a smudge behind text rather than as the mark. The footer
   bands it goes in have no bottom padding of their own — the design mock gave
   its seam band 64px expressly for this — so the placement class carries it.
   Anything using .mm-walk gets the clearance automatically, which is the point:
   the mark and the space it needs are one decision, not two.

   Both hooks are named so the selector outweighs the single-class `padding`
   shorthand on .ftB__table / .ftBS__siblings, which would otherwise zero this
   out. They are always applied together, so this costs nothing in meaning — and
   it stops the rule depending on footer.css and this sheet keeping their
   current enqueue order, which nothing enforces. */
[data-mm-walk].mm-walk { padding-bottom: 64px; }

/* Below 900px there is not enough width for the walk to read as a walk — the
   mark would cross a phone in a couple of strides and look like a rendering
   fault. The band keeps its own tone and loses the mark entirely, and gives back
   the floor space with it. A display:none traveller runs no animation, so the
   crossing costs nothing here either. */
@media (max-width: 899px) {
  .mm-walk__traveller { display: none; }
  [data-mm-walk].mm-walk { padding-bottom: 0; }
}

/* --- Device as wallpaper -------------------------------------
   The tiled field from makemy_logo_pattern(). Decoration only: it never carries
   text or meaning, so it is aria-hidden in the markup, inert to the pointer
   here, and painted at Rule strength. The block that owns the band lifts its own
   content above it — an absolutely positioned element paints over static inline
   content whatever its z-index. */
.mm-pattern {
  position: absolute; inset: 0; width: 100%; height: 100%;
  fill: var(--rule); pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .mm-reveal__line { display: none; }
  .mm-reveal__fill { fill-opacity: 1; animation: none; }
  .mm-divider__line, .mm-divider__mark { animation: none; opacity: 1; transform: none; }
  .mm-divider__line { opacity: .3; }
  /* Parked upright at the left — the same frame the mark rests on before it
     starts, and the same frame a page with no JavaScript gets. logo-motion.js
     also bails on the media query, so this is the belt to its braces. Both
     halves are named because either animation alone still moves the mark. */
  .mm-walk__traveller, .mm-walk__mark { animation: none; transform: none; }
}
