/* ==========================================================================
   story.css : the Creative Legacy scroll story
   /creative-legacy/story/ and /creative-legacy/zh/story/

   Sits on top of style.css tokens. Every selector is .cs- (creative story).

   THE ONE DECISION THAT SHAPES EVERYTHING ELSE
   There is no scroll hijacking here. No rAF-driven transform of the page
   body, no virtual scrollbar, no wheel interception. Those techniques buy a
   smoother-looking easing curve and cost the things a scroll page cannot
   afford to lose: keyboard paging, find-in-page, screen-reader cursor
   tracking, trackpad and touch momentum, and the scrollbar telling you where
   you are. Apple's own product pages do not hijack either; they use native
   scroll with sticky stages, which is exactly what this file does.

   MOTION BUDGET
   Only opacity and transform are animated. Nothing here triggers layout or
   paint on scroll. Parallax runs as a CSS scroll-driven animation where the
   browser has one, so it is off the main thread and costs no JS at all; the
   image sequence and the progress rail are the only scroll-linked work
   story.js does.

   REDUCED MOTION
   Not a degraded version: a different, complete design. Sections unpin, the
   reel becomes a legible grid of all sixteen frames, and every reveal starts
   at its finished state. Nothing is hidden, nothing has to move to be read.
   ========================================================================== */

/* ====================================================== making sticky work
   style.css sets `overflow-x: hidden` on html and body. That turns both into
   scroll containers, and a sticky element sticks to its nearest scrollport —
   which is then <body>, an element that never scrolls. So the stage silently
   does not stick: it scrolls away with the copy, computed style still reads
   "position: sticky", and every frame of the reel crossfades correctly just
   off the top of the screen. site-ux.css records the same failure killing the
   geo template's header, so this is the site's oldest trap, not a new one.

   `clip` is the fix rather than removing the rule: it still prevents sideways
   overflow, but it does not create a scroll container, and it is the one
   overflow value that pairs with `visible` on the other axis without forcing
   it to `auto`. Scoped to .cs-page so no other template changes.
   ========================================================================== */

html:has(body.cs-page),
body.cs-page { overflow-x: clip; }

