/* ===========================================================================
   maddynf - dusk plum, set as an editorial page.

   COLOUR. Starts from her own branding rather than being invented: the
   indigo-to-plum wash and the magenta wordmark are off her Twitch banner,
   the lilac descends from the primary colour Twitch stores on her channel
   (#FAB3FF), and the cream is the skin-tone paper of her avatar. All of it
   is turned down from there - a banner is looked at for two seconds and a
   page is sat on - so the ground is a muted plum rather than a saturated
   indigo, the magenta relaxes into an orchid light enough to carry dark ink,
   and the wash and the shadows are about half the strength they started at.
   Nothing glows.

   LAYOUT. No cards. There is not a single border-plus-fill container on the
   page: separation is done with hairline rules, whitespace and type size,
   the way a magazine does it. Sections are numbered chapters in one column,
   images sit on the page rather than inside frames, and lists are rows split
   by rules. The only filled shapes are the buttons, the player, and the
   thumbnails themselves.

   Single theme, every colour painted explicitly. No prefers-color-scheme:
   there is nothing to switch to.
   =========================================================================== */

:root{
  --night:   #211B33;   /* the page */
  --deep:    #2A2340;   /* a step up, for the player and thumbnail backings */
  --raised:  #362E4C;

  /* Rules come in two weights: a hairline between rows, and a slightly
     stronger one between chapters. */
  --rule:      #362E4C;
  --rule-firm: #453B60;

  --magenta: #CE8FDF;
  --lilac:   #E6C6F0;
  --cream:   #FFE4C7;
  --live:    #FF8AA6;

  --ink:   #F2EAF8;
  --muted: #C3B6D6;
  --dim:   #9C90B2;

  /* One family throughout; headings, body and the small labels are told
     apart by weight, size and tracking rather than by typeface. */
  --display: "Plus Jakarta Sans", "Segoe UI", system-ui, sans-serif;
  --body:    "Plus Jakarta Sans", "Segoe UI", system-ui, sans-serif;
  --label:   "Plus Jakarta Sans", "Segoe UI", system-ui, sans-serif;
  /* Only the masthead lockup: the drawn M and the cover wordmark are
     outlined from Poppins, so the live text beside the mark has to match. */
  --brand:   "Poppins", "Segoe UI", system-ui, sans-serif;

  --wrap:   1120px;
  --gutter: 28px;
  --r:      14px;      /* only ever on images and the player */
}

*,*::before,*::after{ box-sizing:border-box; }

html{ scroll-behavior:smooth; scroll-padding-top:5rem; }

body{
  margin:0;
  background:var(--night);
  color:var(--ink);
  font-family:var(--body);
  font-size:1.0625rem;
  line-height:1.65;
  -webkit-font-smoothing:antialiased;
}

/* Her banner's wash, rebuilt in CSS and turned right down. Fixed, so it sits
   behind the whole scroll rather than repeating per section. */
body::before{
  content:"";
  position:fixed; inset:0; z-index:0;
  background:
    radial-gradient(58% 46% at 90% 0%, rgba(206,143,223,.11), transparent 70%),
    radial-gradient(50% 42% at 2% 1%,  rgba(132,108,190,.12), transparent 72%);
  pointer-events:none;
}
body > *{ position:relative; z-index:1; }

::selection{ background:var(--magenta); color:var(--night); }

a{ color:inherit; }
h1,h2,h3{ font-family:var(--display); font-weight:600; letter-spacing:-.03em; text-wrap:balance; margin:0; }
p{ margin:0; }
em{ font-style:normal; color:var(--lilac); }

.mono{ font-family:var(--label); font-size:.76rem; letter-spacing:.02em; }

.skip{
  position:absolute; left:-9999px; top:0; z-index:99;
  background:var(--magenta); color:var(--night); padding:.6rem 1rem;
  font-weight:600; text-decoration:none;
}
.skip:focus{ left:0; }

:focus-visible{ outline:2px solid var(--lilac); outline-offset:3px; border-radius:4px; }


.eyebrow{
  font-family:var(--label); font-size:.68rem; font-weight:500;
  text-transform:uppercase; letter-spacing:.18em; color:var(--lilac);
  margin-bottom:1rem;
}

/* Her own sub emotes, dotted through the headings. Sized in em so they ride
   the line they sit on rather than fighting it. */
.emote{ height:1.15em; width:auto; max-width:100%; vertical-align:-.2em; margin-left:.18em; }

/* Screen-reader-only. */
.vh{ position:absolute; width:1px; height:1px; overflow:hidden; clip-path:inset(50%); white-space:nowrap; }

/* -- buttons -----------------------------------------------------------------
   The only filled shapes on the page besides the media itself. */
