/* Ozeka — the landing page.

   Shared world lives in base.css: tokens, stage, bar, credit bar, controls.
   Three things hold this sheet together, and the third was learned late.

   ONE — a handover. The hero is a composition: she takes the right half, the
   type hugs the left. Past it she drops to a glow and the page takes the full
   width, because six sections in a 50ch left column read as a long letter.

   TWO — no generated-page patterns. No numbered 01/02/03 runs, no stat-tile
   banners, no all-caps label above every section, one coloured left border on
   the whole page. DESIGN.md § Prohibited has the measured list.

   THREE — every space on this page comes from --sp-1…--sp-8, the 8px ladder in
   base.css. Nothing is picked by eye. The version before this used .85rem,
   .95rem, 1.1rem, 1.3rem, 1.6rem, 2.25rem and a dozen more one-off values, and
   that is the real reason it read as unprofessional: with no shared increment
   nothing aligns with anything, and the eye sees the near-misses even when it
   cannot name them. Internal padding is always <= the space around the thing. */

#live{opacity:0;transition:opacity 1.2s ease,transform .9s cubic-bezier(.4,0,.2,1)}
#live.up{opacity:1}
#live.recede{opacity:.07;transform:translateX(8%) scale(.97)}
/* ---- measure and rhythm ----
   Prose runs near 70 characters: below ~60 the eye jumps lines, past ~80 it
   loses the return (Butterick: 45–90).

   The rhythm is one rule, applied everywhere. A heading belongs to the text
   *under* it, so the space below it must be smaller than the space between
   paragraphs, and the space above it larger. This sheet had it exactly backwards
   until 31 Oct: 24px under every heading and 16px between paragraphs, which
   glued each heading to the section above and floated it off its own text.

     line-height   1.6 for all prose, 1.1 for display
     p + p         --sp-3  (24px, ~0.87 of a line)
     heading → p   --sp-2  (16px, 0.67 × paragraph spacing)
     p → heading   --sp-6  (64px, ~2.7 × paragraph spacing)
     section       --sp-7  (96px) */
/* The hero column is sized for the HEADLINE, not for the body text.
   `50ch` resolves against .col's own font-size — the body size — so it came out
   at ~500px while the h1 is set at 69px and needs 548px for "Exclusive
   content," alone. Every line of the headline broke in half: four lines where
   two were written, with 460px of dead space to the right of them. Display type
   and body type need different measures; the paragraph keeps its own below. */
.col{width:min(100%,38rem)}
.blk{padding:var(--sp-7) 0}
.blk p,.blk li{line-height:1.6}
.blk > h2{margin-bottom:var(--sp-2)}
.blk p{max-width:68ch}
h2.big{font-size:var(--s-3);max-width:20ch}
.lede{color:var(--muted);font-size:var(--s-1);line-height:1.5;max-width:46ch}
.plain{color:var(--muted)}
.plain + .plain,.lede + .plain{margin-top:var(--sp-3)}
.plain b{color:var(--bone);font-weight:500}
.note{margin-top:var(--sp-3);color:var(--dim);max-width:56ch}

/* ---- hero ---- */
.hero{min-height:100svh;display:flex;align-items:center;padding:var(--sp-8) 0 var(--sp-6)}
/* …and the paragraph keeps a paragraph's measure inside that wider column. */
.hero .col p{max-width:44ch}
.sig{display:flex;align-items:center;gap:var(--sp-1);margin-bottom:var(--sp-3)}
.sig .box{width:8px;height:8px;background:var(--dim)}
.sig .t{font-family:var(--mono);font-size:var(--s--1);letter-spacing:.16em;text-transform:uppercase;color:var(--dim)}
.sig .c{font-family:var(--mono);font-size:var(--s--1);color:var(--muted);font-variant-numeric:tabular-nums}
h1{font-size:var(--s-4);text-wrap:balance}
h1 i{font-style:normal;color:var(--signal)}
.hero p.sub{margin-top:var(--sp-3);font-size:var(--s-1);color:var(--muted);line-height:1.5}
.acts{display:flex;flex-wrap:wrap;gap:var(--sp-1);margin-top:var(--sp-4)}