.cs {
  --cs-ink: var(--text, #f8f4ee);
  --cs-dim: var(--text-dim, rgba(248, 244, 238, .68));
  --cs-mut: var(--text-muted, rgba(248, 244, 238, .46));
  --cs-gold: var(--gold, #d6ae67);
  --cs-gold-soft: var(--gold-soft, #f0d7a1);
  --cs-line: var(--line-soft, rgba(255, 255, 255, .10));

  /* One scroll unit = the distance one frame of the reel occupies. Beat
     heights are multiples of it, so a beat's copy and its frames begin and
     end on the same scroll position by construction rather than by tuning. */
  --cs-unit: 62svh;

  --cs-stage: calc(100svh - var(--ux-hdr, 80px));
  --cs-ease: cubic-bezier(.22, .61, .36, 1);
  --cs-wrap: min(1180px, 100% - 48px);
}

.cs :is(h1, h2, h3, p, ul, ol, li, figure, blockquote) { margin: 0; }

/* The header is fixed, so anything the keyboard moves focus to has to keep
   its own clearance or it arrives underneath the bar. */
.cs :is(a, button, [tabindex]) { scroll-margin-top: calc(var(--ux-hdr, 80px) + 24px); }

/* ------------------------------------------------------------------ type */

.cs-eyebrow {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--cs-gold);
}
:lang(zh) .cs-eyebrow { letter-spacing: .1em; }

/* 56px, not 78px. The h1 lives in the left column of a two-column hero, so
   its measure is about 640px at 1440, and at 78px "Twenty-five" broke at its
   own hyphen and the Scroll cue fell below the fold. Display type is sized to
   the column it sits in, not to the window. overflow-wrap is returned to
   normal because the site sets break-word globally, which lets a long word
   split anywhere rather than pushing it to the next line. */
.cs-display {
  font-size: clamp(30px, 4.4vw, 56px);
  line-height: 1.07;
  letter-spacing: -.03em;
  overflow-wrap: normal;
  text-wrap: balance;
}
:lang(zh) .cs-display { letter-spacing: -.01em; line-height: 1.18; }

.cs-h2 {
  font-size: clamp(25px, 3.1vw, 40px);
  line-height: 1.1;
  letter-spacing: -.028em;
  text-wrap: balance;
}
:lang(zh) .cs-h2 { letter-spacing: -.005em; line-height: 1.26; }

.cs-lede {
  font-size: clamp(16px, 1.55vw, 19px);
  line-height: 1.68;
  color: var(--cs-dim);
  max-width: 54ch;
}
:lang(zh) .cs-lede { line-height: 1.85; }

.cs-note {
  font-size: 14px;
  line-height: 1.7;
  color: var(--cs-mut);
  max-width: 46ch;
}
:lang(zh) .cs-note { font-size: 14.5px; line-height: 1.86; }

/* --------------------------------------------------------------- reveals
   A line reveal, not a character reveal. The text stays one intact node:
   selectable, searchable with find-in-page, and read in one piece by a
   screen reader. Splitting a heading into per-character spans buys a
   prettier stagger and breaks all three. The mask is a wrapper with
   overflow clipped; the inner span is what moves. */

.cs-line { display: block; overflow: hidden; padding-bottom: .04em; }
.cs-line > span {
  display: block;
  transform: translate3d(0, 108%, 0);
  transition: transform .82s var(--cs-ease);
}
.cs-line.is-in > span,
.cs-line:focus-within > span { transform: none; }
.cs-line:nth-of-type(2) > span { transition-delay: .07s; }
.cs-line:nth-of-type(3) > span { transition-delay: .14s; }
.cs-line:nth-of-type(4) > span { transition-delay: .21s; }

.cs-rise {
  opacity: 0;
  transform: translate3d(0, 18px, 0);
  transition: opacity .7s var(--cs-ease), transform .7s var(--cs-ease);
}
.cs-rise.is-in { opacity: 1; transform: none; }

/* A keyboard user can reach a link inside a block that has not been revealed
   yet, and an invisible focused link is a dead end. Focus completes the
   reveal immediately, for the block and for any masked line inside it. */
.cs-rise:focus-within,
.cs-rise:has(:focus-visible) { opacity: 1; transform: none; transition: none; }
.cs-rise[data-cs-delay="1"] { transition-delay: .1s; }
.cs-rise[data-cs-delay="2"] { transition-delay: .2s; }
.cs-rise[data-cs-delay="3"] { transition-delay: .3s; }

/* ------------------------------------------------------------------ hero */

.cs-hero {
  min-height: var(--cs-stage);
  display: grid;
  align-content: center;
  padding-block: calc(var(--ux-hdr, 80px) + clamp(20px, 3vw, 44px))
                 clamp(28px, 4vw, 56px);
}
.cs-hero-in { width: var(--cs-wrap); margin-inline: auto; display: grid; gap: 22px; }
.cs-hero .cs-lede { max-width: 50ch; }

.cs-hint {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-top: 10px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--cs-mut);
  text-decoration: none;
  min-height: 44px;
}
.cs-hint:hover, .cs-hint:focus-visible { color: var(--cs-gold-soft); }
.cs-hint i {
  width: 1px;
  height: 30px;
  background: linear-gradient(180deg, var(--cs-gold), transparent);
  animation: cs-hint 2.4s var(--cs-ease) infinite;
}
@keyframes cs-hint {
  0%, 100% { transform: scaleY(.4); opacity: .5; transform-origin: top; }
  50%      { transform: scaleY(1);  opacity: 1;  transform-origin: top; }
}

/* ------------------------------------------------------------------ reel
   One object, held on screen, transforming while the argument scrolls past
   it. The frame stack is sticky; the copy beats are in normal flow in the
   right-hand column. Sticky rather than fixed, so the stage releases at the
   end of its own track with no JS and no class toggling. */

.cs-reel { position: relative; }
.cs-reel-track { width: var(--cs-wrap); margin-inline: auto; position: relative; }

.cs-stage {
  position: sticky;
  top: var(--ux-hdr, 80px);
  height: var(--cs-stage);
  width: 46%;
  display: grid;
  align-content: center;
  gap: 18px;
  /* The stage is one scrolling layer of its own. Isolation keeps the frame
     crossfades from being composited against the beats above them. */
  isolation: isolate;
}

.cs-frames {
  position: relative;
  width: min(100%, 420px);
  aspect-ratio: 3 / 4;
  border-radius: var(--r-md, 16px);
  overflow: hidden;
  background: #0a0a0a;
  box-shadow: 0 40px 90px rgba(0, 0, 0, .55);
  transform: translateZ(0);
}
.cs-frames img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  /* No transition: opacity is driven per frame from the scroll position, so
     a transition here would fight the input and lag behind the finger. The
     crossfade IS the scroll position. */
}
.cs-frames img:first-child { opacity: 1; }

