/*
 * move-motion.css: the Ummah One motion layer (Lane M, Oct 16 2026). Version 3 (after the
 * confirming seat round). Publish it under a NEW file name (move-motion.v3.css): version 2
 * sits behind an immutable URL on ummah.city. Spec: /root/handoffs/next-round-oct16/motion-M/SPEC.md.
 * Drop-in, no build step.
 *
 * Three pieces, all prefixed mm- so nothing collides with the page's own CSS:
 *   1. The move strip [data-move-motion]: five generic tools sit loose on a "before" shelf.
 *      One at a time each is picked up, carried across above the shelf, and dropped into
 *      its well in a plate under @yourname. The Held Name seal fills when the fifth lands.
 *      CSS owns the choreography; move-motion.js only starts, stops and replays it.
 *   2. Honest status labels .mm-status[data-mm-status] (word plus a shape) and status
 *      shelves [data-mm-shelf]: each shelf draws its top rule once as it scrolls in.
 *      The marks never animate: a half-drawn mark would read as a progress meter.
 *   3. A cross-document view transition: the @name text on /move carries over to the
 *      claim line on /join. Zero JavaScript (move-motion.js only switches it off when the
 *      line is off screen).
 *
 * Rules this file keeps:
 *   - The page with no CSS animation (JavaScript off, reduced motion, an old browser)
 *     is the complete, finished state. Motion only ever plays INTO that state.
 *   - Transform and opacity only in the strip. Body text never moves.
 *   - No inline style or script is needed (strict CSP safe).
 *   - Gold is the seal only. The seal never rotates (brand rule).
 */

/* ---------- tokens (Held Name, day) ---------- */
.mm-strip,
.mm-tile,
.mm-status,
[data-mm-shelf] {
  --mm-paper: #EEF1E9;
  --mm-plate: #FBFCF8;
  --mm-ink: #0F1F17;
  --mm-moss: #3F5247;
  --mm-rule: #6B7A70;
  --mm-hair: #C3CBBE;
  --mm-ghost: #9AA79E;
  --mm-tile: #166534;
  --mm-tile-hover: #0F4A26;
  --mm-tile-ink: #FFFFFF;
  --mm-lift-shadow: rgba(15, 31, 23, 0.14);
  --mm-gold: #C8912E;
  --mm-seal-edge: #0F1F17;
  --mm-ready: #0F4A26;
  --mm-later: #3F5247;
  --mm-focus: #0F4A26;
  --mm-serif: "Literata", Georgia, "Times New Roman", serif;
}

/* ---------- tokens (Held Name, night): system preference first, then the site switch ---------- */
@media (prefers-color-scheme: dark) {
  :root:not([data-umg-theme="light"]) .mm-strip,
  :root:not([data-umg-theme="light"]) .mm-tile,
  :root:not([data-umg-theme="light"]) .mm-status,
  :root:not([data-umg-theme="light"]) [data-mm-shelf] {
    --mm-paper: #060B18;
    --mm-plate: #0E1626;
    --mm-ink: #F3F1EA;
    --mm-moss: #B9C0B8;
    --mm-rule: #6F7A74;
    --mm-hair: #6F7A74;
    --mm-ghost: #6F7A74;
    --mm-tile: #F3F1EA;
    --mm-tile-hover: #DCE3DA;
    --mm-tile-ink: #0F1F17;
    --mm-lift-shadow: rgba(0, 0, 0, 0.45);
    --mm-gold: #DFA032;
    --mm-seal-edge: #F3F1EA;
    --mm-ready: #F3F1EA;
    --mm-later: #B9C0B8;
    --mm-focus: #DFA032;
  }
}
:root[data-umg-theme="dark"] .mm-strip,
:root[data-umg-theme="dark"] .mm-tile,
:root[data-umg-theme="dark"] .mm-status,
:root[data-umg-theme="dark"] [data-mm-shelf] {
  --mm-paper: #060B18;
  --mm-plate: #0E1626;
  --mm-ink: #F3F1EA;
  --mm-moss: #B9C0B8;
  --mm-rule: #6F7A74;
  --mm-hair: #6F7A74;
  --mm-ghost: #6F7A74;
  --mm-tile: #F3F1EA;
  --mm-tile-hover: #DCE3DA;
  --mm-tile-ink: #0F1F17;
  --mm-lift-shadow: rgba(0, 0, 0, 0.45);
  --mm-gold: #DFA032;
  --mm-seal-edge: #F3F1EA;
  --mm-ready: #F3F1EA;
  --mm-later: #B9C0B8;
  --mm-focus: #DFA032;
}