/* ---- the alternating pair ----
   align-items:start, not center. Centred, the heading and the panel beside it
   began at two different heights in every section — the misalignment you could
   see without being able to name it. Their top edges now agree. */
.duo{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.05fr);
  gap:var(--sp-6);align-items:start}
.duo.flip .say{order:2}
.duo .say h2{font-size:var(--s-3);max-width:17ch;margin-bottom:var(--sp-3)}

.ticks{margin:var(--sp-4) 0 0;padding:0;list-style:none;border-top:1px solid var(--veil)}
.ticks li{padding:var(--sp-2) 0 var(--sp-2) var(--sp-3);border-bottom:1px solid var(--veil);
  position:relative;color:var(--bone)}
.ticks li::before{content:"";position:absolute;left:0;top:1.5rem;width:7px;height:1px;background:var(--signal)}

/* ====== the creator's side, in the creator's colours ======
   The preview below is her page as a fan sees it; this is the same world from
   behind the counter. It shares the preview's palette on purpose rather than
   reverting to a neutral card — one of these objects being grey and the other
   coloured was the inconsistency that made the page feel assembled from parts.
   The light grey panel this replaced is gone with it. */
.composer{margin:0;--pv-bg:#190F35; --pv-card:#271752; --pv-line:#432C7C;
  --pv-text:#F5EFFF; --pv-dim:#C4B2EA;
  --pv-hot:#FF6FB5; --pv-cool:#6BE3FF; --pv-gold:#FFC46B;
  background:var(--pv-bg);color:var(--pv-text);border-radius:16px;overflow:hidden;
  box-shadow:0 22px 50px -20px rgba(0,0,0,.7)}
.composer p{max-width:none}
.cp-head{display:flex;align-items:center;gap:var(--sp-2);padding:var(--sp-3);
  border-bottom:1px solid var(--pv-line);color:var(--pv-dim)}
