/* =============================================================================
   03-motion.css — the motion layer for "First Steps in OpenUSD"
   -----------------------------------------------------------------------------
   Owns: transitions, easings, timing tokens, disclosure clipping, marker morph,
         drawer/scrim, rail segment states, focus rings, card hover.
   Does NOT own: layout, colour palette, typography, scroll/rail measurement.

   Load order: this file MUST come AFTER the page's base <style>/stylesheet.
   Marker rules are additionally scoped under `html.motion-js` (a class added by
   03-motion.js) which raises specificity above the base sheet's
   `details[open] summary::before` rule and — deliberately — makes the whole
   glyph morph vanish if JS never runs, falling back to the base "+"/"–" text.

   No @import, no url(), no external fonts. Works from file://.
   ============================================================================= */


/* -----------------------------------------------------------------------------
   1. TIMING SYSTEM — three durations, two easings. That is the whole vocabulary.

   --mo-fast  160ms  things that only change colour/opacity/rotation in place:
                     hover, focus ring, marker morph, scrim fade.
   --mo-base  220ms  things that change state and need to be *read*: rail
                     segments, drawer scrim, default disclosure duration.
   --mo-slow  280ms  the one element that travels a long distance: the menu
                     drawer sliding 330px. Distance buys duration, nothing else.

   --mo-ease      entering / expanding / arriving. Fast out of the gate, long
                  settle. Feels like the element was already on its way.
   --mo-ease-exit leaving / collapsing. Slow start, quick finish — an exit
                  should not linger.

   JS mirror: 03-motion.js keeps numeric copies of these in Motion.T.
   If you change a number here, change it there. They are documented as a pair.
   -------------------------------------------------------------------------- */
:root{
  --mo-fast:160ms;
  --mo-base:220ms;
  --mo-slow:280ms;
  --mo-ease:cubic-bezier(.2,0,0,1);
  --mo-ease-exit:cubic-bezier(.4,0,1,1);
}


/* -----------------------------------------------------------------------------
   2. DISCLOSURE — <details>/<summary>

   The height animation itself is driven by 03-motion.js via the Web Animations
   API (see the notes file for why, and why not ::details-content). CSS here only
   provides the clipping context and the marker morph.

   `data-mo-anim` is set by JS to "open" or "close" for the duration of the
   animation and removed on settle. While it is present the element is clipped;
   the rest of the time overflow is whatever the base sheet says, so nothing
   about the static page changes.
   -------------------------------------------------------------------------- */

/* Clip only while animating. Never a permanent overflow:hidden — that would
   crop focus rings and any future popovers inside a settled disclosure. */
details[data-mo-anim]{
  overflow:hidden;
  /* height is set inline by JS; declared here so the intent is greppable */
}

/* The summary is the only always-visible part; keep it above the clipped body
   so a focus ring on it is never sliced by the animating edge. */
details[data-mo-anim] > summary{
  position:relative;
  z-index:1;
}

/* .qa is a 2-column grid, so its <details> children inherit align-self:stretch
   and are sized by the TALLEST item in the row, not by their own content. That
   breaks the collapse animation: the element animates down to its true closed
   height and then snaps back up to the stretched height on settle.
   align-self:start makes each disclosure own its height.

   NOTE TO THE LAYOUT OWNER: this is the one layout-affecting declaration in the
   motion layer, and it is required for correctness, not taste. It is scoped to
   html.motion-js so the no-JS rendering is byte-identical to today. Visible
   difference: a closed Q&A card no longer stretches to match an open sibling. */
html.motion-js .asks > details{align-self:start}

/* Pointer feedback on the summary row itself. */
html.motion-js details > summary{
  transition:background var(--mo-fast) var(--mo-ease),
             color var(--mo-fast) var(--mo-ease);
}
html.motion-js details > summary:hover{
  background:var(--wash);
}


