/*
  motion.css: the live mulholland.ai motion modules, re-skinned for /a
  (Mulholland lab, 2026-09-24). Pair with motion.js (one deferred script).

  Ported from website/src: site.js (behaviour), lib/components/components.css
  and tokens.css (the live timings). Behaviour, timing and choreography are
  the live ones; every colour, type size, spacing step, duration and easing
  is a token from tokens.css. Every class is mo-*, every state class mo-is-*,
  every hook data-mo-*, so nothing here collides with a.css. Link it after
  a.css.

  Colour is monochrome, as the rest of /a: everything follows the ground's
  currentColor, so each module sits on any a.css ground (.on-ink, .on-bone,
  .on-stone ...). Where the live site uses coral, /a uses the ground's full
  foreground; a page may set --mo-accent (and --mo-accent-strong for the
  rider head) on any ancestor to tint the active routes. The electric blue
  (.on-pop) is a ground like the others, with its own rules in section 12.

  Sections
   1  Module tokens (in tokens.css: --mo-*)
   2  Section frame (slice padding, heading row)
   3  Linework: fine paths, active route, riders, trace
   4  MarzyOS hero (wordmark, two paragraphs, portal linework)
   5  Closing statement with the action linework
   6  Work cycle (window, films, notes)
   7  It all comes together (three tiles, two scenes each)
   8  Record cards (receipt, session recording), plain list, steps
   9  Ontology diagram
  10  Section reveal (the live one), pause toggle
  11  Reduced motion
  12  The blue ground (.on-pop)
*/

/* 1  Module tokens --------------------------------------------------------
   Every value this file spends is a token in a/tokens.css, which each page
   links first: the semantic roles (--spacing-*, --type-*, --motion-*,
   --muted-opacity ...) and this module's own component tokens, --mo-* (the
   live timings, the rider maths, line weights, the live dimensions, the
   lines and fills derived from the ground's text colour, the monospace face
   for code and run logs). Nothing here states a colour, size or duration. */

/* 2  Section frame ------------------------------------------------------- */

/* A slice that holds one module: margins on the wrapper, 4rem air. */
.mo-section { position: relative; padding: var(--spacing-2xl) var(--page-margin); }
.mo-section__head { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--gutter); row-gap: var(--spacing-lg); align-items: start; margin-bottom: var(--spacing-2xl); }
.mo-section__title { grid-column: 1 / 7; }
.mo-section__copy { grid-column: 9 / 13; display: flex; flex-direction: column; gap: var(--type-p-size); }
@media (max-width: 767.98px) {
  .mo-section__title, .mo-section__copy { grid-column: 1 / -1; }
  .mo-section__head { margin-bottom: var(--spacing-xl); }
}

/* 3  Linework --------------------------------------------------------------
   Fine paths and one active route, full bleed, 320 tall (240 on phones).
   The live site draws the fine paths at 1px whatever the scale and the
   rider figure at its own width divided by 1.2 (its 1440 scale). */

.mo-linework { position: relative; margin: 0; overflow: hidden; color: inherit; }
.mo-linework svg { display: block; width: 100%; height: var(--mo-linework-height); }
.mo-linework path { fill: none; stroke: currentColor; stroke-width: var(--mo-stroke); vector-effect: non-scaling-stroke; }
.mo-lw-fine { opacity: var(--muted-opacity); }
.mo-linework .mo-lw-active { stroke: var(--mo-accent, currentColor); stroke-width: var(--mo-stroke-active); }
@media (max-width: 767.98px) { .mo-linework svg { height: var(--mo-linework-height-mobile); } }

/* Riders: head, trail, wall and far wall run one route together. Under
   them the route is only a ghost (live .18, here faint x dim), so the wall
   the rider leaves is what draws it. */
