/* OUT NOW lyric film: the render spec (W6, 2026-09-26). The source of the landing's public/paper/assets/outnow-film.css
   (copied by tools/outnow-film-sync.mjs) and of the worker's capture page (film/rasterise.mjs): one CSS, so the landing
   film and the delivered video are the same pixels.
   One ground per song: paper, ink or cobalt (design/accent-tokens.md §3; outnow-film.mjs GROUND_TONES holds the same
   values). The word being sung is LIT: cobalt on paper (9.49:1), mustard on ink (8.03:1) and on cobalt (4.66:1), so it
   reads at any size; tomato is never in a film. The words still to come are dim at >= 3:1 on each ground. Anton for the
   name, Instrument Serif italic for the title and the hook, Inter Tight for the lyric and the small type. Hard cuts on
   phrases, nothing bounces. Every size is in px of the 1080x1920 master (--u = one master pixel).
   The host page declares the six @font-face rules and may set --on-name / --on-title / --on-body. */
.bf{display:block;--u:calc(100cqw / 1080);--bf-ground:#F3EFE6;--bf-text:#121212;--bf-dim:#878580;--bf-lit:#1D358A;--bf-hair:rgba(18,18,18,.5);
  --bf-mark:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cpath fill-rule='evenodd' d='M61.85 29.02A30 30 0 1 0 29.02 61.85ZM36.6 32a4.6 4.6 0 1 0-9.2 0a4.6 4.6 0 1 0 9.2 0Z'/%3E%3Cpath d='M61.85 29.02A30 30 0 0 0 29.02 61.85Z' fill-opacity='.45'/%3E%3C/svg%3E");
  position:relative;container-type:inline-size;aspect-ratio:9/16;overflow:hidden;background:var(--bf-ground);color:var(--bf-text);
  font-family:var(--on-body,"Inter Tight",system-ui,sans-serif);-webkit-font-smoothing:antialiased;text-align:left;user-select:none}