/* -----------------------------------------------------------------------------
   3. THE +/– MARKER MORPH

   The base sheet draws the marker as literal text: summary::before {content:"+"}
   flipping to "–" on open. `content` cannot be transitioned, so it snaps.

   Replacement: two 1.7px bars drawn with pseudo-elements.
     ::before  the horizontal bar — always present, this is the "–".
     ::after   the vertical bar, absolutely positioned exactly on top of it.
               Closed: rotate(90deg) scale(1)  -> together they read "+".
               Open:   rotate(0deg)  scale(0)  -> it spins down into the "–".

   Both rules are scoped under html.motion-js so that with JS off the base sheet's
   text glyphs survive untouched.
   -------------------------------------------------------------------------- */
html.motion-js details > summary::before,
html.motion-js details[open] > summary::before{
  content:"";
  display:block;
  flex:none;
  width:.62em;
  height:1.7px;
  border-radius:1px;
  background:currentColor;
  color:var(--acc);
}

html.motion-js details > summary{
  position:relative;                     /* anchor for ::after */
}

/* The two bars only read as a "+" if they are drawn in the same place. The
   ::after is absolutely positioned at top:50%, but 02-layout.css aligns
   `.asks summary` on the BASELINE, which drops the flex-laid ::before onto the
   text baseline instead — so the cross came apart and rendered as a "T" lying
   on its side. Centre is the alignment this marker assumes; state it. */
html.motion-js .asks summary{align-items:center}

html.motion-js details > summary::after{
  content:"";
  position:absolute;
  left:.8rem;                            /* matches summary's horizontal padding */
  top:50%;
  width:.62em;
  height:1.7px;
  border-radius:1px;
  background:var(--acc);
  transform:translateY(-50%) rotate(90deg) scale(1);
  transform-origin:center;
  transition:transform var(--mo-base) var(--mo-ease);
  pointer-events:none;
}
html.motion-js details[open] > summary::after{
  transform:translateY(-50%) rotate(0deg) scale(0);
}


/* -----------------------------------------------------------------------------
   4. NO-JS PROGRESSIVE PATH (modern CSS only)

   If 03-motion.js never runs, `html.motion-js` is absent and browsers that
   support `interpolate-size` + `::details-content` still get a real animated
   disclosure. Everywhere else it simply snaps open, exactly as today.

   Scoped to html:not(.motion-js) so it can NEVER fight the JS controller —
   only one of the two is ever live.
   -------------------------------------------------------------------------- */
@supports (interpolate-size: allow-keywords) and selector(::details-content){
  html:not(.motion-js){
    interpolate-size:allow-keywords;
  }
  html:not(.motion-js) details::details-content{
    block-size:0;
    overflow:hidden;
    transition:block-size var(--mo-base) var(--mo-ease),
               content-visibility var(--mo-base) allow-discrete;
  }
  html:not(.motion-js) details[open]::details-content{
    block-size:auto;
  }
}


/* -----------------------------------------------------------------------------
   5. MENU DRAWER, SCRIM, BURGER

   The base sheet already animates these. Re-declared here only to pull them onto
   the shared tokens so the whole site shares one easing curve. Values are
   essentially the originals (.22s/.28s) rounded to the tokens.
   -------------------------------------------------------------------------- */
.scrim{
  transition:opacity var(--mo-base) var(--mo-ease);
}
.menu{
  transition:transform var(--mo-slow) var(--mo-ease);
}
/* Exit is quicker than entry — a dismissed drawer should get out of the way. */
.menu:not(.open){
  transition:transform var(--mo-base) var(--mo-ease-exit);
}
.scrim:not(.open){
  transition:opacity var(--mo-fast) var(--mo-ease-exit);
}

/* Burger → × morph. Base sheet already does this; only the timing is retuned so
   the bars finish together with the drawer's first half. */