[data-mo-rider] .mo-lw-active, [data-mo-rider] .mo-rider { vector-effect: none; }
[data-mo-rider] .mo-lw-active { stroke-width: calc(var(--mo-stroke-active) / var(--mo-linework-scale)); opacity: calc(var(--faint-opacity) * var(--muted-opacity)); }
.mo-linework .mo-rider {
  stroke: var(--mo-accent-strong, var(--mo-accent, currentColor));
  stroke-linecap: round;
  stroke-width: calc(var(--mo-stroke-rider) / var(--mo-linework-scale));
  stroke-dasharray: var(--rider-head) calc(var(--rider-cycle) - var(--rider-head));
  stroke-dashoffset: var(--rider-start);
  animation: mo-lap calc(var(--mo-rider-lap, var(--motion-lap)) * var(--rider-cycle)) var(--motion-ease-steady) infinite;
}
.mo-linework .mo-rider--trail {
  stroke-width: calc(var(--mo-stroke-trail) / var(--mo-linework-scale));
  opacity: var(--muted-opacity);
  stroke-dasharray: var(--rider-trail) calc(var(--rider-cycle) - var(--rider-trail));
}
.mo-linework .mo-rider--wall {
  stroke: var(--mo-accent, currentColor);
  stroke-width: calc(var(--mo-stroke-active) / var(--mo-linework-scale));
  stroke-dasharray: var(--rider-wall) calc(var(--rider-cycle) - var(--rider-wall));
}
.mo-linework .mo-rider--wall-far {
  stroke: var(--mo-accent, currentColor);
  stroke-width: calc(var(--mo-stroke-active) / var(--mo-linework-scale));
  opacity: var(--muted-opacity);
  stroke-dasharray: var(--rider-wall-far) calc(var(--rider-cycle) - var(--rider-wall-far));
}
/* Off screen, in a hidden tab or paused, the cycle holds still. */
.mo-is-off .mo-rider { animation-play-state: paused; }
@keyframes mo-lap { from { stroke-dashoffset: var(--rider-start); } to { stroke-dashoffset: 1; } }

/* Trace: a linework revealed from below the fold draws its active route
   once (the live .is-visible rule). */
.mo-is-visible .mo-linework .mo-lw-active { animation: mo-trace var(--mo-reveal) var(--motion-ease-ui) both; }
@keyframes mo-trace { from { stroke-dasharray: 1; stroke-dashoffset: 1; } to { stroke-dasharray: 1; stroke-dashoffset: 0; } }

/* 4  MarzyOS hero ---------------------------------------------------------
   The wordmark across nine columns, two paragraphs under it (cols 3-6 and
   9-12, bottom-aligned), then the portal linework edge to edge. */

.mo-hero { position: relative; display: flex; flex-direction: column; gap: var(--spacing-2xl); padding: calc(var(--header-height) + var(--spacing-4xl)) 0 var(--spacing-2xl); }
.mo-hero__inner { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--gutter); row-gap: var(--spacing-2xl); padding-inline: var(--page-margin); }
.mo-hero__mark { grid-column: 1 / 10; }
.mo-hero__mark svg { display: block; width: 100%; height: auto; }
.mo-hero__under { grid-column: 1 / -1; display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--gutter); row-gap: var(--spacing-lg); align-items: end; }
.mo-hero__lead { grid-column: 3 / 7; }
.mo-hero__aside { grid-column: 9 / 13; }
@media (max-width: 767.98px) {
  .mo-hero { gap: var(--spacing-xl); padding: calc(var(--header-height) + var(--spacing-2xl)) 0 var(--spacing-xl); }
  .mo-hero__inner { row-gap: var(--spacing-xl); }
  .mo-hero__mark, .mo-hero__lead, .mo-hero__aside { grid-column: 1 / -1; }
}

/* 5  Closing statement with the action linework --------------------------- */