.bf:is([data-ground=ink],[data-ground=plum]){--bf-ground:#121212;--bf-text:#F3EFE6;--bf-dim:#6C6A67;--bf-lit:#D8A033;--bf-hair:rgba(243,239,230,.5)}
.bf:is([data-ground=cobalt],[data-ground=forest]){--bf-ground:#1D358A;--bf-text:#F3EFE6;--bf-dim:#7D89B3;--bf-lit:#D8A033;--bf-hair:rgba(243,239,230,.5)}
/* forest and plum retired (J-Visual): aliases of cobalt and ink until the landing's film.json says cobalt and ink */
.bf *{box-sizing:border-box}
/* The worker's text layer: the same film on a transparent ground; ffmpeg lays it on the ground and the motion layer. */
.bf[data-layer=text]{background:transparent}
.bf[data-layer=text] .bf-photo{display:none!important}

/* ---- photos (Single + Video, landing films): a full-bleed window at the top, one grade for every photo, type only
   in the band below it, so type never sits over a face. Tall photos: 1080x1000 window. Wide photos: 1080x760. */
.bf-photo{position:absolute;left:0;right:0;top:0;height:calc(1000 * var(--u));overflow:hidden;display:none;background:#1C1B19}
.bf[data-photo=land] .bf-photo{height:calc(760 * var(--u))}
.bf:is([data-photo=tall],[data-photo=land]) .bf-photo{display:block}
.bf-photo img{display:block;width:100%;height:100%;object-fit:cover;object-position:50% var(--y,30%);filter:saturate(.8) contrast(1.06) sepia(.1) brightness(.98)}

/* ---- the stage: where the words go. Safe area without a photo: 88 px sides, 250 px top (Story/Reels header),
   400 px bottom (reply bar, captions). With a photo: the band under the window, down to 330 px from the bottom. */
.bf-stage{position:absolute;left:calc(88 * var(--u));right:calc(88 * var(--u));top:calc(250 * var(--u));bottom:calc(400 * var(--u));display:flex;flex-direction:column;justify-content:center}
.bf[data-photo=tall] .bf-stage{top:calc(1070 * var(--u));bottom:calc(330 * var(--u));justify-content:flex-start}
.bf[data-photo=land] .bf-stage{top:calc(840 * var(--u));bottom:calc(330 * var(--u));justify-content:center}

/* ---- words: what is still to come is dim, what has been sung is full, the word being sung is lit. No fades. */
.bf-w{color:var(--bf-dim)}
.bf-w.is-sung{color:var(--bf-text)}
.bf-w.is-now{color:var(--bf-lit)}

/* a plain line: Inter Tight 700, 112 px, 1.02 (92 px in the band under a photo), at most three rows; a longer line
   is set smaller in steps (--fit, film/outnow-film.mjs) */
.bf-line{display:block;margin:0;font:700 calc(112 * var(--u) * var(--fit,1))/1.02 var(--on-body,"Inter Tight",sans-serif);letter-spacing:-.022em;text-wrap:balance}
.bf:is([data-photo=tall],[data-photo=land]) .bf-line{font-size:calc(92 * var(--u) * var(--fit,1))}

/* the name line: the name alone on its row in Anton caps, sized to fill the measure (max 380 px; 300 in the band); the words around it 92 px (76 in the band) */
.bf-pre,.bf-post{display:block;margin:0;font:700 calc(92 * var(--u) * var(--fit,1))/1.04 var(--on-body,"Inter Tight",sans-serif);letter-spacing:-.02em;text-wrap:balance}
.bf:is([data-photo=tall],[data-photo=land]) :is(.bf-pre,.bf-post){font-size:calc(76 * var(--u) * var(--fit,1))}
.bf-name{display:block;margin:calc(22 * var(--u)) 0 calc(18 * var(--u));font:400 min(calc(380 * var(--u)),calc(1740 * var(--u) / var(--n,6)))/.86 var(--on-name,"Anton",Impact,sans-serif);text-transform:uppercase;letter-spacing:.004em;white-space:nowrap}
.bf:is([data-photo=tall],[data-photo=land]) .bf-name{font-size:min(calc(300 * var(--u)),calc(1740 * var(--u) / var(--n,6)))}
.bf-pre:empty,.bf-post:empty{display:none}
.bf-name:first-child{margin-top:0}

/* the hook: the one big type moment of the song, Instrument Serif italic 196 px, filling the frame, type only */
.bf-hook{display:block;margin:0;font:italic 400 calc(196 * var(--u) * var(--fit,1))/.92 var(--on-title,"Instrument Serif",Georgia,serif);letter-spacing:-.012em;text-wrap:balance}

/* ---- the cover (decision 13: one cover opens and closes the film; the same cover is the poster, og:image and the
   email poster). Open: from 0 to the first sung word - 0.12 s, 0.7-1.5 s (outnow-film.mjs coverEndFor). The stack is
   bottom-aligned: NAME (Anton), "Title" (serif italic), "from Amelia", the foot (HAD TO BE THERE, the label). No age. */
.bf-cover{display:flex;flex-direction:column;height:100%}
.bf-cbody{margin-top:auto;display:flex;flex-direction:column;padding-bottom:calc(20 * var(--u))}
.bf-cover .bf-name{margin:0;font-size:min(calc(400 * var(--u)),calc(1740 * var(--u) / var(--n,6)))}
.bf-title{display:block;margin:calc(14 * var(--u)) 0 0;font:italic 400 calc(112 * var(--u))/1 var(--on-title,"Instrument Serif",Georgia,serif);letter-spacing:-.01em;text-wrap:balance}
.bf-from{display:block;margin:calc(34 * var(--u)) 0 0;font:600 calc(46 * var(--u))/1.2 var(--on-body,"Inter Tight",sans-serif);letter-spacing:-.005em}
.bf-cfoot{display:flex;justify-content:space-between;align-items:flex-end;gap:calc(30 * var(--u));margin-top:calc(60 * var(--u))}
/* the sticker: the advisory-label mechanic (a boxed, tracked, heavy caps label in the corner of the sleeve) */
.bf-jokes{display:inline-block;flex:none;border:calc(4 * var(--u)) solid currentColor;padding:calc(14 * var(--u)) calc(20 * var(--u)) calc(12 * var(--u));font:800 calc(30 * var(--u))/1 var(--on-body,"Inter Tight",sans-serif);letter-spacing:.1em;text-transform:uppercase}
.bf-label{display:flex;flex-direction:column;align-items:flex-end;gap:calc(12 * var(--u));font:600 calc(32 * var(--u))/1 var(--on-body,"Inter Tight",sans-serif);letter-spacing:.02em;opacity:.65}
.bf-label-row{display:flex;align-items:center;gap:calc(14 * var(--u))}
.bf-label i,.bf-glyph{display:inline-block;background:currentColor;-webkit-mask:var(--bf-mark) center/contain no-repeat;mask:var(--bf-mark) center/contain no-repeat}
/* the mark in the label: 40 px, under 5% of the width; then the ℗, drawn (PHONOGRAM: no brand face carries it) */
.bf-label i{width:calc(40 * var(--u));height:calc(40 * var(--u))}
.bf-p{display:block;flex:none;width:calc(28 * var(--u));height:calc(28 * var(--u));margin-right:calc(-5 * var(--u));fill:currentColor}
.bf-url{display:block;letter-spacing:.01em}
/* the address row is reserved on the opening cover too, so the closing cover's stack stands exactly where the cover's did */
.bf-cover:not(.bf-close) .bf-url{visibility:hidden}
/* with a photo, the cover's type sits in the band under the window, the photo's top on a scrim */
.bf:is([data-photo=tall],[data-photo=land]) .bf-cover{padding:0}
.bf:is([data-photo=tall],[data-photo=land]) .bf-cbody{margin-top:0}
.bf:is([data-photo=tall],[data-photo=land]) .bf-cfoot{margin-top:calc(40 * var(--u))}
.bf[data-state=cover]:is([data-photo=tall],[data-photo=land]) .bf-photo::after{content:"";position:absolute;inset:0 0 auto;height:calc(300 * var(--u));background:linear-gradient(rgba(0,0,0,.45),transparent)}

/* ---- the closing cover: the same cover, plus one small HAPPY BIRTHDAY line over the name, the cause over it (the
   gift, never its outcome) and birthdayclip.com under the label. It is the film's last frame. */
.bf-kicker{display:block;margin:0 0 calc(22 * var(--u));font:700 calc(40 * var(--u))/1 var(--on-body,"Inter Tight",sans-serif);letter-spacing:.18em;text-transform:uppercase}
/* the cause, in the stack over HAPPY BIRTHDAY (the top of the frame is the moving layer's: J-Video fix 9). The mark is
   IC-B's, in the type colour; the line is CONTENT_MAP's cause.state. Quieter than the stack it sits in (J-Video round
   2): regular weight, 27 px (75 % of the 36 px it was), 70 % tone, the mark 72 px (was 120), so HAPPY BIRTHDAY and the
   NAME read before it. It keeps its place; J-Video may move the line, never drop it. */
.bf-cause{display:flex;align-items:center;gap:calc(20 * var(--u));margin:0 0 calc(44 * var(--u));opacity:.7}
.bf-icon{flex:none;display:block;width:calc(72 * var(--u));height:calc(72 * var(--u))}
.bf-icon svg{display:block;width:100%;height:100%;fill:currentColor;stroke:none}
.bf-cause-text{display:flex;flex-direction:column;gap:calc(8 * var(--u));max-width:calc(560 * var(--u))}
.bf-cause-what{font:400 calc(27 * var(--u))/1.2 var(--on-body,"Inter Tight",sans-serif);letter-spacing:0;text-wrap:balance}
.bf-cause-with{font:400 calc(23 * var(--u))/1 var(--on-body,"Inter Tight",sans-serif);letter-spacing:.02em;opacity:.8}

/* ---- the moving layer (landing films; the worker draws it with ffmpeg from the same geometry, motifLayout): each
   piece a mask of its pool PNG filled in its motif tone, placed by create() at motifPose(t). Never on the text layer
   the worker rasterises, and not in the photo band (the photo video's band is not in this pool). */
.bf-motif{position:absolute;inset:0;overflow:hidden;pointer-events:none}
.bf-mp{position:absolute;left:0;top:0;background:var(--c);-webkit-mask:var(--m) center/100% 100% no-repeat;mask:var(--m) center/100% 100% no-repeat;transform-origin:50% 50%;will-change:transform}
.bf[data-layer=text] .bf-motif,.bf:is([data-photo=tall],[data-photo=land]) .bf-motif{display:none}

/* ---- the corner glyph: the label mark only (no URL), 54 px (5% of the width), 65% opacity. Default: lower left,
   raised 22% of the height to clear Reels/TikTok captions (y 1444); data-glyph=top: top right (962, 150), the other
   placement J-Video tests. Not on the covers, which carry the label in words. */
.bf-glyph{position:absolute;left:calc(64 * var(--u));bottom:calc(422 * var(--u));width:calc(54 * var(--u));height:calc(54 * var(--u));opacity:.65;pointer-events:none}
.bf[data-glyph=top] .bf-glyph{left:auto;bottom:auto;right:calc(64 * var(--u));top:calc(150 * var(--u))}
.bf:is([data-state=cover],[data-state=close]) .bf-glyph{display:none}
/* with a photo the glyph moves off the photo (never on a face): the band's lower right, 270 px from the bottom */
.bf:is([data-photo=tall],[data-photo=land]) .bf-glyph{top:auto;left:auto;right:calc(64 * var(--u));bottom:calc(270 * var(--u))}

/* ---- the square cover (og:image, email): the same stack, bottom-aligned, on a 1080x1080 sleeve */
.bf[data-format=square]{aspect-ratio:1}
.bf[data-format=square] .bf-stage{top:calc(88 * var(--u));bottom:calc(80 * var(--u))}
.bf[data-format=square] .bf-cover .bf-name{font-size:min(calc(300 * var(--u)),calc(1740 * var(--u) / var(--n,6)))}
.bf[data-format=square] .bf-title{font-size:calc(96 * var(--u))}
.bf[data-format=square] .bf-from{margin-top:calc(26 * var(--u))}
.bf[data-format=square] .bf-cfoot{margin-top:calc(44 * var(--u))}

/* The landing's own placement rules (player, room, Story mock) live in outnow.css. */