/* =====================================================================================
 * 1. THE MOVE STRIP
 * Geometry is fixed by these variables, so the shelf and the plate share five columns
 * and the travel of every tile is known in CSS before any script runs.
 * ===================================================================================== */
.mm-strip {
  --mm-size: 52px;          /* tile and slot, also the tap target */
  --mm-cgap: 10px;          /* column gap, shelf and plate alike */
  --mm-pad: 12px;           /* plate padding; 5 x 52 + 4 x 10 + 2 x 12 + 2 = 326px, fits a 360px phone */
  --mm-name-h: 36px;        /* the @name line */
  --mm-name-gap: 10px;
  --mm-shelf-gap: 14px;     /* shelf to plate */
  --mm-radius: 12px;
  --mm-col: calc(var(--mm-size) + var(--mm-cgap));
  --mm-drop: calc(var(--mm-size) + var(--mm-shelf-gap) + 1px + var(--mm-pad) + var(--mm-name-h) + var(--mm-name-gap));
  display: block;
  inline-size: max-content;
  max-inline-size: 100%;
  color: var(--mm-ink);
  isolation: isolate;       /* the tiles' z-index stays inside the strip: never over a sticky header */
}
@media (min-width: 600px) {
  .mm-strip {
    --mm-size: 64px;        /* 5 x 64 + 4 x 16 + 2 x 18 + 2 = 422px */
    --mm-cgap: 16px;
    --mm-pad: 18px;
    --mm-name-h: 48px;
    --mm-name-gap: 12px;
    --mm-shelf-gap: 22px;
    --mm-radius: 14px;
  }
}
@media (min-width: 1280px) {
  .mm-strip {
    --mm-size: 80px;        /* 5 x 80 + 4 x 18 + 2 x 22 + 2 = 518px */
    --mm-cgap: 18px;
    --mm-pad: 22px;
    --mm-name-h: 56px;
    --mm-name-gap: 14px;
    --mm-shelf-gap: 26px;
    --mm-radius: 16px;
  }
}
.mm-strip [hidden] { display: none !important; }   /* defect 1: never let a display rule beat [hidden] */

.mm-shelf-label {
  margin: 0 0 12px;          /* 16 + 12 = the same 28 px as before, with more air under the glyphs */
  padding-inline-start: calc(var(--mm-pad) + 1px);
  font-size: 14px;
  line-height: 16px;
  color: var(--mm-moss);
}
.mm-shelf {
  display: grid;
  grid-template-columns: repeat(5, var(--mm-size));
  column-gap: var(--mm-cgap);
  block-size: var(--mm-size);
  margin: 0 0 var(--mm-shelf-gap);
  padding: 0 0 0 calc(var(--mm-pad) + 1px);
  list-style: none;
}
.mm-ghost {
  transform-origin: 50% 0;   /* tiles and ghosts pivot on their top edge, so a lift never raises it */
  inline-size: var(--mm-size);
  block-size: var(--mm-size);
  box-sizing: border-box;
  border: 1.5px dashed var(--mm-ghost);
  border-radius: var(--mm-radius);
}
/* The shelf is loose: each place sits a little off true. These match the tiles' start poses. */
.mm-ghost:nth-child(1) { translate: 0 -2px; rotate: 4deg; }   /* calls */
.mm-ghost:nth-child(2) { translate: 0 -3px; rotate: 6deg; }   /* giving */
.mm-ghost:nth-child(3) { translate: 0 0; }                    /* email, already moved at frame 0 */
.mm-ghost:nth-child(4) { translate: 0 4px; rotate: -3deg; }   /* chat */
.mm-ghost:nth-child(5) { translate: 0 3px; rotate: -5deg; }   /* page */