.mo-cta { position: relative; display: flex; flex-direction: column; gap: var(--spacing-2xl); padding: var(--spacing-3xl) 0 var(--spacing-2xl); }
.mo-cta__text { display: flex; flex-direction: column; align-items: flex-start; gap: var(--spacing-lg); padding-inline: var(--page-margin); }
@media (max-width: 767.98px) {
  .mo-cta { gap: var(--spacing-xl); padding: var(--spacing-2xl) 0 var(--spacing-xl); }
}

/* 6  Work cycle ------------------------------------------------------------
   A product window: bar (MarzyOS mark, Mulholland brain), a stage where the screens
   cross-fade (.5s) every 6s, and the notes under it, each note in one grid
   cell so the caption never shifts; the incoming note waits .25s for the
   outgoing one. */

.mo-cycle { margin: 0; display: flex; flex-direction: column; }
.mo-window { border: var(--hairline) solid var(--mo-line); }
.mo-window__bar { display: flex; justify-content: space-between; align-items: center; gap: var(--spacing-lg); padding: var(--spacing-sm) var(--spacing-lg); border-bottom: var(--hairline) solid var(--mo-line); }
.mo-window__brand { display: inline-flex; align-items: center; }
.mo-window__brand svg { display: block; width: auto; height: var(--type-label-size); }
/* The Mulholland brain at the right of the bar, where the marzy.com address was (Sam, 2026-09-25):
   the header lockup's brain paths as a 1px non-scaling line in currentColor, as tall as the wordmark.
   Its line keeps the address's type (--type-small-size, --type-small-leading), so the bar is exactly as tall as before;
   the mark hangs from the line's top, centred like the wordmark, and never grows the line. */
.mo-window__mark { font-size: var(--type-small-size); line-height: var(--type-small-leading); }
.mo-window__mark svg { display: inline-block; vertical-align: top; width: auto; height: var(--type-label-size); margin-top: calc((var(--type-small-size) * var(--type-small-leading) - var(--type-label-size)) / 2); }
.mo-cycle__stage { position: relative; display: grid; aspect-ratio: var(--aspect-screen); overflow: hidden; background: var(--fill-subtle); }
.mo-cycle__film { grid-area: 1 / 1; display: block; width: 100%; height: 100%; object-fit: cover; opacity: 0; transition: opacity var(--motion-slow) var(--motion-ease-ui); }
.mo-cycle__film.mo-is-current { opacity: 1; }
.mo-cycle__stage > picture { display: contents; } /* a responsive still: its img stays the grid item */
.mo-cycle__caption { display: grid; gap: var(--spacing-2xs); padding: var(--spacing-sm) var(--page-margin) 0; }
.mo-cycle__text { grid-area: 1 / 1; max-width: var(--mo-measure); opacity: 0; transition: opacity var(--mo-normal) var(--motion-ease-ui); }
.mo-cycle__text.mo-is-current { opacity: 1; transition-delay: var(--mo-normal); }
.mo-cycle__note { font-family: var(--type-family-code); font-size: var(--type-label-size); line-height: var(--type-code-leading); letter-spacing: var(--type-code-tracking); opacity: var(--muted-opacity); }
@media (max-width: 767.98px) {
  .mo-window__bar { padding: var(--spacing-2xs) var(--spacing-sm); }
}

/* 7  It all comes together ------------------------------------------------
   Three tiles; each stage holds two scenes in one cell. Scene one plays,
   then scene two rises (.5s, 4px) over it. Without script only scene two
   shows, complete. */