.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:.55rem;
  padding:.68rem 1.35rem; border-radius:999px;
  font-family:var(--body); font-size:.92rem; font-weight:600;
  text-decoration:none; white-space:nowrap;
  border:1px solid transparent;
  transition:transform .18s ease, background .18s ease, border-color .18s ease, color .18s ease;
}
button.btn{ cursor:pointer; }
.btn--solid{ background:var(--magenta); color:var(--night); }
.btn--solid:hover{ background:#DEA8EC; transform:translateY(-1px); }
/* Not a button so much as a link with a target area - no fill at all. */
.btn--quiet{ background:none; color:var(--muted); padding-inline:.4rem; }
.btn--quiet:hover{ color:var(--lilac); }
.btn__icon{ width:15px; height:15px; fill:currentColor; }

.linkbtn{
  background:none; border:0; padding:0; cursor:pointer;
  font-family:var(--label); font-size:.74rem;
  color:var(--lilac); text-decoration:none; white-space:nowrap;
  transition:color .18s ease;
}
.linkbtn:hover{ color:var(--magenta); }

/* -- masthead -----------------------------------------------------------------
   A rule across the top, not a bar: transparent-ish, one hairline underneath,
   nothing boxed inside it. */
.masthead{
  position:sticky; top:0; z-index:20;
  background:rgba(33,27,51,.88);
  backdrop-filter:blur(14px);
  border-bottom:1px solid var(--rule);
}
.masthead__in{
  max-width:var(--wrap); margin-inline:auto;
  padding:.7rem var(--gutter);
  display:flex; align-items:center; gap:1.6rem;
}
.brand{ display:flex; align-items:center; gap:.6rem; text-decoration:none; }
.brand__avatar{
  width:34px; height:34px; flex:none; border-radius:50%; object-fit:cover;
  box-shadow:0 0 0 1.5px var(--magenta);
}
/* The lockup. Every measurement here is the banner's, taken off the artwork:
   the mark stands 1.118x the height of the d's ascender, overshoots the
   baseline the way a round shape has to, and is set off the a by .04em -
   with the a's own side bearing that is the same gap as between two
   letters, so the M reads as part of the word. All of it in em, so the mark tracks the type at any size
   and the two never come apart. The -.03em is the banner's tracking too -
   Poppins sets "addynf" about 4% wide of it. */
.brand__name{
  font-family:var(--brand); font-weight:600; font-size:1.05rem;
  letter-spacing:-.03em; color:var(--ink);
}
.brand__name b{ color:var(--magenta); }
.brand__mark{
  height:.838em; width:auto;
  vertical-align:-.019em;
  margin-right:.04em;
  fill:var(--magenta);
}

.masthead__nav{ display:flex; gap:1.5rem; margin-left:auto; }
.masthead__nav a{
  white-space:nowrap; text-decoration:none; color:var(--muted); font-size:.92rem; font-weight:500;
  padding-block:.25rem; border-bottom:1.5px solid transparent;
  transition:color .18s ease, border-color .18s ease;
}
.masthead__nav a:hover{ color:var(--ink); }
.masthead__nav a[aria-current="page"]{ color:var(--ink); border-bottom-color:var(--magenta); }

.pill{
  display:inline-flex; align-items:center; gap:.45rem;
  font-family:var(--label); font-size:.64rem;
  text-transform:uppercase; letter-spacing:.14em; color:var(--dim);
}
.pill__dot{ width:6px; height:6px; border-radius:50%; background:var(--dim); flex:none; }
.pill.is-live{ color:var(--live); }
.pill.is-live .pill__dot{ background:var(--live); animation:pulse 1.9s ease-in-out infinite; }
@keyframes pulse{ 0%,100%{ opacity:1; transform:scale(1);} 50%{ opacity:.3; transform:scale(.7);} }

/* -- the column ---------------------------------------------------------------- */
.view{ max-width:var(--wrap); margin-inline:auto; padding-inline:var(--gutter); }

/* -- opening spread -------------------------------------------------------------- */
.lede{ position:relative; padding-block:5.5rem 0; }
.lede--short{ padding-block:4.5rem 0; }
.lede__title{
  font-size:clamp(2.4rem,6vw,4.1rem); line-height:1.04;
  letter-spacing:-.045em; font-weight:700; max-width:18ch;
}
.lede__text{ color:var(--muted); font-size:1.15rem; max-width:44ch; margin-top:1.4rem; }
/* One quiet line for her second channel - there, not competing. */
.lede__also{ color:var(--dim); font-size:.9rem; margin-top:.9rem; }
.lede__also a{ color:var(--muted); }
.lede__also a:hover{ color:var(--lilac); }

/* Her name on the cover, written on left to right as the page opens, then
   caught by a glint every few seconds - the opening sommerset.walju.net
   has. The write-on is a soft-edged mask slid across the mark; the glint is
   a band of light cut to the letters by assets/wordmark.svg, so it never
   paints the space around them. */
.lede__name{
  position:relative; width:min(100%,560px); margin:0 0 1.6rem;
  filter:drop-shadow(0 6px 22px rgba(206,143,223,.22));
}
.lede__wordmark{
  display:block; width:100%; height:auto; overflow:visible;
  -webkit-mask-image:linear-gradient(90deg,#000 40%,transparent 60%);
          mask-image:linear-gradient(90deg,#000 40%,transparent 60%);
  -webkit-mask-size:300% 100%; mask-size:300% 100%;
  -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
  animation:wordmark-write 1.8s cubic-bezier(.45,.05,.3,1) .15s both;
}
.lede__wordmark-m{ fill:var(--magenta); }
.lede__wordmark-word{ fill:var(--ink); }
.lede__name::after{
  content:""; position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(105deg,
    transparent 38%, rgba(255,240,255,.35) 46%, rgba(255,255,255,.75) 50%,
    rgba(255,240,255,.35) 54%, transparent 62%) no-repeat;
  background-size:250% 100%; background-position:160% 0;
  -webkit-mask:url(wordmark.svg) center / 100% 100% no-repeat;
          mask:url(wordmark.svg) center / 100% 100% no-repeat;
  animation:wordmark-glint 6s ease-in-out 2.1s infinite;
}
@keyframes wordmark-write{
  from{ -webkit-mask-position:100% 0; mask-position:100% 0; transform:translateY(6px); }
  to{   -webkit-mask-position:0 0;    mask-position:0 0;    transform:none; }
}
/* One sweep at the start of each cycle, then a long rest. */
@keyframes wordmark-glint{
  0%      { background-position:160% 0; }
  22%,100%{ background-position:-60% 0; }
}
/* With the name above it, the old headline becomes the line under the name. */
.lede__title--sub{ font-size:clamp(1.6rem,3.6vw,2.5rem); max-width:22ch; }
@media (prefers-reduced-motion:reduce){
  .lede__wordmark{ animation:none; -webkit-mask-image:none; mask-image:none; }
  .lede__name::after{ animation:none; display:none; }
}
.lede__actions{ display:flex; align-items:center; gap:1.2rem; flex-wrap:wrap; margin-top:2.2rem; }
.lede__count{ color:var(--dim); margin-top:1.4rem; }

/* Her profile picture, parked in the top corner of the opening spread.
   Absolute, so it never pushes the type around - the headline keeps its own
   measure and the picture fills the space the headline does not want.

   Round with a hairline ring, the same treatment it gets at 34px in the
   masthead: it is a profile picture, and a profile picture is a circle. The
   ring is the one place the saturated end of the palette is still allowed,
   because the artwork's own background is a violet that would otherwise
   dissolve into the page. */
.lede__portrait{
  position:absolute; right:0; top:4.2rem;
  width:clamp(150px,19vw,236px); height:auto;
  border-radius:50%;
  box-shadow:0 0 0 2px var(--magenta), 0 18px 40px rgba(0,0,0,.35);
  transition:transform .3s ease;
}

/* Clicking her throws emotes across the page. Nothing says so, which is the
   point, so the only tells are the cursor and the lift. */
.is-throwable{ cursor:pointer; transition:transform .3s ease; }
.is-throwable:hover{ transform:translateY(-4px) scale(1.02); }
.is-throwable:active{ transform:translateY(-1px) scale(.99); }

/* -- marginalia ------------------------------------------------------------------
   Her emotes out beside the column, in the white space a wide screen leaves
   over. Turned down to half strength and set behind the text's stacking
   order: this is the page's wallpaper, not its illustration, and it has to
   lose every argument it has with a word.

   The margin only exists past 1400px - 1120 of column plus a hand's width
   either side - so below that they are not drawn at all rather than crowded
   in. app.js sets the angle, the drop and the phase per emote. */
.marginal{ display:none; }

@media (min-width:1400px){
  .marginal{
    display:block;
    position:absolute; top:var(--top,5rem);
    width:84px; height:84px;
    opacity:.5;
    transform:rotate(var(--rot,0deg));
    animation:drift 7s ease-in-out infinite;
    animation-delay:var(--delay,0s);
    pointer-events:none;
    z-index:0;
  }
  .marginal[data-side="right"]{ right:-116px; }
  .marginal[data-side="left"]{  left:-116px; }
}
@keyframes drift{
  0%,100%{ transform:rotate(var(--rot,0deg)) translateY(0); }
  50%    { transform:rotate(var(--rot,0deg)) translateY(-9px); }
}

/* -- the burst -------------------------------------------------------------------
   Thrown from the mascot on click. Fixed rather than absolute so they fly
   over the page instead of stretching it, and removed on animationend, so
   nothing accumulates however many times he is poked. */
.burst{
  position:fixed; z-index:40;
  width:54px; height:54px;
  pointer-events:none;
  animation:burst .9s cubic-bezier(.2,.7,.3,1) forwards;
}
@keyframes burst{
  0%  { transform:translate(0,0) rotate(0deg) scale(.4); opacity:0; }
  15% { opacity:1; }
  /* Held a moment at full reach before it goes, so the eye can land on one. */
  70% { transform:translate(var(--dx),var(--dy)) rotate(var(--spin)) scale(1); opacity:1; }
  100%{ transform:translate(var(--dx),calc(var(--dy) + 40px)) rotate(var(--spin)) scale(.9); opacity:0; }
}

/* -- the three numbers -----------------------------------------------------------
   A rule above, wide gaps, nothing boxed. */
.stats{
  display:flex; gap:clamp(2rem,6vw,5rem); flex-wrap:wrap;
  margin:3.5rem 0 0; padding-top:1.8rem;
  border-top:1px solid var(--rule-firm);
}
.stats div{ display:flex; flex-direction:column; gap:.2rem; }
.stats dd{
  margin:0; order:1;
  font-family:var(--display); font-weight:700;
  font-size:clamp(1.7rem,3.4vw,2.3rem);
  letter-spacing:-.04em; font-variant-numeric:tabular-nums; line-height:1.1;
}
.stats dt{
  order:2; font-family:var(--label); font-size:.66rem;
  text-transform:uppercase; letter-spacing:.14em; color:var(--dim);
}
/* Only ever on a number that really is hand-maintained; the live check
   deletes it the moment it answers. */
.stats__asof{ opacity:.7; text-transform:none; letter-spacing:.04em; }

/* -- chapters ---------------------------------------------------------------------
   One hairline, then air. This is the whole separation mechanism. */
.chapter{ position:relative; padding-block:4.6rem 0; }
.chapter + .chapter{ border-top:1px solid var(--rule); margin-top:4.6rem; padding-top:4.6rem; }
.chapter--tight{ padding-block:3.4rem 0; }
/* The marquee is full-bleed and carries a rule above and below itself, so the
   chapter after it must not draw a second one a few centimetres later. */
.chapter--band + .chapter{ border-top:0; }

.chapter__head{
  display:grid; grid-template-columns:1fr auto; gap:.2rem 1.5rem;
  align-items:baseline; margin-bottom:2.4rem;
}
.chapter__num{
  grid-column:1; font-family:var(--label); font-size:.7rem; font-weight:500;
  text-transform:uppercase; letter-spacing:.2em; color:var(--lilac);
}
.chapter__title{ grid-column:1; font-size:clamp(1.6rem,3.2vw,2.15rem); margin-top:.35rem; }
.chapter__title--sm{ font-size:1.35rem; margin-bottom:1.5rem; }
.chapter__note{ grid-column:1; color:var(--dim); font-size:.95rem; max-width:56ch; margin-top:.7rem; }
.chapter__link{ grid-column:2; grid-row:1 / span 2; align-self:center; }
/* A link inside a note, e.g. her newest upload on Watch - set like the one in
   the empty photo state, as underlined type rather than a button. */
.chapter__note a{ color:var(--lilac); text-decoration:none; border-bottom:1px solid var(--rule-firm); }
.chapter__note a:hover{ color:var(--magenta); border-bottom-color:var(--magenta); }

.sublabel{
  font-family:var(--label); font-size:.64rem; text-transform:uppercase;
  letter-spacing:.16em; color:var(--dim); margin:2rem 0 .8rem;
}

/* -- two-column spreads ------------------------------------------------------------ */
.split{ display:grid; grid-template-columns:1fr 1fr; gap:3.5rem; }
.split--wide{ grid-template-columns:.8fr 1.2fr; }

/* -- the player ---------------------------------------------------------------------
   The one big filled shape on the page, and it earns it by being a video. */
.player{ border-radius:var(--r); overflow:hidden; background:var(--deep); }
.player__screen{
  position:relative; aspect-ratio:16/9;
  display:grid; place-items:center; padding:1.5rem;
  background:linear-gradient(158deg,#3A3157,#262034 60%,#423569);
}
.player__screen--embed{ display:block; width:100%; padding:0; border:0; }
.player__glow{
  position:absolute; inset:0;
  background:radial-gradient(56% 64% at 50% 42%, rgba(206,143,223,.18), transparent 70%);
}
.player__state{ position:relative; text-align:center; display:grid; gap:.55rem; justify-items:center; }
.player__emote{ width:76px; height:76px; filter:drop-shadow(0 8px 18px rgba(0,0,0,.45)); }
.player__msg{ font-family:var(--display); font-weight:600; font-size:1.15rem; letter-spacing:-.025em; }
.player__sub{ color:var(--muted); font-size:.88rem; max-width:38ch; line-height:1.55; }
.player__bar{
  display:flex; align-items:center; justify-content:space-between; gap:1rem;
  flex-wrap:wrap; padding:.85rem 1.2rem;
}
.player__bar .mono{ color:var(--dim); }

/* -- the crew ------------------------------------------------------------------------
   Four portraits standing on the page. No frames - the emotes are cut-out art
   with transparent backgrounds and look better without one. */
.crew{ display:grid; grid-template-columns:repeat(5,1fr); gap:2rem 1.5rem; }
.crewcard{
  margin:0; display:grid; gap:.3rem; justify-items:center; text-align:center;
}
.crewcard img{
  width:78px; height:78px; max-width:100%; margin-bottom:.5rem;
  transition:transform .22s ease;
}
.crewcard:hover img,
.crewcard:hover .crewcard__initial{ transform:translateY(-5px) scale(1.04); }
.crewcard__photo{ border-radius:50%; object-fit:cover; }
/* The stand-in for a pet with no art: his initial, in the ring the profile
   pictures wear, on the plum the player and the book covers use. */
.crewcard__initial{
  width:78px; height:78px; margin-bottom:.5rem;
  display:grid; place-items:center; border-radius:50%;
  background:linear-gradient(158deg,#3A3157,#262034 60%,#423569);
  box-shadow:0 0 0 1.5px var(--rule-firm);
  font-family:var(--display); font-weight:700; font-size:2rem;
  letter-spacing:-.04em; color:var(--cream);
  transition:transform .22s ease;
}
.crewcard__name{ font-family:var(--display); font-weight:600; font-size:1.05rem; letter-spacing:-.025em; }
.crewcard__species{
  font-family:var(--label); font-size:.6rem; text-transform:uppercase;
  letter-spacing:.16em; color:var(--magenta);
}
.crewcard__note{ font-family:var(--label); font-size:.68rem; color:var(--dim); font-variant-numeric:tabular-nums; min-height:1.65em; }

/* -- pull quote ------------------------------------------------------------------------
   Cream and a thick left rule, the way a magazine lifts a line out of a column. */
.pullquote{
  margin:0; display:flex; gap:1.4rem; align-items:flex-start; flex-wrap:wrap;
  padding:.4rem 0 .4rem 1.6rem;
  border-left:3px solid var(--cream);
}
.pullquote img{ width:56px; height:56px; flex:none; }
.pullquote > div{ min-width:16rem; flex:1; display:grid; gap:.5rem; justify-items:start; }
.pullquote__title{
  font-family:var(--display); font-weight:600; font-size:1.35rem;
  letter-spacing:-.03em; color:var(--cream);
}
.pullquote p{ color:var(--muted); font-size:1rem; max-width:52ch; }

/* -- clips and videos --------------------------------------------------------------------
   Thumbnail, then a caption under it. The image is the only shape; nothing is
   wrapped in a box. */
.clipgrid{ display:grid; grid-template-columns:repeat(3,1fr); gap:2.2rem 1.6rem; }
.clip{ display:block; text-decoration:none; }
.clip__thumb{
  position:relative; aspect-ratio:16/9; border-radius:var(--r); overflow:hidden;
  display:grid; place-items:center;
  background-color:var(--raised); background-size:cover; background-position:center;
  transition:transform .22s ease;
}
.clip:hover .clip__thumb{ transform:translateY(-4px); }
/* Scrim so the badge and duration stay legible over any frame. ::before, not
   ::after, so the real children paint above it. */
.clip__thumb::before{
  content:""; position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(180deg,
    rgba(22,18,34,.5) 0%, rgba(22,18,34,0) 34%,
    rgba(22,18,34,0) 58%, rgba(22,18,34,.55) 100%);
}
.clip__play{
  position:relative;
  width:46px; height:46px; border-radius:50%;
  background:rgba(22,18,34,.55);
  display:grid; place-items:center;
  border:1.5px solid rgba(255,255,255,.6);
  opacity:0; transform:scale(.9);
  transition:opacity .22s ease, transform .22s ease, background .22s ease, border-color .22s ease;
}
/* The arrow only appears on hover - on a page this quiet, six of them sitting
   there permanently is six pieces of furniture. Touch devices get it always,
   since there is no hover to reveal it. */
.clip:hover .clip__play,
.clip:focus-visible .clip__play{ opacity:1; transform:scale(1); background:var(--magenta); border-color:var(--magenta); }
.clip__play svg{ width:12px; height:12px; fill:#fff; margin-left:2px; }
.clip:hover .clip__play svg,
.short:hover .clip__play svg{ fill:var(--night); }
@media (hover:none){ .clip__play{ opacity:1; transform:scale(1); } }

.clip__dur,.clip__game{
  position:absolute;
  background:rgba(22,18,34,.78); color:#fff;
  padding:.14rem .45rem; border-radius:5px;
  font-family:var(--label); font-size:.64rem; font-variant-numeric:tabular-nums;
}
.clip__dur{ right:.6rem; bottom:.6rem; }
.clip__game{ left:.6rem; top:.6rem; letter-spacing:.03em; }
.clip__body{ padding-top:.85rem; display:grid; gap:.35rem; }
.clip__title{
  font-family:var(--display); font-weight:600; font-size:1rem;
  line-height:1.32; letter-spacing:-.025em;
  transition:color .18s ease;
}
.clip:hover .clip__title{ color:var(--lilac); }
.clip__meta{
  display:flex; gap:.45rem; align-items:center; flex-wrap:wrap;
  font-family:var(--label); font-size:.68rem; color:var(--dim);
  font-variant-numeric:tabular-nums;
}

/* -- away from the setup -----------------------------------------------------------------
   The third shape in the same family. A clip is 16:9 with a title under it
   and TikTok is 9:16; a photograph is square and has no title at all, so
   the only line under it is where it came from and when. The picture is the
   content here rather than the lid on a video, which is also why there is no
   play arrow and no scrim - nothing has to stay legible on top of it. */
.photogrid{ display:grid; grid-template-columns:repeat(3,1fr); gap:1.8rem 1.6rem; }
.photo{ display:block; margin:0; text-decoration:none; }
/* 3:4, which is what the photographs already are, rather than the square an
   Instagram grid would impose - squaring them took her boots off the bottom
   of one and a third of the room off another. They are tall because she is
   standing up in them. */
.photo img{
  display:block; width:100%; aspect-ratio:3/4; object-fit:cover;
  border-radius:var(--r); background:var(--raised);
  transition:transform .22s ease;
}
/* Only the ones that link anywhere lift, so nothing invites a click that
   has no post behind it. */
a.photo:hover img{ transform:translateY(-4px); }
.photo .clip__meta{ padding-top:.7rem; }

/* Empty, which is a state and not a gap: one line saying where they are. */
.away__none{ color:var(--dim); font-size:.95rem; max-width:52ch; }
.away__none a{ color:var(--lilac); text-decoration:none; border-bottom:1px solid var(--rule-firm); }
.away__none a:hover{ color:var(--magenta); border-bottom-color:var(--magenta); }

/* -- tiktok: the same thing, stood upright ------------------------------------------------ */
.shortgrid{ display:grid; grid-template-columns:repeat(6,1fr); gap:2rem 1.4rem; }
.short{ display:block; text-decoration:none; }
.short__thumb{
  position:relative; aspect-ratio:9/16; border-radius:var(--r); overflow:hidden;
  display:grid; place-items:center;
  background-color:var(--raised); background-size:cover; background-position:center;
  transition:transform .22s ease;
}
.short:hover .short__thumb{ transform:translateY(-4px); }
.short__thumb::before{
  content:""; position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(180deg,
    rgba(22,18,34,.28) 0%, rgba(22,18,34,0) 26%,
    rgba(22,18,34,0) 62%, rgba(22,18,34,.55) 100%);
}
.short .clip__play{ opacity:0; }
.short:hover .clip__play{ opacity:1; transform:scale(1); background:var(--magenta); border-color:var(--magenta); }
@media (hover:none){ .short .clip__play{ opacity:1; } }
.short__body{ padding-top:.7rem; display:grid; gap:.3rem; }
.short__title{
  font-family:var(--display); font-weight:600; font-size:.88rem;
  line-height:1.32; letter-spacing:-.02em; transition:color .18s ease;
}
.short:hover .short__title{ color:var(--lilac); }

/* -- emote marquee --------------------------------------------------------------------------
   Full bleed, with rules above and below - a band running across the page
   rather than a panel sitting on it. The track is rendered twice so the loop
   has no seam. */
.marquee{
  position:relative; overflow:hidden;
  margin-inline:calc(50% - 50vw); width:100vw;
  padding-block:1.6rem;
  border-block:1px solid var(--rule);
  -webkit-mask-image:linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
          mask-image:linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
}
.marquee__track{ display:flex; gap:2.4rem; width:max-content; animation:slide 46s linear infinite; }
.marquee:hover .marquee__track{ animation-play-state:paused; }
.marquee__img{ width:60px; height:60px; display:block; transition:transform .2s ease; }
.marquee__img:hover{ transform:scale(1.2); }
@keyframes slide{ from{ transform:translateX(0); } to{ transform:translateX(-50%); } }

/* -- emote grid ------------------------------------------------------------------------------
   No cards - just the art on the page with its token underneath. auto-fill so
   58 emotes never leave a lonely pair on the last row. */
/* 92px is what sets ten across in the full column, which is the size of
   two of the five groups on /emotes and half of two more - at 96px it was
   nine, and two chapters ended on a single emote alone on its row. */
.emotegrid{ display:grid; grid-template-columns:repeat(auto-fill,minmax(92px,1fr)); gap:1.6rem .8rem; }
/* A button, not a figure: the code underneath is something to take away, so
   clicking the emote copies it. Stripped back to nothing - the grid is still
   art on the page with a token under it, and a border-and-fill button 58
   times over would be exactly the panelling the rest of the page refuses. */
.emotecard{
  position:relative; margin:0;
  display:grid; gap:.45rem; justify-items:center; align-content:start;
  appearance:none; background:none; border:0; padding:0;
  font:inherit; color:inherit; text-align:center; cursor:pointer;
}
.emotecard img{ width:52px; height:52px; max-width:100%; transition:transform .2s ease; }
.emotecard:hover img{ transform:scale(1.14); }
.emotecard:active img{ transform:scale(.96); }
.emotecard__code{
  font-family:var(--label); font-size:.56rem; color:var(--dim);
  overflow-wrap:anywhere; line-height:1.4;
  transition:color .18s ease;
  /* Two lines' worth whether the token needs them or not, so a wrapped one
     like maddynfCowboyBaxter doesn't leave its neighbours short. */
  min-height:2.8em;
}
.emotecard:hover .emotecard__code{ color:var(--muted); }
/* It has just said "copied" back in place of its own name. Lilac for a
   moment so the word is seen as an answer rather than read as a caption. */
.emotecard[data-said] .emotecard__code{ color:var(--lilac); }
.emotecard[data-said="no"] .emotecard__code{ color:var(--dim); }
/* Out of flow, so an animated emote sits at exactly the same height as a
   still one and the rows line up. */
.emotecard__anim{
  position:absolute; top:-2px; right:50%; margin-right:-30px;
  width:5px; height:5px; border-radius:50%; background:var(--magenta);
}

/* -- row lists ---------------------------------------------------------------------------------
   Socials, channel facts, the rig, the support links. All the same object: a
   label, a value, a hairline. This is what replaced four different card
   styles. */
.rows{ display:grid; }
.rows > *{
  display:flex; align-items:baseline; justify-content:space-between; gap:1.2rem;
  padding:.85rem .1rem;
  border-bottom:1px solid var(--rule);
  text-decoration:none;
}
.rows > *:first-child{ border-top:1px solid var(--rule); }
.rows a:hover{ color:var(--lilac); }
.rows svg{ width:16px; height:16px; fill:var(--lilac); flex:none; align-self:center; }
.rows__name{ font-size:.98rem; font-weight:500; min-width:0; }
.rows__meta{
  margin-left:auto; font-family:var(--label); font-size:.7rem; color:var(--dim);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.rows__note{ color:var(--dim); font-size:.8rem; }
.rows__arrow{ color:var(--lilac); font-family:var(--label); flex:none; }
/* A creator code sits where the arrow would: it is typed, not followed. */
.rows__code{ color:var(--lilac); font-family:var(--label); font-size:.85rem; letter-spacing:.04em; flex:none; user-select:all; }

/* The <dl> variant: dt is the label, dd is the value. */
.rows--dl{ margin:0; }
.rows--dl div{
  display:flex; align-items:baseline; justify-content:space-between; gap:1.2rem;
  padding:.8rem .1rem; border-bottom:1px solid var(--rule);
}
.rows--dl div:first-child{ border-top:1px solid var(--rule); }
.rows--dl dt{ font-family:var(--label); font-size:.64rem; text-transform:uppercase; letter-spacing:.14em; color:var(--dim); }
.rows--dl dd{ margin:0; font-size:.9rem; text-align:right; }

/* -- about bits ------------------------------------------------------------------------------- */
.prose{ display:grid; gap:1rem; max-width:62ch; color:var(--muted); font-size:1.08rem; margin-top:1.6rem; }

.ticks{ list-style:none; margin:0; padding:0; display:grid; }
.ticks li{
  display:flex; gap:.8rem; align-items:flex-start;
  padding:.7rem .1rem; border-bottom:1px solid var(--rule);
  color:var(--muted); font-size:.96rem; line-height:1.5;
}
.ticks li:first-child{ border-top:1px solid var(--rule); }
.ticks li::before{
  content:""; flex:none; margin-top:.55rem;
  width:5px; height:5px; border-radius:50%; background:var(--magenta);
}

.timeline{ list-style:none; margin:0; padding:0 0 0 1.3rem; display:grid; gap:1.3rem; border-left:1px solid var(--rule); }
.timeline li{ position:relative; display:grid; gap:.1rem; }
.timeline li::before{
  content:""; position:absolute; left:calc(-1.3rem - 3.5px); top:.55rem;
  width:7px; height:7px; border-radius:50%;
  background:var(--magenta); box-shadow:0 0 0 3px var(--night);
}
.timeline__date{ font-family:var(--label); font-size:.63rem; text-transform:uppercase; letter-spacing:.14em; color:var(--dim); }
.timeline__what{ font-size:.98rem; }

.places{ list-style:none; margin:0; padding:0; display:grid; }
.places li{
  display:flex; align-items:baseline; gap:1.2rem;
  padding:.7rem .1rem; border-bottom:1px solid var(--rule);
}
.places li:first-child{ border-top:1px solid var(--rule); }
.places__place{
  font-family:var(--label); font-size:.74rem; font-weight:500;
  color:var(--dim); width:2.4rem; flex:none; font-variant-numeric:tabular-nums;
}
.places li[data-win] .places__place{ color:var(--cream); }
.places__event{ font-size:.94rem; color:var(--muted); }
.places li[data-win] .places__event{ color:var(--ink); }

/* The one place a soft outline survives, because a chip with no edge is just
   loose words. */
.chips{ display:flex; flex-wrap:wrap; gap:.45rem; list-style:none; margin:0; padding:0; }
.chips li{
  padding:.34rem .75rem; border-radius:999px;
  border:1px solid var(--rule-firm);
  font-family:var(--label); font-size:.65rem; color:var(--muted);
}

/* -- contact ------------------------------------------------------------------------------------ */
.contact p{ color:var(--muted); font-size:.96rem; max-width:44ch; }
.contact__mail{
  display:inline-flex; align-items:center; gap:.6rem;
  margin-top:1.4rem; padding-bottom:.35rem;
  font-family:var(--label); font-size:.92rem; color:var(--lilac);
  text-decoration:none; border-bottom:1px solid var(--rule-firm);
  transition:color .18s ease, border-color .18s ease;
}
.contact__mail:hover{ color:var(--magenta); border-color:var(--magenta); }
.contact__mail svg{ width:15px; height:15px; flex:none; }
.contact .mono{ color:var(--dim); margin-top:.8rem; }
.contact .contact__note{ color:var(--dim); font-size:.82rem; margin-top:1.1rem; }

/* -- the book club ---------------------------------------------------------------------------------
   The books pages of a magazine: the current read as a spread, the cover
   large on the left and the type hung off its foot on the right, then the
   shelf as a numbered list. */
.bc-cmd{ font-size:.86em; letter-spacing:0; }
.btn .bc-cmd{ font-weight:500; }

.book{ display:grid; grid-template-columns:220px 1fr; gap:3rem; align-items:end; }
.book__text{ display:grid; gap:.6rem; justify-items:start; padding-bottom:.4rem; }
.book__when{
  font-family:var(--label); font-size:.66rem; text-transform:uppercase;
  letter-spacing:.16em; color:var(--dim);
}
.book__title{
  font-size:clamp(2rem,4.4vw,3.1rem); line-height:1.05;
  font-weight:700; letter-spacing:-.045em; max-width:16ch;
}
.book__author{ color:var(--lilac); font-size:1.12rem; }
.book__note{ color:var(--muted); max-width:50ch; margin-top:.4rem; }
.book .linkbtn{ margin-top:.8rem; }

/* The cover. A real image when there is one; otherwise typeset - the same
   plum ground as the player, a spine down the left edge drawn as a shadow,
   her mark where a publisher's would go. One of the page's few filled
   shapes, which a book has earned the same way a thumbnail has: it is the
   picture of the thing. */
.bookcover{
  width:100%; aspect-ratio:2/3; border-radius:4px 10px 10px 4px;
  box-shadow:inset 7px 0 0 rgba(0,0,0,.2), 0 22px 44px rgba(0,0,0,.35);
}
.bookcover--img{ display:block; height:auto; object-fit:cover; background:var(--raised); }
div.bookcover{
  display:grid; grid-template-rows:auto 1fr auto; gap:1rem;
  padding:1.4rem 1.2rem 1.3rem 1.7rem;
  background:linear-gradient(158deg,#3A3157,#262034 60%,#423569);
}
.bookcover__mark{ width:30px; height:auto; fill:var(--magenta); }
.bookcover__title{
  align-self:center;
  font-family:var(--display); font-weight:700; font-size:1.55rem;
  line-height:1.08; letter-spacing:-.04em; color:var(--cream);
  overflow-wrap:anywhere;
}
.bookcover__author{
  font-family:var(--label); font-size:.6rem; text-transform:uppercase;
  letter-spacing:.14em; color:var(--muted);
}

/* The shelf: the rows again, with a number in front. Newest first and
   numbered down from the top, so 01 is always the club's first book. */
.shelf{ list-style:none; margin:0; padding:0; display:grid; }
.shelf li > *{
  display:flex; align-items:baseline; gap:1.2rem;
  padding:.95rem .1rem; border-bottom:1px solid var(--rule); text-decoration:none;
}
.shelf li:first-child > *{ border-top:1px solid var(--rule); }
.shelf__num{ font-family:var(--label); font-size:.72rem; color:var(--lilac); width:2rem; flex:none; font-variant-numeric:tabular-nums; }
.shelf__book{ flex:1; min-width:0; display:flex; flex-wrap:wrap; align-items:baseline; gap:.2rem .8rem; }
.shelf__title{ font-family:var(--display); font-weight:600; font-size:1.05rem; letter-spacing:-.025em; transition:color .18s ease; }
.shelf__author{ color:var(--dim); font-size:.9rem; }
.shelf__when{ font-family:var(--label); font-size:.68rem; color:var(--dim); flex:none; }
.shelf a:hover .shelf__title{ color:var(--lilac); }

/* -- the links page (/links) -------------------------------------------------------------------------
   Link-in-bio, Linktree style: one centred column of big rounded buttons,
   each a whole-width tap target with its icon on the left. Narrow, because
   it is read on the phone that tapped a bio link, and the same column reads
   fine on a desk. */
body[data-route="links"] .masthead,
body[data-route="links"] .foot{ display:none; }

.view--links{ max-width:520px; padding-block:3.2rem 3rem; }
.contents__head{ display:grid; justify-items:center; text-align:center; gap:.7rem; }
.contents__avatar{
  width:96px; height:96px; border-radius:50%;
  box-shadow:0 0 0 2px var(--magenta), 0 14px 30px rgba(0,0,0,.3);
  margin-bottom:.3rem;
}
.contents__brand{ text-decoration:none; }
.contents__brand .brand__name{ font-size:2.1rem; }
.contents__tag{ color:var(--muted); font-size:1rem; max-width:32ch; }

.tree{ margin-top:2rem; }
.tree__list{ list-style:none; margin:0; padding:0; display:grid; gap:.7rem; }
/* Icon | label | a spacer as wide as the icon, so the label sits dead
   centre the way it does on every link-in-bio page people already know. */
.tree__btn{
  display:grid; grid-template-columns:2.4rem 1fr 2.4rem; align-items:center;
  min-height:58px; padding:.55rem .8rem; width:100%;
  border-radius:16px; border:1px solid var(--rule-firm);
  background:var(--raised); color:var(--ink);
  font:inherit; text-align:center; text-decoration:none; cursor:pointer;
  transition:transform .18s ease, border-color .18s ease, background .18s ease;
}
.tree__btn:hover{ border-color:var(--magenta); transform:translateY(-2px); }
.tree__btn:active{ transform:translateY(0) scale(.99); }
.tree__btn:focus-visible{ outline:2px solid var(--lilac); outline-offset:3px; }
.tree__icon{ display:grid; place-items:center; }
.tree__icon svg{ width:20px; height:20px; fill:currentColor; }
.tree__icon svg[data-stroke]{ fill:none; stroke:currentColor; stroke-width:1.9; stroke-linecap:round; stroke-linejoin:round; }
.tree__label{
  display:grid; gap:.1rem;
  font-family:var(--display); font-weight:600; font-size:1rem; letter-spacing:-.02em;
}
.tree__label small{ font-family:var(--label); font-weight:400; font-size:.68rem; letter-spacing:0; color:var(--dim); }
/* Twitch is the channel, so it is the one filled button. */
.tree__btn--main{ background:var(--magenta); border-color:var(--magenta); color:var(--night); }
.tree__btn--main small{ color:rgba(33,27,51,.7); }
.tree__btn--main:hover{ background:#DEA8EC; border-color:#DEA8EC; }
/* Only there while she is live, above everything else. */
.tree__btn--live{ border-color:var(--live); background:rgba(255,138,166,.1); }
.tree__btn--live .tree__label{ color:var(--live); }
.tree__btn--live .pill{ justify-self:start; }
.tree__btn[data-said] .tree__label small{ color:var(--lilac); }

/* Her second channel: a quiet row rather than two more big buttons. */
.tree__also{
  display:flex; flex-wrap:wrap; justify-content:center; align-items:center; gap:.35rem .9rem;
  padding:.5rem 0 .2rem; color:var(--dim); font-size:.88rem;
}
.tree__also a{ display:inline-flex; align-items:center; gap:.35rem; color:var(--muted); text-decoration:none; }
.tree__also a:hover{ color:var(--lilac); }
.tree__also svg{ width:15px; height:15px; fill:currentColor; }

.tree__socials{ display:flex; justify-content:center; flex-wrap:wrap; gap:.4rem; margin-top:1.8rem; }
.tree__socials a{
  display:grid; place-items:center; width:44px; height:44px; border-radius:50%;
  color:var(--muted); transition:color .18s ease, background .18s ease;
}
.tree__socials a:hover{ color:var(--ink); background:var(--raised); }
.tree__socials svg{ width:20px; height:20px; fill:currentColor; }


/* -- sign-off ------------------------------------------------------------------------------------ */
.signoff{
  text-align:center; display:grid; gap:.7rem; justify-items:center;
  padding-block:1rem;
}
.signoff h2{ font-size:clamp(1.5rem,3.4vw,2.1rem); }
.signoff p{ color:var(--muted); }
.signoff .btn{ margin-top:1rem; }

/* -- footer --------------------------------------------------------------------------------------
   Who this is on the left, where she is on the right, on one line that wraps
   to two when it runs out of room.

   It is the one part of the page allowed a ground of its own. Everywhere
   above, separation is whitespace and a hairline; down here the page has
   ended, and a bottom that is the same plum as the thing above it just
   trails off. The band is the same device as the emote marquee - it runs
   edge to edge rather than sitting on the page as a panel - and it is a
   gradient of about half a step, not a box. */
.foot{
  margin-top:6rem;
  border-top:1px solid var(--rule);
  background:linear-gradient(180deg, rgba(42,35,64,0), rgba(42,35,64,.55));
}
.foot__in{
  max-width:var(--wrap); margin-inline:auto;
  padding:3.2rem var(--gutter) 2.8rem;
  display:flex; align-items:center; justify-content:space-between;
  gap:1.8rem; flex-wrap:wrap;
}
.foot a{ color:var(--muted); }
.foot a:hover{ color:var(--lilac); }

/* The left stack: the lockup, the small print, the credit. */
.foot__brand{ display:inline-block; text-decoration:none; }
.foot__brand .brand__name{
  font-family:var(--brand); font-weight:600; font-size:1.25rem;
  letter-spacing:-.03em; color:var(--ink);
}
/* The link and the emote after it move as one word. Left to wrap on its own
   the emote lands alone on the next line, which reads as a mistake rather
   than as the end of a sentence. */
.foot__tail{ white-space:nowrap; }
.foot__legal{
  margin-top:.75rem;
  font-family:var(--label); font-size:.74rem; color:var(--dim);
}
.foot__credit{
  margin-top:.4rem;
  font-family:var(--label); font-size:.68rem; color:var(--dim); opacity:.8;
}

/* The emote in the small print. A button, so it is sized off nothing but
   itself - no padding, no fill, no border - and reads as the picture it is. */
.foot__poke{
  appearance:none; background:none; border:0; padding:0;
  margin-left:.45rem; vertical-align:-.5em;
  line-height:0; cursor:pointer;
  transition:transform .18s ease;
}
.foot__poke img{ width:26px; height:26px; display:block; }
.foot__poke:hover{ transform:translateY(-2px) rotate(-8deg); }
.foot__poke:active{ transform:translateY(0) scale(.94); }

/* Spelled out, not five bare glyphs. These are the page's only outlined
   shapes, which the buttons already licence - and they are unfilled, so the
   row still reads as type on the page rather than five panels on it. */
.foot__socials{
  display:flex; gap:.6rem; flex-wrap:wrap;
  list-style:none; margin:0; padding:0;
}
.socialchip{
  display:inline-flex; align-items:center; gap:.5rem;
  padding:.5rem .9rem; border-radius:999px;
  border:1px solid var(--rule-firm);
  font-family:var(--body); font-size:.82rem; font-weight:600;
  color:var(--muted); text-decoration:none;
  transition:color .18s ease, border-color .18s ease, transform .18s ease;
}
.socialchip svg{ width:15px; height:15px; flex:none; fill:currentColor; }
.foot .socialchip:hover{
  color:var(--lilac); border-color:var(--magenta);
  transform:translateY(-2px);
}

/* -- responsive ------------------------------------------------------------------------------------ */
@media (max-width:1040px){
  .shortgrid{ grid-template-columns:repeat(4,1fr); }
  .lede__portrait{ width:clamp(120px,16vw,150px); top:3.6rem; }
}
@media (max-width:860px){
  :root{ --gutter:20px; }
  .clipgrid,.photogrid{ grid-template-columns:repeat(2,1fr); }
  .split,.split--wide{ grid-template-columns:1fr; gap:3rem; }
  .crew{ grid-template-columns:repeat(3,1fr); gap:2rem 1rem; }
  .lede__portrait{ width:118px; top:3rem; }
  .book{ grid-template-columns:170px 1fr; gap:2rem; }
  .chapter{ padding-block:3.6rem 0; }
  .chapter + .chapter{ margin-top:3.6rem; padding-top:3.6rem; }
}
@media (max-width:620px){
  .clipgrid{ grid-template-columns:1fr; gap:1.8rem; }
  .shortgrid{ grid-template-columns:repeat(2,1fr); }
  /* No corner left to park it in, so it comes back into the column and
     leads the spread rather than hiding. First in the source, so this is
     all it takes. */
  .lede__portrait{
    position:static;
    width:96px; margin-bottom:1.6rem;
    box-shadow:0 0 0 2px var(--magenta);
  }
  .crew{ grid-template-columns:repeat(3,1fr); gap:2rem .6rem; }
  /* The cover stands over the type rather than beside it, at a size that
     still reads as a book in a hand rather than a thumbnail. */
  .book{ grid-template-columns:1fr; gap:1.8rem; }
  .bookcover{ width:180px; }
  .shelf__when{ display:none; }
  .view--links{ padding-block:2.6rem 2.4rem; }
  .contents__brand .brand__name{ font-size:2rem; }
  .emotegrid{ grid-template-columns:repeat(auto-fill,minmax(80px,1fr)); }
  .masthead__in{ gap:1rem; }
  .masthead__nav{ gap:1.1rem; }
  /* The row runs out of width around here, so the lockup falls back to the
     mark on its own - which is the thing a mark is for. The word and the
     avatar both go; the mark is sized up a little to hold the corner by
     itself, and the .vh name means nothing is lost to a reader. */
  .masthead .brand__avatar,
  .masthead .brand__word{ display:none; }
  .masthead .brand__name{ font-size:1.3rem; }
  .masthead .brand__mark{ margin-right:0; }
  .chapter__head{ grid-template-columns:1fr; }
  .chapter__link{ grid-column:1; grid-row:auto; justify-self:start; margin-top:1rem; }
  .lede{ padding-block:3.5rem 0; }
  /* Both blocks go full width and stack, rather than the socials squeezing
     up beside the lockup at two chips a row. */
  .foot__in{ gap:2rem; }
  .foot__id,
  .foot__socials{ width:100%; }
}

@media (max-width:480px){
  /* Four routes and the mark fill a phone's width, so the status pill keeps
     its dot and gives up the word. The word stays for a screen reader. */
  .masthead__pill #live-pill{ position:absolute; width:1px; height:1px; overflow:hidden; clip-path:inset(50%); }
  .masthead__nav{ gap:.95rem; }
  .masthead__nav a{ font-size:.88rem; }
  /* Five routes do not fit beside the mark at phone width, and the mark is
     already the link home, so the word goes. */
  .masthead__home{ display:none; }

}

@media (prefers-reduced-motion:reduce){
  html{ scroll-behavior:auto; }
  *{ animation-duration:.01ms !important; animation-iteration-count:1 !important; transition-duration:.01ms !important; }
  /* The marquee is only readable while it moves; frozen it is a row that runs
     off the screen. Stopped, it wraps into a block instead - and the second
     run, which exists only to hide the loop's seam, goes away so the block
     isn't every emote twice. */
  .marquee{ -webkit-mask-image:none; mask-image:none; margin-inline:0; width:auto; }
  .marquee__track{ flex-wrap:wrap; width:100%; justify-content:center; gap:1.4rem; }
  .marquee__dup{ display:none; }
  /* Nothing reveals on hover here, so the play arrows have to be there. */
  .clip__play{ opacity:1; transform:none; }
  /* The blanket rule above would leave the marginalia mid-drift. They are
     decoration either way, so they just sit still at their angle. app.js
     separately never wires the mascot or the portrait reels up at all. */
  .marginal{ animation:none; transform:rotate(var(--rot,0deg)); }
}