.cp-body{padding:var(--sp-3);display:grid;gap:var(--sp-2)}
.cp-body b{font-family:var(--display);font-size:var(--s-1);line-height:1.2}
.cp-body p{color:var(--pv-dim);line-height:1.6}
.cp-shot{height:124px;border-radius:12px;position:relative;
  background:linear-gradient(140deg,#B23BC9,#FF6FB5 46%,#FFC46B)}
.cp-shot .badge{position:absolute;left:var(--sp-2);top:var(--sp-2)}
.cp-foot{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-2);
  padding:var(--sp-3);border-top:1px solid var(--pv-line)}
.cp-lbl{color:var(--pv-dim);margin-right:4px}
.cp-foot .pill:last-child{margin-left:auto}

/* ====== the product preview ======================================
   The most important thing on the page: a fan arriving on a creator's page.

   Rebuilt twice. First as a neutral grey card — "on n'est pas en train de faire
   le site d'un hôpital". Then lighter and warmer, still grey underneath, and
   still wrong. Looking at bacharu.io, audioeve.com and vdoo side by side made
   the actual gap nameable, and it is not light versus dark: **two of those three
   are dark, and all three are saturated.** Ours was desaturated. A VTuber page
   is a loud, coloured, image-first place and the community around it is alive;
   a grey card with grey squares reads as LinkedIn.

   So the preview is now a page in Vela's own colours, not in ours: deep teal
   ink, warm amber for anything you can act on, art filling the cards, a visible
   unlock on everything locked, and the hearts and replies that say people are
   in there. Our navy chrome stops at the edge of this panel. */
/* margin:0 first — a <figure> carries 40px of left and right margin from the
   UA stylesheet, which silently pushed this panel out of alignment with
   every heading on the page and shaved 80px off its width. */
.preview{margin:var(--sp-5) 0 0;max-width:72rem;
  /* Vivid, because the reference points are. Teal into sage into sand read as
     muddy — "bleu et vert cacadoie" — and nothing about it said VTuber. The
     violet-into-magenta family is what bacharu and audioeve both live in, and
     it is where this audience's own art already sits. */
  --pv-bg:#190F35; --pv-card:#271752; --pv-line:#432C7C;
  --pv-text:#F5EFFF; --pv-dim:#C4B2EA;
  --pv-hot:#FF6FB5; --pv-cool:#6BE3FF; --pv-gold:#FFC46B;
  background:var(--pv-bg);color:var(--pv-text);border-radius:18px;overflow:hidden;
  box-shadow:0 26px 60px -22px rgba(0,0,0,.75), 0 2px 8px -2px rgba(0,0,0,.4)}
.preview p{max-width:none}

/* Her cover: her colours, and the chalk tally the Depot turns on. */
.pv-cover{height:150px;position:relative;overflow:hidden;
  background:linear-gradient(112deg,#3B1B6B 0%,#8A2B9B 40%,#FF6FB5 70%,#FFC46B 100%)}
.pv-cover::before{content:"";position:absolute;inset:0;
  background:radial-gradient(52% 120% at 72% 10%, rgba(255,214,245,.6), transparent 62%)}
.pv-cover::after{content:"";position:absolute;right:var(--sp-5);bottom:var(--sp-3);
  width:186px;height:58px;opacity:.55;
  background:repeating-linear-gradient(74deg, rgba(255,255,255,.9) 0 2px, transparent 2px 13px)}

.pv-head{display:flex;flex-wrap:wrap;align-items:flex-start;gap:var(--sp-3);
  padding:0 var(--sp-4) var(--sp-4);position:relative}
.pv-ava{width:92px;height:92px;border-radius:26px;flex:none;margin-top:-42px;
  border:4px solid var(--pv-bg);
  background:linear-gradient(145deg,#9BE8FF,#A34BD6 58%,#FF9ECB)}
.pv-id{flex:1;min-width:15rem;padding-top:var(--sp-2)}
.pv-id b,.pv-id .at,.pv-id .bio{display:block}
.pv-id b{font-family:var(--display);font-size:var(--s-2);line-height:1.1;color:var(--pv-text)}
.pv-id .at{color:var(--pv-dim);margin-top:4px}
.pv-id .bio{color:var(--pv-text);margin-top:var(--sp-2);line-height:1.5;max-width:54ch}
.pv-join{display:flex;align-items:center;gap:var(--sp-2);flex-wrap:wrap;padding-top:var(--sp-2)}

/* Anything you can act on is her amber; anything merely true is her cyan. */
.pill{display:inline-block;border-radius:999px;padding:7px var(--sp-2);
  font-weight:600;line-height:1.3;background:var(--pv-hot);color:#190F35}
.pill.cool{background:var(--pv-cool)}
.pill.ghost{background:transparent;border:1px solid var(--pv-line);color:var(--pv-dim);font-weight:400}

.pv-theme{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-2);
  padding:var(--sp-2) var(--sp-4);border-top:1px solid var(--pv-line);
  border-bottom:1px solid var(--pv-line);color:var(--pv-dim)}
.sw{width:24px;height:24px;border-radius:8px;display:inline-block}
.sw.on{box-shadow:0 0 0 2px var(--pv-bg),0 0 0 4px var(--pv-text)}
.sw.a{background:linear-gradient(135deg,#7B2BC6,#FF6FB5)}
.sw.b{background:linear-gradient(135deg,#2563EB,#6BE3FF)}
.sw.c{background:linear-gradient(135deg,#E0366B,#FFC46B)}
.sw.d{background:linear-gradient(135deg,#0E9488,#6EE7C8)}

.tiers{display:grid;grid-template-columns:repeat(3,1fr);border-bottom:1px solid var(--pv-line)}
.tier{padding:var(--sp-3) var(--sp-4);border-right:1px solid var(--pv-line)}
.tier:last-child{border-right:0}
.tier.on{background:var(--pv-card)}
.tier b{display:block;color:var(--pv-text);font-weight:600}
.tier .pr{display:block;font-family:var(--display);font-size:var(--s-1);
  color:var(--pv-hot);line-height:1.3;margin:4px 0 var(--sp-1)}
.tier span{color:var(--pv-dim);line-height:1.5}

/* ---- the feed: image first, like every page a VTuber actually has ---- */
.feed{display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-4);padding:var(--sp-4)}
.item{position:relative;background:var(--pv-card);border-radius:14px;overflow:hidden;
  display:flex;flex-direction:column}
.item.wide{grid-column:1 / -1;flex-direction:row}
.item.wide .shot{width:300px;flex:none;aspect-ratio:auto}

/* The artwork is the card. Locked, it is still the artwork — blurred, with the
   way in sitting on top of it, which is the whole proposition in one object.

   The blur lives on an inner layer, not on the frame: putting filter:blur on
   the frame smeared the badges and the unlock button along with the art, and
   an absolutely-positioned gate needs a positioned ancestor to sit over — the
   first version had neither, so the button rendered nowhere. */
.shot{aspect-ratio:16/9;position:relative;overflow:hidden;background:var(--pv-card)}
.shot .art{position:absolute;inset:-14px}
.shot .art::after{content:"";position:absolute;inset:0;
  background:radial-gradient(46% 58% at 30% 28%, rgba(255,255,255,.5), transparent 62%)}
.art.a{background:linear-gradient(140deg,#B23BC9,#FF6FB5 46%,#FFC46B)}
.art.b{background:linear-gradient(150deg,#4C2BA8,#9B5BE8 46%,#6BE3FF)}
.art.c{background:linear-gradient(135deg,#2B1A66,#6B3FD4 55%,#FF8FC8)}
.art.d{background:linear-gradient(160deg,#C2367A,#FF8A5C 52%,#FFD98A)}
.item.locked .art{filter:blur(14px) saturate(1.2)}
.item.locked .shot::after{content:"";position:absolute;inset:0;background:rgba(25,15,53,.42)}

.shot-top{position:absolute;inset:var(--sp-2) var(--sp-2) auto;display:flex;
  justify-content:space-between;gap:var(--sp-2);z-index:2}
.badge{background:rgba(25,15,53,.82);color:var(--pv-text);border-radius:999px;
  padding:5px var(--sp-2);font-size:var(--s--1);font-family:var(--mono)}

/* The unlock sits over the blur, never under it. */
.gate{position:absolute;inset:0;display:grid;place-items:center;z-index:3}

.card-b{padding:var(--sp-3);display:flex;flex-direction:column;gap:var(--sp-1);flex:1}
.card-b b{font-family:var(--display);font-size:var(--s-1);line-height:1.2;color:var(--pv-text)}
.card-b p{color:var(--pv-dim);line-height:1.6}
.card-f{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-2);margin-top:auto;
  padding-top:var(--sp-2);color:var(--pv-dim)}
.react{display:flex;gap:var(--sp-2);margin-left:auto;color:var(--pv-dim)}
.react span{display:inline-flex;align-items:center;gap:5px}
.react i{font-style:normal;color:var(--pv-hot)}

/* ====== three reasons, on the dark page ====== */
.why{display:grid;grid-template-columns:repeat(3,1fr);gap:0;
  margin-top:var(--sp-5);border-top:1px solid var(--veil)}
.why > div{padding:var(--sp-4) var(--sp-4) var(--sp-4) 0;border-right:1px solid var(--veil)}
.why > div:last-child{border-right:0}
.why > div + div{padding-left:var(--sp-4)}
.why h3{font-size:var(--s-1);margin-bottom:var(--sp-1);max-width:18ch}
.why p{color:var(--muted)}

/* ====== what you can publish: formats, shown rather than listed ====== */
.kinds{display:grid;grid-template-columns:repeat(auto-fit,minmax(13rem,1fr));
  gap:var(--sp-4) var(--sp-4);margin-top:var(--sp-5);
  border-top:1px solid var(--veil);padding-top:var(--sp-4)}
.kind{padding:0}
.kind b{display:block;color:var(--bone);font-weight:500;margin-bottom:2px}
.kind span{color:var(--muted)}

/* ---- faq ---- */
.faqs{columns:2;column-gap:var(--sp-6);border-top:1px solid var(--veil)}
.faqs details{break-inside:avoid;border-bottom:1px solid var(--veil);padding:var(--sp-2) 0}
.faqs summary{cursor:pointer;list-style:none;color:var(--bone);line-height:1.4;
  display:flex;justify-content:space-between;gap:var(--sp-2);align-items:baseline}
.faqs summary::-webkit-details-marker{display:none}
.faqs summary::after{content:"+";font-family:var(--mono);color:var(--signal);flex:none}
.faqs details[open] summary::after{content:"\2212"}
.faqs details p{margin-top:var(--sp-2);color:var(--muted);max-width:52ch}

/* ---- the form ---- */
/* No rules between the fields. The previous version drew a hairline under every
   one of them plus one over the form — five horizontal lines in a four-field
   form, which is the visual signature of a generated page and does nothing a
   gap would not do better. The input's own border is the only boundary a field
   needs; spacing does the grouping. */
.form .f + .f{margin-top:var(--sp-4)}
.form label{display:block;font-size:var(--s-0);color:var(--bone);margin-bottom:var(--sp-1)}
.form label i{font-style:normal;color:var(--signal);margin-left:.2em}
/* A hint beside a question, not fine print: same size, quieter colour. */
.form label .opt{color:var(--dim)}
/* At or above 16px, always: below that iOS Safari zooms the page when a field
   takes focus and drops the visitor into a half-visible form at 1.3x. */
.form input,.form textarea{width:100%;background:var(--raise);color:var(--bone);
  border:1px solid var(--veil-2);font-family:var(--body);font-size:var(--s-0);
  padding:var(--sp-2);resize:vertical;border-radius:8px}
.form input:focus,.form textarea:focus{outline:none;border-color:var(--signal)}
.form input::placeholder,.form textarea::placeholder{color:var(--muted);opacity:1}
.form input[aria-invalid="true"],.form textarea[aria-invalid="true"]{border-color:var(--warm)}
.hp{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.fa{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-3);margin-top:var(--sp-5)}
.fs{color:var(--muted);line-height:1.5}
.fs.bad{color:var(--warm)}
.fs.good{color:var(--signal)}
.form.sent .f,.form.sent .fa .btn{display:none}
.form.sent .fa{margin-top:0}
.form.sent .fs{font-family:var(--body);font-size:var(--s-1);line-height:1.5;color:var(--bone);
  background:var(--raise);padding:var(--sp-3);max-width:46ch}

/* ---- trust footer ----
   Back, and doing a different job from the one that was removed: not a
   paragraph of small print but the three links a stranger looks for before
   typing their address into a form. */
footer::before{content:"";position:absolute;left:0;right:0;top:calc(-1 * var(--sp-8));
  height:var(--sp-8);pointer-events:none;
  background:linear-gradient(180deg,rgba(10,6,24,0),var(--deep))}
footer{position:relative;z-index:2;border-top:1px solid var(--veil);background:var(--deep);
  padding:var(--sp-4) clamp(1.5rem,4vw,4rem) var(--sp-7)}
footer .in{width:min(100%,1320px);margin:0 auto;display:flex;flex-wrap:wrap;
  justify-content:space-between;align-items:center;gap:var(--sp-3)}
.fnav{display:flex;flex-wrap:wrap;gap:var(--sp-3)}
.fnav a{color:var(--muted);text-decoration:none;border-bottom:1px solid var(--veil-2)}
.fnav a:hover{color:var(--bone);border-bottom-color:var(--signal)}

/* ---- the standalone pages: about, privacy ---- */
.page{padding:var(--sp-8) 0 var(--sp-7);max-width:68ch}
.page h1{font-size:var(--s-3);margin-bottom:var(--sp-2)}
.page h2{font-size:var(--s-1);margin:var(--sp-6) 0 var(--sp-2)}
.page p,.page li{color:var(--muted);line-height:1.6}
.page p + p{margin-top:var(--sp-3)}
.page ul{margin:var(--sp-2) 0 0;padding-left:var(--sp-3)}
.page li{margin-bottom:var(--sp-1)}
.page a{color:var(--signal)}
.page .back{display:inline-block;margin-bottom:var(--sp-4);font-family:var(--mono);
  font-size:var(--s--1);color:var(--muted);text-decoration:none}
.page .back:hover{color:var(--bone)}

/* Shown only by the phone block below. */
.feed-more{display:none}
.lbl-short{display:none}

.rv{opacity:0;transform:translateY(10px)}
.rv.in{opacity:1;transform:none;transition:opacity .45s ease,transform .45s ease}

/* ====== narrow ======================================================
   Desktop above 980px is unchanged and stays that way. Everything below is
   written for a phone, because that is where most of this traffic arrives.

   Measured before touching anything, at 390px: no navigation at all (three of
   four links were display:none), a 9 913px document — about fourteen screens —
   the hero's top third empty, the only CTA scrolled off after one swipe, and
   the product preview a desktop page squeezed sideways with cards 800px tall.

   The rules this follows: a tap target is at least 44x44 with 8px between
   targets, and the primary action lives in the thumb's reach, which on a phone
   means the bottom of the screen rather than the top. */
@media (max-width:980px){
  .duo{grid-template-columns:1fr;gap:var(--sp-5)}
  .tiers,.why,.feed{grid-template-columns:1fr}
  .item.wide{flex-direction:column}
  .item.wide .shot{width:auto;aspect-ratio:16/9}
  .tier{border-right:0;border-bottom:1px solid var(--pv-line)}
  .tier:last-child{border-bottom:0}
  .why > div{border-right:0;border-bottom:1px solid var(--veil);padding:var(--sp-3) 0}
  .why > div + div{padding-left:0}
  .pv-theme{padding:var(--sp-2) var(--sp-3)}
  .duo.flip .say{order:0}
  .faqs{columns:1}
  .cost .fig{font-size:var(--s-3)}
  .blk{padding:var(--sp-6) 0}
}
@media (max-width:900px){
  #live.recede{opacity:.07;transform:none}
  .col{width:100%}
  h2.big,.duo .say h2{max-width:none}
}

/* ---------------- phone ---------------- */
@media (max-width:640px){

  /* She fills the dead band at the top of the hero instead of hiding behind the
     words. app.js frames her head into the upper third on narrow screens; the
     veil below her stays near-solid so the type never crosses her face. */
  #live.up{opacity:.85;transform:none}
  #stage::after{background:
    linear-gradient(180deg, rgba(16,10,36,.55) 0%, rgba(16,10,36,.10) 20%,
                    rgba(16,10,36,.82) 40%, var(--ground) 52%)}

  /* These two must come AFTER .up or they lose to it at equal specificity —
     which is exactly what happened: she stayed at 85% for the whole scroll and
     every heading below the hero was set across her face. Past the hero she is
     a whisper and the veil is effectively solid; a phone has no room to hold a
     composition beside the text the way the desktop does. */
  #live.recede{opacity:.05;transform:none}
  #stage.reading::after{background:linear-gradient(180deg,
    rgba(16,10,36,.95) 0%, rgba(16,10,36,.97) 100%)}

  .hero{min-height:auto;padding:46vh 0 var(--sp-5);align-items:flex-start}
  .hero p.sub{margin-top:var(--sp-2)}
  .acts{flex-direction:column;align-items:stretch;gap:var(--sp-2)}
  .acts .btn{text-align:center}

  .blk{padding:var(--sp-5) 0}
  h2.big,.duo .say h2{font-size:var(--s-2)}
  .duo{gap:var(--sp-4)}

  /* Every target the thumb has to hit. 44px is the floor, 8px the gap. */
  .btn{padding:var(--sp-2) var(--sp-3);min-height:48px;display:flex;
    align-items:center;justify-content:center}
  .bar .go{min-height:44px;display:flex;align-items:center}
  .faqs summary{min-height:48px;align-items:center}
  .form input{min-height:48px}
  .fnav{gap:var(--sp-1)}
  .fnav a{display:flex;align-items:center;min-height:44px;padding:0 var(--sp-2)}
  .fnav a:first-child{padding-left:0}

  /* ---- the product preview, as a phone ----
     The point of this block. A fan on a phone sees a phone-shaped page, not a
     desktop one shrunk: near full bleed, one tall card to carry the argument
     that locked work is still visible, and the rest as compact rows the way
     every feed on a phone actually looks. */
  .preview{margin-left:calc(-1 * clamp(1.5rem,4vw,4rem) + 12px);
    margin-right:calc(-1 * clamp(1.5rem,4vw,4rem) + 12px);
    border-radius:16px}
  .pv-cover{height:104px}
  .pv-head{padding:0 var(--sp-3) var(--sp-3)}
  .pv-ava{width:68px;height:68px;border-radius:20px;margin-top:-30px}
  .pv-id{padding-top:var(--sp-1)}
  .pv-id b{font-size:var(--s-1)}
  .tier{padding:var(--sp-3)}
  .feed{padding:var(--sp-3);gap:var(--sp-3)}

  /* The first card keeps its picture, because the argument that locked work is
     still visible needs one full-size example. The rest become rows, which is
     what a feed looks like on a phone. The thumb is 128px so the unlock still
     fits inside it without spilling across the title. */
  .item:not(.lead-card){flex-direction:row;align-items:stretch}
  .item:not(.lead-card) .shot,
  .item.wide:not(.lead-card) .shot{width:104px;flex:none;aspect-ratio:auto;border-radius:0}
  .item:not(.lead-card) .shot-top{inset:6px 6px auto;flex-direction:column;gap:4px}
  .item:not(.lead-card) .shot-top .badge:last-child{display:none}
  .item:not(.lead-card) .gate{inset:auto 6px 6px;align-items:end}
  /* A 104px thumb has no room for "Join to unlock" and a 190px text column has
     none for "Open to everyone" beside a heart count. Each long label has a
     short twin; the row shows the twin and the full-size card keeps the real
     words. Nothing is measured in CSS and guessed at. */
  .item:not(.lead-card) .lbl-long{display:none}
  .item:not(.lead-card) .lbl-short{display:inline-block;font-size:var(--s--1);padding:4px 10px}

  /* min-width:0 or the meta row's intrinsic width stops the text column ever
     shrinking, and the title gets clipped mid-word instead of wrapping. */
  .item:not(.lead-card) .card-b{padding:var(--sp-2) var(--sp-3);gap:0;
    justify-content:center;min-width:0}
  .item:not(.lead-card) .card-b p{display:none}
  .item:not(.lead-card) .card-b b{overflow-wrap:anywhere}
  /* One line of meta, not three stacked: the tier says what it costs and the
     hearts say the place is alive. The date and the reply count go. */
  .item:not(.lead-card) .card-f{margin-top:var(--sp-1);padding-top:0;flex-wrap:nowrap;
    gap:var(--sp-2);align-items:center;min-width:0}
  .item:not(.lead-card) .card-f > span:not(.pill):not(.react){display:none}
  .item:not(.lead-card) .card-f .pill{font-size:var(--s--1);padding:4px 10px;white-space:nowrap}
  .item:not(.lead-card) .react{gap:var(--sp-1);flex:none}
  .item:not(.lead-card) .react span:last-child{display:none}

  /* A feed is endless; saying so is more honest than printing five of it. */
  .feed-more{display:block;padding:var(--sp-2) var(--sp-3) var(--sp-3);
    color:var(--pv-dim);text-align:center}

  .composer{margin-left:0;margin-right:0}
  .cp-foot .pill:last-child{margin-left:0}

  /* ---- the action, where the thumb is ----
     The top bar keeps the mark alone; the CTA moves to a fixed bar at the foot
     of the screen so it is reachable from anywhere in a 10 000px page, with
     2ex's credit as the strip beneath it. Two jobs, one assembly. */
  .bar nav{display:none}
  .bar{padding:var(--sp-2) clamp(1.5rem,4vw,4rem)}

  .dock > .dock-cta{display:flex;width:auto;margin:10px 16px;border-top:0}
  .credit{padding:8px 16px calc(8px + env(safe-area-inset-bottom))}
  .credit p{white-space:normal}
  /* Clearance so the dock never covers the end of the page. */
  body{padding-bottom:132px}
  footer{padding-bottom:var(--sp-4)}
}

/* ---------------- very narrow (iPhone SE and friends) ----------------
   At 320px a row has 96px left for its meta after the thumb and the padding,
   and the tier pill alone wants 82 of it. Measured: four of five cards
   overflowed. Here the meta is allowed to wrap onto a second line — a taller
   card is better than a clipped one. */
@media (max-width:360px){
  .item:not(.lead-card) .shot,
  .item.wide:not(.lead-card) .shot{width:88px}
  .item:not(.lead-card) .card-f{flex-wrap:wrap;gap:var(--sp-1)}
  .item:not(.lead-card) .react{margin-left:0}
  .preview{margin-left:-12px;margin-right:-12px}
  .feed{padding:var(--sp-2)}
}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *{transition:none!important;animation:none!important}
  .rv{opacity:1;transform:none}
  #live{opacity:1}
}