.mo-together { position: relative; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); column-gap: var(--gutter); }
.mo-together__step { min-width: 0; }
@media (min-width: 1001px) {
  .mo-together__step { display: grid; grid-template-rows: subgrid; grid-row: span 2; row-gap: 0; }
}
.mo-together__stage { position: relative; display: grid; height: 100%; min-height: var(--mo-stage-min-height); padding: var(--spacing-lg); border: var(--hairline) solid var(--mo-line); overflow: hidden; }
.mo-scene { grid-area: 1 / 1; display: flex; flex-direction: column; gap: var(--spacing-sm); min-width: 0; min-height: 0; transition: opacity var(--motion-slow) var(--motion-ease-ui), transform var(--motion-slow) var(--motion-ease-ui); }
.mo-scene[data-mo-scene="a"] { display: none; }
.mo-js .mo-scene[data-mo-scene="a"] { display: flex; }
.mo-js .mo-scene:not(.mo-is-current) { opacity: 0; transform: translateY(var(--mo-nudge)); pointer-events: none; }
.mo-scene__head { display: flex; justify-content: space-between; gap: var(--spacing-sm); margin: 0; padding-bottom: var(--spacing-2xs); border-bottom: var(--hairline) solid var(--mo-line); }
.mo-scene__head > span + span { color: var(--mo-muted-foreground); }

.mo-signal { display: inline-block; width: var(--mo-signal-size); height: var(--mo-signal-size); margin-inline-end: var(--spacing-2xs); border-radius: var(--round-radius); background: currentColor; opacity: var(--faint-opacity); vertical-align: middle; transition: opacity var(--mo-normal); }
.mo-is-on .mo-signal, .mo-is-done .mo-signal { opacity: 1; background: var(--mo-accent, currentColor); }

.mo-conn, .mo-log { flex: 1; display: flex; flex-direction: column; justify-content: space-between; }
.mo-conn li, .mo-log li { padding-block: var(--spacing-2xs); border-bottom: var(--hairline) solid var(--mo-line); }
.mo-conn li:last-child, .mo-log li:last-child { border-bottom: 0; }
.mo-conn li { display: flex; justify-content: space-between; align-items: baseline; gap: var(--spacing-sm); }
.mo-conn em { flex: none; font-style: normal; color: var(--mo-muted-foreground); transition: color var(--mo-normal); }
.mo-conn li.mo-is-on em { color: inherit; }

.mo-log { font-family: var(--type-family-mono); font-size: var(--type-label-size); line-height: var(--mo-code-leading); }
.mo-log li { display: grid; grid-template-columns: var(--mo-run-label-width) minmax(0, 1fr) auto; gap: var(--spacing-sm); }
.mo-log em { font-style: normal; opacity: var(--muted-opacity); }
.mo-log u { text-decoration: none; opacity: var(--muted-opacity); }
.mo-log li.mo-is-on u { opacity: 1; color: var(--mo-accent, currentColor); }

.mo-code { margin: 0; font-family: var(--type-family-mono); font-size: var(--type-label-size); line-height: var(--mo-code-leading); white-space: pre; overflow-x: auto; }
.mo-code__line { display: inline-block; }
.mo-code__kw { font-weight: var(--type-weight-bold); color: var(--mo-accent, currentColor); }
.mo-code__str { opacity: var(--muted-opacity); }
.mo-js .mo-code__line, .mo-js .mo-log li { opacity: 0; transform: translateX(calc(-1 * var(--mo-nudge))); transition: opacity var(--mo-normal), transform var(--mo-normal); }
.mo-js .mo-log li { transform: translateY(var(--mo-nudge)); }
.mo-js .mo-code__line.mo-is-on, .mo-js .mo-log li.mo-is-on { opacity: 1; transform: none; }

.mo-chat { display: flex; flex-direction: column; gap: var(--spacing-sm); }
.mo-chat__question { padding: var(--spacing-sm); background: var(--fill-subtle); }
.mo-chat__composer { margin-top: auto; padding: var(--spacing-sm); background: var(--fill-subtle); color: var(--mo-muted-foreground); }
.mo-post { display: flex; flex-direction: column; gap: var(--spacing-2xs); }
.mo-post__author { font-weight: var(--type-weight-medium); }
.mo-post__time { opacity: var(--muted-opacity); }