.burger i{
  transition:transform var(--mo-base) var(--mo-ease),
             opacity var(--mo-fast) var(--mo-ease);
}
.burger{
  transition:border-color var(--mo-fast) var(--mo-ease);
}


/* -----------------------------------------------------------------------------
   6. RAIL SEGMENTS

   Each row's `transform` is rewritten by the host's paint() every scroll frame
   — it IS the scroll position, so it must NEVER be transitioned. A transition
   here makes the rows lag the page and rubber-band on a fast flick. Only the
   discrete state paint (background / colour / the 3px edge) moves.
   -------------------------------------------------------------------------- */
.seg{
  transition:background var(--mo-base) var(--mo-ease),
             color var(--mo-base) var(--mo-ease);
}
.seg::after{
  transform:scaleY(0);
  transform-origin:top;
  transition:transform var(--mo-base) var(--mo-ease),
             background var(--mo-base) var(--mo-ease);
}
.seg.done::after,
.seg.on::after{
  transform:scaleY(1);
}
/* The dot is repositioned every scroll frame by paint(); never transition it. */
.dot{transition:none}


/* -----------------------------------------------------------------------------
   7. FOCUS RINGS — the one piece of motion that must never be removed for
   aesthetics. Kept fast; outline colour/offset only, no movement.
   -------------------------------------------------------------------------- */
/* Deliberately NOT transitioned. A focus ring that fades in reads as lag to a
   keyboard user and is a known accessibility annoyance; it appears instantly in
   both motion modes. Included here so nobody "helpfully" adds a transition. */
:where(button,summary,a,input,[tabindex]):focus-visible{
  outline:2px solid var(--acc);
  outline-offset:2px;
}
summary:focus-visible{outline-offset:-2px}
.seg:focus-visible{outline-offset:-3px}


/* -----------------------------------------------------------------------------
   8. CARD / ROW HOVER — border and background only, plus a 1px lift on the two
   card grids. No shadows, no scale. Anything larger reads as a toy.
   -------------------------------------------------------------------------- */
.chapcard,.hc,.gc,.routecard{
  transition:border-color var(--mo-fast) var(--mo-ease),
             transform var(--mo-fast) var(--mo-ease),
             background var(--mo-fast) var(--mo-ease);
}
.chapcard:hover{transform:translateY(-1px)}
.chapcard:active{transform:translateY(0)}
.hc:hover{border-color:var(--rule2)}
.mrow,.cta,.resume,.endcap button,.devbar button{
  transition:background var(--mo-fast) var(--mo-ease),
             color var(--mo-fast) var(--mo-ease),
             border-color var(--mo-fast) var(--mo-ease);
}


/* =============================================================================
   9. prefers-reduced-motion: reduce
   -----------------------------------------------------------------------------
   Non-negotiable. Every duration token collapses to 1ms, which:
     - kills every transition declared above (they all read the tokens);
     - kills the ::details-content transition in the no-JS path;
     - is mirrored in JS (Motion.T.reduced) so the disclosure controller uses a
       0ms animation — the element still opens/closes and STILL DISPATCHES
       `motion:disclosure-settled`, so the host's re-measure contract is
       byte-identical in both modes.

   The blanket rule catches any transition declared elsewhere on the page
   (the base sheet, or another agent's file) without needing to enumerate them.
   1ms rather than 0 so that transitionend/animationend listeners still fire.
   ========================================================================== */
@media (prefers-reduced-motion:reduce){
  :root{
    --mo-fast:1ms;
    --mo-base:1ms;
    --mo-slow:1ms;
    --mo-ease:linear;
    --mo-ease-exit:linear;
  }
  *,*::before,*::after{
    animation-duration:1ms !important;
    animation-iteration-count:1 !important;
    transition-duration:1ms !important;
    scroll-behavior:auto !important;
  }
  /* State still reads correctly — only the travel between states is removed. */
  html.motion-js details > summary::after{transition:none}
  .chapcard:hover{transform:none}
}