/* A thin gold rule that fills as the reel is read: the only thing telling a
   reader how much of a pinned section is left. Driven from story.js, because
   no view-timeline range lines up with a sticky pin span. */
.cs-rail {
  position: relative;
  width: min(100%, 420px);
  height: 2px;
  background: var(--cs-line);
  border-radius: 2px;
  overflow: hidden;
}
.cs-rail i {
  position: absolute;
  inset: 0;
  transform-origin: left;
  transform: scaleX(0);
  background: linear-gradient(90deg, var(--cs-gold), var(--cs-gold-soft));
}

/* The style caption. Its text is written by story.js, so it is aria-hidden
   and the same information is in each beat's own copy for anyone not
   watching pictures. */
.cs-caption {
  display: flex;
  align-items: baseline;
  gap: 10px;
  width: min(100%, 420px);
  min-height: 20px;
  font-size: 12.5px;
  letter-spacing: .02em;
  color: var(--cs-mut);
}
.cs-caption b { color: var(--cs-ink); font-weight: 600; }
.cs-caption span { margin-left: auto; font-variant-numeric: tabular-nums; }

/* -------------------------------------------------------------- the beats
   Height is frames x unit, so beat boundaries and frame boundaries are the
   same positions. --cs-n is set per beat in the markup. */

.cs-beat {
  position: relative;
  z-index: 1;
  margin-left: 52%;
  min-height: calc(var(--cs-n, 3) * var(--cs-unit));
  display: grid;
  align-content: center;
  gap: 20px;
  padding-block: 8vh;
}
.cs-beat-tag {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--cs-gold);
}
.cs-beat-tag u {
  width: 22px;
  height: 1px;
  background: currentColor;
  text-decoration: none;
}
:lang(zh) .cs-beat-tag { letter-spacing: .08em; }

.cs-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  list-style: none;
  padding: 0;
}
.cs-strip li {
  font-size: 12px;
  letter-spacing: .02em;
  color: var(--cs-dim);
  border: 1px solid var(--cs-line);
  border-radius: 999px;
  padding: 7px 13px;
}
.cs-strip b { color: var(--cs-ink); font-weight: 600; }

.cs-fact {
  border-left: 2px solid rgba(214, 174, 103, .4);
  padding-left: 18px;
  font-size: 14.5px;
  line-height: 1.72;
  color: var(--cs-dim);
  max-width: 48ch;
}
:lang(zh) .cs-fact { line-height: 1.88; }
.cs-fact b { color: var(--cs-ink); font-weight: 600; }

/* ---------------------------------------------------------------- thesis */

.cs-thesis {
  min-height: 86svh;
  display: grid;
  align-content: center;
  padding-block: 12vh;
  border-block: 1px solid var(--cs-line);
  background:
    radial-gradient(120% 90% at 50% 0%, rgba(214, 174, 103, .07), transparent 62%);
}
.cs-thesis-in { width: min(900px, 100% - 48px); margin-inline: auto; display: grid; gap: 26px; }
.cs-thesis blockquote {
  font-size: clamp(24px, 3.2vw, 40px);
  line-height: 1.22;
  letter-spacing: -.026em;
  text-wrap: balance;
}
:lang(zh) .cs-thesis blockquote { line-height: 1.38; letter-spacing: 0; }
.cs-thesis cite {
  font-style: normal;
  font-size: 13px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--cs-mut);
}

/* -------------------------------------------------------------- timeline */