.mm-plate {
  box-sizing: border-box;
  inline-size: max-content;
  max-inline-size: 100%;
  padding: var(--mm-pad);
  background: var(--mm-plate);
  border: 1px solid var(--mm-hair);
  border-radius: calc(var(--mm-radius) + 4px);
}
.mm-plate-name {
  display: flex;
  align-items: center;
  gap: 10px;
  block-size: var(--mm-name-h);
  margin: 0 0 var(--mm-name-gap);
  overflow: hidden;
  font-family: var(--mm-serif);
  font-size: 28px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.01em;
  white-space: nowrap;
  color: var(--mm-ink);
}
@media (min-width: 600px) { .mm-plate-name { font-size: 34px; gap: 12px; } }
@media (min-width: 1280px) { .mm-plate-name { font-size: 40px; gap: 14px; } }
.mm-plate-name .mm-at { font-weight: 400; color: var(--mm-moss); margin-inline-end: -0.06em; }

.mm-seal { position: relative; flex: none; inline-size: 34px; block-size: 34px; }
@media (min-width: 600px) { .mm-seal { inline-size: 40px; block-size: 40px; } }
@media (min-width: 1280px) { .mm-seal { inline-size: 46px; block-size: 46px; } }
.mm-seal > span { position: absolute; inset: 0; display: block; }
.mm-seal svg { display: block; inline-size: 100%; block-size: 100%; }
.mm-seal-o polygon { fill: none; stroke: var(--mm-rule); stroke-width: 8; stroke-linejoin: miter; }
.mm-seal-f polygon { fill: var(--mm-gold); stroke: var(--mm-seal-edge); stroke-width: 7; stroke-linejoin: miter; }