/* The caret blinks while Marzy is still answering. */
.mo-together.mo-is-typing:not(.mo-is-done) .mo-chat__answer:not(:empty)::after {
  content: ""; display: inline-block; width: var(--mo-stroke); height: var(--caret-height); margin-inline-start: var(--spacing-2xs);
  vertical-align: text-bottom; background: currentColor; animation: mo-caret var(--motion-blink) var(--motion-ease-blink) infinite;
}
.mo-together.mo-is-off .mo-chat__answer::after { animation-play-state: paused; }
@keyframes mo-caret { 50% { opacity: 0; } }

.mo-together__caption { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: var(--gutter); align-items: baseline; margin: 0; padding-top: var(--spacing-sm); }
.mo-together__caption > span:first-child { opacity: var(--muted-opacity); }

@media (max-width: 1000px) {
  .mo-together { grid-template-columns: 1fr; }
  .mo-together__stage { min-height: 0; height: auto; }
  .mo-together__step + .mo-together__step { margin-top: var(--spacing-lg); }
}
@media (max-width: 767.98px) {
  .mo-together__stage { padding: var(--spacing-lg) var(--spacing-sm); }
  .mo-together__caption { grid-template-columns: 1fr; row-gap: var(--spacing-2xs); }
}

/* 8  Record cards ---------------------------------------------------------
   A receipt or a session recording beside the record it changed: a head row
   over a hairline, then label/value rows (15rem label column). */

.mo-record { display: flex; flex-direction: column; gap: var(--spacing-lg); padding: var(--spacing-lg); border: var(--hairline) solid var(--mo-line); background: var(--fill-subtle); }
.mo-record__head { display: flex; justify-content: space-between; gap: var(--spacing-sm); margin: 0; padding-bottom: var(--spacing-sm); border-bottom: var(--hairline) solid var(--mo-line); }
.mo-record__head > span { opacity: var(--muted-opacity); text-align: right; }
.mo-record__rows { display: flex; flex-direction: column; gap: var(--spacing-2xs); }
.mo-record__rows > div { display: grid; grid-template-columns: var(--mo-record-label-width) minmax(0, 1fr); column-gap: var(--gutter); align-items: baseline; }
.mo-record__rows dt { opacity: var(--muted-opacity); }

/* Receipt: the plain list beside the card (cols 1-6 and 7-12). */
.mo-split { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--gutter); row-gap: var(--spacing-lg); align-items: start; }
.mo-split > :first-child { grid-column: 1 / 7; }
.mo-split > :last-child { grid-column: 7 / 13; }
.mo-list { display: flex; flex-direction: column; gap: var(--spacing-2xs); }
.mo-list li { padding-top: var(--spacing-2xs); border-top: var(--hairline) solid var(--mo-line); }

/* Session recording: four steps two by two, the card under them. */
.mo-steps { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--gutter); row-gap: var(--spacing-lg); margin-bottom: var(--spacing-2xl); }
.mo-step { grid-column: span 6; display: flex; flex-direction: column; gap: var(--spacing-2xs); }
.mo-step__title { font-weight: var(--type-weight-medium); }

@media (max-width: 767.98px) {
  .mo-record { padding: var(--spacing-lg) var(--spacing-sm); }
  .mo-record__rows { gap: var(--spacing-sm); }
  .mo-record__rows > div { grid-template-columns: 1fr; row-gap: var(--spacing-3xs); }
  .mo-split > :first-child, .mo-split > :last-child, .mo-step { grid-column: 1 / -1; }
  .mo-steps { margin-bottom: var(--spacing-xl); }
}

/* 9  Ontology diagram ------------------------------------------------------
   Black line art on white: multiplied onto light grounds so the white takes
   the ground; inverted and screened onto dark ones. */

.mo-ontology { margin: 0; display: flex; flex-direction: column; gap: var(--spacing-sm); }
.mo-ontology img { display: block; width: 100%; height: auto; mix-blend-mode: multiply; }
.on-ink .mo-ontology img, .on-black .mo-ontology img { filter: invert(1); mix-blend-mode: screen; }

/* 10  Section reveal and pause toggle --------------------------------------
   The live reveal: a module whose top is below the fold at load waits
   hidden 1rem low, then fades and rises over 650ms when it enters. */