.cs-arc { padding-block: clamp(64px, 9vw, 120px); }
.cs-arc-in { width: var(--cs-wrap); margin-inline: auto; display: grid; gap: 44px; }
.cs-arc ol {
  list-style: none;
  padding: 0;
  display: grid;
  gap: 1px;
  background: var(--cs-line);
  border-block: 1px solid var(--cs-line);
}
.cs-arc li {
  background: #050505;
  display: grid;
  grid-template-columns: 116px minmax(0, 1fr) minmax(0, 1.5fr);
  gap: 24px;
  align-items: baseline;
  padding: 26px 4px;
}
.cs-arc dt, .cs-arc h3 {
  font-size: 16.5px;
  font-weight: 700;
  letter-spacing: -.012em;
  color: var(--cs-ink);
}
.cs-arc .cs-when {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--cs-gold);
}
.cs-arc p { font-size: 14.5px; line-height: 1.68; color: var(--cs-dim); }

/* ------------------------------------------------------------------- cta */

.cs-cta { padding-block: clamp(56px, 8vw, 104px); background: var(--bg-lift, #0b0b0b); }
.cs-cta-in {
  width: var(--cs-wrap);
  margin-inline: auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 40px;
  align-items: center;
}
.cs-cta-btns { display: flex; flex-wrap: wrap; gap: 12px; }

/* ------------------------------------------------- the reduce-motion pill
   The OS setting is honoured without this control. It exists because a
   person can want a still page on a machine they do not administer, or on a
   borrowed one, which is common in the rooms this page gets opened in. */

/* Position is dictated by what is already parked in that corner: site-ux.css
   puts the back-to-top button at right 18px / bottom 88px (44px square), and
   style.css puts the WhatsApp FAB at right 24px / bottom 24px below 980px. So
   on a desktop this sits immediately left of back-to-top and level with it,
   and on a phone it moves to the opposite corner rather than joining a stack
   of three floating buttons. */
.cs-motion {
  position: fixed;
  right: calc(18px + 44px + 14px);
  bottom: calc(env(safe-area-inset-bottom, 0px) + 88px);
  z-index: 54;
  height: 44px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 0 14px;
  font: inherit;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .04em;
  color: var(--cs-dim);
  background: rgba(14, 14, 14, .82);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border: 1px solid var(--cs-line);
  border-radius: 999px;
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transition: opacity .3s var(--cs-ease), color .2s ease, border-color .2s ease;
}
.cs-motion.is-on { opacity: 1; pointer-events: auto; }
.cs-motion:hover, .cs-motion:focus-visible {
  color: var(--cs-ink);
  border-color: rgba(214, 174, 103, .45);
}
.cs-motion i {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--cs-gold); flex: 0 0 auto;
}
.cs-still .cs-motion i { background: var(--cs-mut); }

/* ---------------------------------------------------------------- crumbs */

.cs-crumbs {
  font-size: 13px;
  color: var(--cs-mut);
  margin-bottom: 4px;
}
.cs-crumbs a { color: var(--cs-gold-soft); text-decoration: none; }
.cs-crumbs a:hover, .cs-crumbs a:focus-visible { text-decoration: underline; }

/* ------------------------------------------------------------- hero layout
   Two columns above 1024px: the argument on the left, the same glass-acrylic
   plate the Creative Legacy essay page opens with on the right, so arriving
   from that page feels like the next room rather than a different building.
   The art is aria-hidden and sized to 0px below the breakpoint, so a phone
   never downloads it. */

.cs-hero-in { align-items: center; }
.cs-hero-copy { display: grid; gap: 20px; }

.cs-hero-art { margin: 0; line-height: 0; }
.cs-hero-art img {
  width: 100%;
  height: auto;
  border-radius: var(--r-md, 16px);
}

@media (min-width: 1024px) {
  .cs-hero-in {
    grid-template-columns: minmax(0, 1fr) minmax(0, .76fr);
    gap: clamp(32px, 5vw, 76px);
  }
}
@media (max-width: 1023px) {
  .cs-hero-art { display: none; }
}

/* -------------------------------------------------------- thesis backdrop
   A zero-weight parallax layer. Nothing is downloaded for it, so the depth
   cue costs no bytes and nothing breaks when the drift does not run. */

.cs-thesis { position: relative; overflow: hidden; isolation: isolate; }
.cs-thesis-glow {
  position: absolute;
  inset: -12% -10%;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(42% 46% at 22% 30%, rgba(214, 174, 103, .14), transparent 70%),
    radial-gradient(38% 40% at 78% 72%, rgba(214, 174, 103, .09), transparent 72%);
}
.cs-thesis-in { position: relative; z-index: 1; }
.cs-thesis cite { display: block; }

/* CTA buttons inherit .btn from style.css; only the row needs saying. */
.cs-cta-btns .btn { flex: 0 1 auto; }

@media (max-width: 600px) {
  .cs-cta-btns { display: grid; }
  .cs-cta-btns .btn { width: 100%; justify-content: center; }
}

/* ======================================================= scroll timelines
   Where the browser has scroll-driven animations, the continuous work runs
   on the compositor and story.js never touches these elements. Where it does
   not, they simply sit at their static state: the rail stays empty and the
   parallax layers do not drift. Neither loss changes what the page says,
   which is the test for whether an effect belongs in this block. */

@supports (animation-timeline: view()) {
  /* Parallax, capped at 26px of travel over a whole viewport of scroll.
     Anything more reads as a slide deck rather than depth, and on a trackpad
     it is the first thing that makes a page feel cheap.

     Only non-sticky subjects get a view timeline. A sticky element's view
     progress is defined against its stuck position, which makes the range
     you actually want unexpressible, so the reel's own progress is measured
     in story.js instead of fought for here. */
  .cs-para {
    animation: cs-drift linear both;
    animation-timeline: view();
    animation-range: entry 0% exit 100%;
  }
  @keyframes cs-drift {
    from { transform: translate3d(0, 26px, 0); }
    to   { transform: translate3d(0, -26px, 0); }
  }
}

/* ===================================================== responsive layout */

/* Below 1023px there is no second column to put the copy in, so the copy has
   to pass behind the pinned frame. Two things make that readable rather than a
   collision, and the first version of this file got both wrong:

   1. The stage must paint ABOVE the beats. .cs-beat carries z-index 1 for the
      desktop layout, so without a higher z-index here the copy scrolled over
      the picture and the caption, which is exactly what it looked like.
   2. The frame has to get much smaller. A 300px-wide portrait plus rail and
      caption eats 380px of an 844px phone, and a beat of this length does not
      fit in what is left. At 160px the stage costs about 230px and the copy
      keeps two thirds of the screen.

   The scrim is opaque for most of the stage and fades at its bottom edge, so
   lines arrive from below rather than being clipped by a hard line. */
@media (max-width: 1023px) {
  .cs { --cs-unit: 58svh; }
  .cs-stage {
    width: 100%;
    height: auto;
    top: var(--ux-hdr, 80px);
    z-index: 3;
    display: grid;
    grid-template-columns: 160px minmax(0, 1fr);
    grid-template-areas: "frame rail" "frame cap";
    align-content: start;
    justify-items: stretch;
    gap: 10px 16px;
    padding: 14px 0 20px;
    background: linear-gradient(180deg,
      #050505 0%, #050505 84%, rgba(5, 5, 5, .86) 94%, rgba(5, 5, 5, 0) 100%);
  }
  .cs-frames { grid-area: frame; width: 160px; box-shadow: 0 18px 40px rgba(0,0,0,.5); }
  .cs-rail { grid-area: rail; width: 100%; align-self: end; }
  .cs-caption { grid-area: cap; width: 100%; align-self: start; display: block; }
  .cs-caption b { display: block; }
  .cs-caption span { display: block; margin: 2px 0 0; }
  .cs-beat { margin-left: 0; z-index: 1; padding-block: 5vh 9vh; }
  .cs-arc li { grid-template-columns: 1fr; gap: 8px; padding: 22px 4px; }
  .cs-cta-in { grid-template-columns: 1fr; gap: 26px; }
}

@media (max-width: 600px) {
  .cs { --cs-unit: 54svh; }
  .cs-stage { grid-template-columns: 132px minmax(0, 1fr); }
  .cs-frames { width: 132px; }
  /* The right-hand corner already holds the WhatsApp FAB and back-to-top. */
  .cs-motion {
    left: max(14px, env(safe-area-inset-left, 0px));
    right: auto;
    bottom: calc(env(safe-area-inset-bottom, 0px) + 24px);
  }
}

/* Short viewports: a pinned stage taller than the window is a trap, and a
   laptop in a meeting room is often 640px tall with a browser bar. */
@media (max-height: 700px) and (min-width: 1024px) {
  .cs-frames { width: min(100%, 320px); }
  .cs { --cs-unit: 76svh; }
}

/* ================================================== reduced motion / still
   Driven by the OS setting or by .cs-still on <html> from the pill. Both
   paths land on the same design: unpinned, complete, still. */

@media (prefers-reduced-motion: reduce) {
  .cs-still-src { display: revert; }
}

.cs-still .cs-line > span,
.cs-still .cs-rise { transform: none; opacity: 1; transition: none; }
.cs-still .cs-hint i { animation: none; transform: none; opacity: .8; }
.cs-still .cs-para { animation: none; transform: none; }
.cs-still .cs-frames { animation: none; transform: none; box-shadow: none; }

/* The reel stops being a reel. It becomes what it always was underneath: a
   contact sheet of sixteen treatments of one photograph, with the same copy
   beside it in a normal column. Nothing moves and nothing is hidden. */
.cs-still .cs-stage {
  position: static;
  width: 100%;
  height: auto;
  background: none;
  padding-bottom: 0;
  justify-items: start;
}
.cs-still .cs-frames {
  width: 100%;
  aspect-ratio: auto;
  overflow: visible;
  border-radius: 0;
  background: none;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(116px, 1fr));
  gap: 10px;
}
.cs-still .cs-frames img {
  position: static;
  opacity: 1;
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 4;
  border-radius: 10px;
}
.cs-still .cs-rail, .cs-still .cs-caption { display: none; }
.cs-still .cs-beat {
  margin-left: 0;
  min-height: 0;
  padding-block: clamp(28px, 5vw, 52px);
  border-top: 1px solid var(--cs-line);
}
.cs-still .cs-hero, .cs-still .cs-thesis { min-height: 0; }
.cs-still .cs-reel-track { display: grid; gap: 8px; }

/* ================================================================ no JS
   story.js adds .cs-js to <html> as its first act. Without it the reel
   cannot crossfade, so it does not pretend to: the same still contact-sheet
   layout is used, built from the five frames that carry a real src. */

html:not(.cs-js) .cs-stage {
  position: static; width: 100%; height: auto; background: none; justify-items: start;
}
/* The reel cannot crossfade without script, so it is not shown at all: only
   frame 0 has a real src, and fifteen empty boxes are worse than none. The
   <noscript> contact sheet below takes its place, which means a reader with
   script enabled never downloads it. */
html:not(.cs-js) .cs-frames { display: none; }
.cs-sheet { display: flex; flex-wrap: wrap; gap: 10px; }
.cs-sheet img { width: 132px; height: auto; aspect-ratio: 3 / 4; border-radius: 10px; }
html:not(.cs-js) .cs-rail,
html:not(.cs-js) .cs-caption,
html:not(.cs-js) .cs-motion { display: none; }
html:not(.cs-js) .cs-beat { margin-left: 0; min-height: 0; padding-block: 42px; }
html:not(.cs-js) .cs-line > span,
html:not(.cs-js) .cs-rise { transform: none; opacity: 1; }

/* ============================================== contrast and forced colors */

@media (prefers-contrast: more) {
  .cs { --cs-dim: rgba(248, 244, 238, .86); --cs-mut: rgba(248, 244, 238, .72); }
  .cs-strip li { border-color: rgba(255, 255, 255, .3); }
}
@media (forced-colors: active) {
  .cs-line > span, .cs-rise { transform: none; opacity: 1; }
  .cs-frames img { opacity: 1; }
  .cs-strip li, .cs-motion { border: 1px solid ButtonText; }
}

/* Print: the argument, not the pictures. */
@media print {
  .cs-stage, .cs-motion, .cs-hint { display: none !important; }
  .cs-beat { margin-left: 0; min-height: 0; padding-block: 16px; }
  .cs-hero, .cs-thesis { min-height: 0; }
  .cs-line > span, .cs-rise { transform: none; opacity: 1; }
}