.mm-slots {
  display: grid;
  grid-template-columns: repeat(5, var(--mm-size));
  column-gap: var(--mm-cgap);
  align-items: start;
  margin: 0;
  padding: 0;
  list-style: none;
}
.mm-slot { display: grid; justify-items: center; row-gap: 6px; }
.mm-well {
  position: relative;
  inline-size: var(--mm-size);
  block-size: var(--mm-size);
  box-sizing: border-box;
  border: 1.5px dashed var(--mm-ghost);
  border-radius: var(--mm-radius);
}
.mm-slot-label {
  display: grid;
  justify-items: center;
  font-size: 14px;
  line-height: 18px;
  white-space: nowrap;
  color: var(--mm-moss);
}
.mm-slot-label .mm-status { font-size: 14px; font-weight: 500; gap: 4px; }   /* the status word on its own line under the name */
.mm-slot-label .mm-status::before { inline-size: 9px; block-size: 9px; }
.mm-vh {
  position: absolute !important;
  inline-size: 1px;
  block-size: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
/* The strip carries its own icon symbols; this hides the sprite that holds them. */
.mm-sprite { position: absolute; inline-size: 0; block-size: 0; overflow: hidden; }

/* The tile. Two layers: how the tool looks today, and how it looks moved. */
.mm-tok {
  position: absolute;
  inset: -1.5px;
  display: block;
  border-radius: var(--mm-radius);
  text-decoration: none;
  -webkit-user-drag: none;
  -webkit-tap-highlight-color: transparent;
}
.mm-tok-in, .mm-was, .mm-now { position: absolute; inset: 0; border-radius: var(--mm-radius); }
.mm-tok-in { transform-origin: 50% 0; }
/* The flat shadow a lifted tile casts (no blur, about 14% ink): seen only while carried. */
.mm-tok-in::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--mm-lift-shadow);
  translate: 0 7px;
  opacity: 0;
}
.mm-was, .mm-now { display: grid; place-items: center; box-sizing: border-box; }
.mm-was { background: var(--mm-paper); border: 1.5px solid var(--mm-rule); color: var(--mm-moss); }
.mm-now { background: var(--mm-tile); color: var(--mm-tile-ink); }
.mm-tok svg, .mm-tile svg { inline-size: 26px; block-size: 26px; display: block; fill: none; stroke: currentColor; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
@media (min-width: 600px) { .mm-tok svg { inline-size: 30px; block-size: 30px; } }
@media (min-width: 1280px) { .mm-tok svg { inline-size: 36px; block-size: 36px; stroke-width: 1.6; } }
.mm-tok:hover .mm-now { background: var(--mm-tile-hover); }
.mm-tok:focus-visible { outline: 3px solid var(--mm-focus); outline-offset: 3px; z-index: 6; }
.mm-tok:active .mm-tok-in { scale: 0.96; transition: scale 100ms cubic-bezier(.2, 0, 0, 1); }

/* The same tile, still, for the page's own lists (the five move sections). One token for
 * both, so day and night always match the strip. */
.mm-tile {
  display: grid;
  place-items: center;
  inline-size: 44px;
  block-size: 44px;
  border-radius: 10px;
  background: var(--mm-tile);
  color: var(--mm-tile-ink);
}
.mm-tile svg { inline-size: 24px; block-size: 24px; }

/* Per move: shelf column minus plate column (--mm-cols), the loose pose, when it is picked
 * up (--mm-at, from the start of the sequence) and how long the whole move takes. Email
 * is already in the plate at frame 0, so it carries no animation. */
.mm-tok[data-mm-move="page"]   { --mm-cols:  3; --mm-tilt: -5deg; --mm-jy:  3px; --mm-at:  700ms; --mm-dur: 820ms; }
.mm-tok[data-mm-move="calls"]  { --mm-cols: -2; --mm-tilt:  4deg; --mm-jy: -2px; --mm-at: 1350ms; --mm-dur: 780ms; }
.mm-tok[data-mm-move="chat"]   { --mm-cols:  0; --mm-tilt: -3deg; --mm-jy:  4px; --mm-at: 1950ms; --mm-dur: 640ms; }
.mm-tok[data-mm-move="giving"] { --mm-cols: -3; --mm-tilt:  6deg; --mm-jy: -3px; --mm-at: 2450ms; --mm-dur: 820ms; }
/* Paint order follows flight order, so the tile in the air is always above every tile
 * still waiting on the shelf (DOM order alone put the waiting ones on top). */
.mm-tok[data-mm-move="email"]  { z-index: 0; }
.mm-tok[data-mm-move="page"]   { z-index: 4; }
.mm-tok[data-mm-move="calls"]  { z-index: 3; }
.mm-tok[data-mm-move="chat"]   { z-index: 2; }
.mm-tok[data-mm-move="giving"] { z-index: 1; }

.mm-replay {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-block-size: 44px;
  margin: 2px 0 0;
  padding: 0 calc(var(--mm-pad) + 1px);
  border: 0;
  background: none;
  font: inherit;
  font-size: 14px;
  font-weight: 500;
  color: var(--mm-moss);
  cursor: pointer;
  text-decoration: underline;
  text-decoration-color: var(--mm-hair);
  text-underline-offset: 4px;
}
.mm-replay:hover { color: var(--mm-ink); text-decoration-color: currentColor; }
.mm-replay:focus-visible { outline: 3px solid var(--mm-focus); outline-offset: 2px; border-radius: 4px; }

/* The choreography. Only when the visitor has not asked for less motion AND scripting is
 * on (so a no-JS visitor gets the finished still). If move-motion.js fails to load, these
 * still play once and end in the finished state on their own.
 * Each move has three phases on one clock: pick up (lift 3 to 4 px, 12%), carry across
 * above the shelf (X runs 6% to 40%), drop into the well (36% to 100%, a critically damped
 * spring). The lift stays under the shelf label's glyphs.
 * The carry is finished before the drop is steep, so no tile slides across the name, the
 * seal or a tile that has already landed. */
@media (prefers-reduced-motion: no-preference) and (scripting: enabled) {
  .mm-strip .mm-tok:not([data-mm-move="email"]) {
    animation: mm-x calc(var(--mm-dur) * .34) cubic-bezier(.4, 0, .2, 1) calc(var(--mm-at) + var(--mm-dur) * .06) both;
  }
  .mm-strip .mm-tok:not([data-mm-move="email"]) .mm-tok-in {
    animation: mm-y var(--mm-dur) linear var(--mm-at) both;
  }
  .mm-strip .mm-tok:not([data-mm-move="email"]) .mm-tok-in::before {
    animation: mm-shadow var(--mm-dur) linear var(--mm-at) both;
  }
  .mm-strip .mm-tok:not([data-mm-move="email"]) .mm-now {
    animation: mm-ink calc(var(--mm-dur) * .34) cubic-bezier(.2, 0, 0, 1) calc(var(--mm-at) + var(--mm-dur) * .66) both;
  }
  .mm-strip .mm-seal-f {
    animation: mm-seal 300ms cubic-bezier(0, 0, .2, 1) 3600ms both;
  }
  .mm-strip .mm-tok:not([data-mm-move="email"]),
  .mm-strip .mm-tok:not([data-mm-move="email"]) .mm-tok-in { will-change: translate; }
  .mm-strip[data-mm-state="done"] .mm-tok,
  .mm-strip[data-mm-state="done"] .mm-tok-in { will-change: auto; }
  /* Keep the replay button's row reserved, so its arrival never moves the page below. */
  .mm-strip .mm-replay[hidden] { display: inline-flex !important; visibility: hidden; }
}

/* Carry: across, on the standard curve. */
@keyframes mm-x {
  from { translate: calc(var(--mm-cols) * var(--mm-col)) 0; }
  to   { translate: 0 0; }
}
/* Pick up, hold while carried, then drop on a critically damped spring (no overshoot),
 * straightening as it goes. */
@keyframes mm-y {
  0% {
    translate: 0 calc(var(--mm-jy) - var(--mm-drop));
    rotate: var(--mm-tilt);
    scale: 1;
    animation-timing-function: cubic-bezier(.2, 0, 0, 1);
  }
  12% {
    translate: 0 calc(var(--mm-jy) - var(--mm-drop) - 3px);
    rotate: calc(var(--mm-tilt) * .25);
    scale: 1.04;
    animation-timing-function: cubic-bezier(.4, 0, .6, 1);
  }
  36% {
    translate: 0 calc(0px - var(--mm-drop) - 4px);
    rotate: 0deg;
    scale: 1.04;
    animation-timing-function: linear(0, 0.114 6.2%, 0.321 12.5%, 0.516 18.8%, 0.671 25%, 0.783 31.2%, 0.86 37.5%, 0.911 43.8%, 0.944 50%, 0.966 56.2%, 0.979 62.5%, 0.987 68.8%, 0.992 75%, 0.995 81.2%, 0.997 87.5%, 0.998 93.8%, 1);
  }
  100% { translate: 0 0; rotate: 0deg; scale: 1; }
}
/* The flat shadow: there while the tile is off the ground, gone as it lands. */
@keyframes mm-shadow {
  0% { opacity: 0; }
  12% { opacity: 1; }
  60% { opacity: 1; }
  92% { opacity: 0; }
  100% { opacity: 0; }
}
/* The moved look arrives over the last third of the drop. */
@keyframes mm-ink {
  from { opacity: 0; }
  to   { opacity: 1; }
}
/* The Held Name moment, reused: the seal fills and settles. No rotation. */
@keyframes mm-seal {
  from { opacity: 0; scale: 1.18; }
  to   { opacity: 1; scale: 1; }
}

/* =====================================================================================
 * 2. HONEST STATUS LABELS AND SHELVES
 * The word is always printed. The mark is a second channel, not colour alone:
 *   Ready = filled dot, Beta = ring with a centre dot, Early access = ring,
 *   Building = broken ring. The marks never animate.
 * ===================================================================================== */
.mm-status {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.3;
  white-space: nowrap;
  color: var(--mm-ready);
}
.mm-status[data-mm-status="early"],
.mm-status[data-mm-status="building"] { color: var(--mm-later); }
.mm-status::before {
  content: "";
  flex: none;
  inline-size: 11px;
  block-size: 11px;
  box-sizing: border-box;
  border-radius: 50%;
}
.mm-status[data-mm-status="ready"]::before { background: currentColor; }
.mm-status[data-mm-status="beta"]::before {
  border: 2px solid currentColor;
  background: radial-gradient(circle, currentColor 0 1.6px, transparent 2.1px);
}
.mm-status[data-mm-status="early"]::before { border: 2px solid currentColor; }
.mm-status[data-mm-status="building"]::before {
  background: repeating-conic-gradient(currentColor 0 30deg, transparent 30deg 60deg);
  -webkit-mask: radial-gradient(circle, transparent 3.3px, #000 3.6px);
  mask: radial-gradient(circle, transparent 3.3px, #000 3.6px);
}

/* A shelf is one status group. Its top rule is drawn by this ::before; do not add another
 * border on that edge. */
[data-mm-shelf] { position: relative; }
[data-mm-shelf]::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  block-size: 0;
  border-block-start: 2px solid var(--mm-hair);
  transform-origin: 0 50%;
}
[data-mm-shelf="building"]::before { border-block-start-style: dashed; }

/* The shelf's rule is drawn left to right once as the shelf enters, driven by the visitor's
 * own scroll (so it stops when they stop). Building gets no motion: nothing completes. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    [data-mm-shelf] { view-timeline: --mm-shelf block; }
    [data-mm-shelf]:not([data-mm-shelf="building"])::before {
      animation: mm-rule linear both;
      animation-timeline: --mm-shelf;
      animation-range: entry 24px entry 240px;
    }
  }
}
@keyframes mm-rule { from { scale: 0 1; } to { scale: 1 1; } }

/* =====================================================================================
 * 3. /move to /join: the @name text carries over (cross-document view transition).
 * Both pages must load this file. Every page that loads it also gets a short root fade on
 * same-origin navigations. Exactly ONE [data-mm-name] or [data-mm-name-target] per page:
 * two cancel the transition. Chrome and Safari animate it; other browsers just navigate.
 * Reduced motion: no transition.
 * ===================================================================================== */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
}
[data-mm-name],
[data-mm-name-target] { view-transition-name: mm-held-name; }
::view-transition-group(mm-held-name) {
  animation-duration: 460ms;
  animation-timing-function: cubic-bezier(.2, 0, 0, 1);
}
/* Swap the two pictures early and fast, so the line travels as ONE line (no doubled
 * "@yourname" mid-flight). The rest of the page fades out before the new page fades in,
 * so the two headlines never overlap. */
::view-transition-old(mm-held-name) { animation: mm-vt-out 90ms cubic-bezier(.4, 0, 1, 1) both; }
::view-transition-new(mm-held-name) { animation: mm-vt-in 180ms cubic-bezier(0, 0, .2, 1) 100ms both; }
::view-transition-old(root) { animation: mm-vt-out 120ms cubic-bezier(.4, 0, 1, 1) both; }
::view-transition-new(root) { animation: mm-vt-in 180ms cubic-bezier(0, 0, .2, 1) 100ms both; }
@keyframes mm-vt-out { to { opacity: 0; } }
@keyframes mm-vt-in { from { opacity: 0; } }