.mo-js .mo-is-pending { opacity: 0; transform: translateY(var(--spacing-sm)); }
.mo-is-pending { transition: opacity var(--mo-reveal) var(--motion-ease-ui), transform var(--mo-reveal) var(--motion-ease-ui); }
.mo-is-pending.mo-is-visible { opacity: 1; transform: none; }

/* Pause/Play for anything that keeps moving; shows on keyboard focus, as the
   /a video toggle does. */
.mo-toggle {
  position: absolute; right: var(--spacing-sm); bottom: var(--spacing-sm); z-index: var(--layer-controls); padding: var(--spacing-2xs) var(--control-padding-inline);
  background: var(--overlay); color: var(--overlay-foreground);
  font-size: var(--type-label-size); line-height: var(--type-label-leading); letter-spacing: var(--type-label-tracking); font-weight: var(--type-weight-medium); text-transform: uppercase;
  opacity: 0; pointer-events: none;
}
.mo-toggle:focus-visible { opacity: 1; pointer-events: auto; outline-color: var(--foreground, var(--overlay-foreground)); }
.mo-cycle__stage > .mo-toggle:focus-visible { outline-color: var(--overlay-foreground); }
/* On the together it sits in the corner of the last tile, above the stage's
   padding, so it never covers the run's status while it plays. */
.mo-together > .mo-toggle { top: 0; right: 0; bottom: auto; }

/* 11  Reduced motion -------------------------------------------------------
   The finished state: no riders (the route shows solid), no cycling (every
   note shows), both scenes' second halves complete, nothing hidden. */

@media (prefers-reduced-motion: reduce) {
  .mo-linework .mo-rider { display: none; }
  [data-mo-rider] .mo-lw-active { opacity: 1; }
  .mo-is-visible .mo-linework .mo-lw-active { animation: none; }
  .mo-cycle__caption { display: flex; flex-direction: column; gap: var(--spacing-sm); }
  .mo-cycle__text { opacity: 1; }
  .mo-cycle__film, .mo-cycle__text, .mo-scene, .mo-code__line, .mo-log li, .mo-signal, .mo-conn em { transition: none; }
  .mo-together .mo-chat__answer::after { display: none; }
  .mo-is-pending { transition: none; }
  .mo-toggle { display: none; }
}

/* 12  The blue ground (.on-pop) --------------------------------------------
   --primary with --primary-foreground as a first-class ground for every
   module. The ground class sets the ink; these rules make each module read
   as drawn for the blue. Secondary text lifts to --primary-muted-opacity; the linework
   keeps --muted-opacity at its :root value (--mo-linework-muted-opacity). Coral or red
   on this blue vibrates (chromostereopsis), so the riders draw in
   --primary-foreground and --highlight is the one hot accent, where the live
   module uses its coral: the closing statement's reviewed route, the live
   signals, the run-log results and the code keywords. The ontology's line
   art turns white; product shots stay as they are. */

.mo-hero.on-pop, .mo-section.on-pop, .mo-cta.on-pop {
  /* --muted-opacity (.85), --mo-muted-foreground and --mo-line (25%: the hairline's weight on the
     other grounds, 1.6:1; 20% is 1.45 here) are rebound in tokens.css, and so is the linework's
     --muted-opacity (it keeps the default .6). */
  --mo-accent: var(--highlight);
}
.on-pop [data-mo-rider] { --mo-accent: var(--primary-foreground); --mo-accent-strong: var(--primary-foreground); }
/* Inverted, the diagram's grey slabs are warm off-white (lavender once
   screened on the blue); 1.15 takes them to the white of the lines. */
.on-pop .mo-ontology img { filter: invert(1) brightness(var(--mo-ontology-lift)); mix-blend-mode: screen; }
/* .mo-cta.on-pop .btn-outline keeps the blue as its ink: tokens.css rebinds --button-ink. */
