/* The bar is a framed surface because it floats over page content while
   sticky; the page shell has no other frame. */
/* Discord sits beside the call button as a square icon link in the LOG IN button's finish. */

/* ---------- hero ---------- */
.funnel-hero{--hero-pad:36px;position:relative;padding:var(--hero-pad) 0 0;text-align:center;overflow:hidden}
/* Wider than the platform shell so the flanks get 400px each beside the eye; the press row inside is centred and unaffected. */
.funnel-hero .hero-copy{position:relative;z-index:1;width:min(100%,1360px)}
/* Copy flanks the eye: the headline on the left, set toward it, the support line and CTA on the right. Both centre on the eye's vertical middle, which eye-particles.js publishes on the hero as --eye-center-y along with --eye-size. Each flank takes what is left of a 1280px shell after the eye and a 48px gutter on either side. */
/* Centred with the translate property rather than transform, because the .rv reveal animation ends on transform:none. */
.flank{--flank-shell:min(100% - 80px,1280px);--flank-lift:7px;container-type:inline-size;position:absolute;top:calc(var(--eye-center-y,50%) - var(--hero-pad) - var(--flank-lift));width:calc(var(--flank-shell) / 2 - var(--eye-size,380px) / 2 - 48px);translate:0 -50%;z-index:2}
.flank-left{left:calc(50% - var(--flank-shell) / 2);text-align:right}
.flank-right{right:calc(50% - var(--flank-shell) / 2);text-align:left}
/* Eyebrow: one line, framed as a link target. The tag is reversed so it reads as a label, not a badge. */
.eyebrow-pill{display:inline-flex;align-items:center;gap:10px;margin:0;max-width:100%;height:34px;padding:0 14px 0 5px;border:1px solid var(--line);background:var(--surface);color:var(--ink2);font-size:13px;line-height:1;transition:border-color 120ms ease,color 120ms ease}
.eyebrow-pill:hover{border-color:var(--dim);color:var(--ink)}
.eyebrow-pill b{display:inline-flex;align-items:center;flex:none;height:22px;padding:0 8px;background:#fff;color:#000;font-family:"Geist Mono",monospace;font-size:10px;font-weight:600;letter-spacing:.08em}
.eyebrow-pill span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* In a flank the eyebrow may wrap to a second line rather than truncate. */
.flank .eyebrow-pill{height:auto;min-height:34px;padding-top:5px;padding-bottom:5px;text-align:left}
.flank .eyebrow-pill span{white-space:normal;overflow:visible;line-height:1.3}
.flank-right .eyebrow-pill{margin-bottom:18px}
/* Sized from the flank itself so the three pinned lines fit whatever the column width. */
/* platform.css caps .hero h1 at 14ch; the flank headline must span its column so it sits against the eye. */
.flank h1{margin:0;max-width:none;font-family:var(--serif);font-weight:400;font-size:clamp(30px,10.5cqw,48px);line-height:1.1;letter-spacing:-.03em}
/* Each line is a block so the gaps can be evened optically: the line boxes
   are equal, but the p in "Templates" fills the gap below it while the
   gap under the figures of "1000" is empty, so the second line lifts a
   little and the last line drops a little. */
.flank h1 .hl{display:block}
.flank h1 .hl-2{margin-top:0}
.flank h1 .hl-4{margin-top:.04em}
.flank .hero-support{margin:0;font-size:17px;line-height:1.5;color:var(--ink2)}
.flank .hero-actions{margin-top:24px}
.btn-lg{height:52px;padding:0 32px;font-size:16px}

/* The gravity well behind the copy. funnel-grid.js draws it once and pins its throat to the proof label; --well-offset nudges it below that anchor per breakpoint. The vertical mask keeps the far rings off the headline; the bottom is left at full strength so the pour below continues it without a step. */
.funnel{position:absolute;left:50%;top:0;width:max(100%,1500px);aspect-ratio:2000/900;--well-offset:52px;transform:translateX(-50%);pointer-events:none;color:var(--ink);opacity:0;transition:opacity .3s var(--ease);-webkit-mask-image:linear-gradient(to bottom,transparent 0,#000 24%);mask-image:linear-gradient(to bottom,transparent 0,#000 24%)}
.funnel.ready{opacity:1}
.funnel canvas{display:block;width:100%;height:100%}
/* The eye: a full-hero canvas above the well so scattered tiles can fly anywhere; it ignores the pointer so the press links stay clickable. The source video is kept in the document but out of sight, since a display:none video may stop advancing frames. */
.eye{position:absolute;inset:0;z-index:1;pointer-events:none}
.eye canvas{display:block;width:100%;height:100%}
.eye-source{position:absolute;left:0;top:0;width:2px;height:2px;opacity:0;pointer-events:none}
/* The stage holds the space the hero copy used to take, so the well and press row keep their old positions while the copy is rebuilt around the eye. The eye itself is centred on the mouth of the throat, which funnel-grid.js publishes as --well-mouth-x/y on the hero. */
.eye-stage{height:434px}

/* Proof strip: sits in the lower half of the funnel like the reference. */
.proof{margin-top:88px;padding-bottom:48px}
.proof-lbl{margin:0;font-size:16px;color:var(--ink2)}
/* The homepage's press row (same assets, same 0.7 dim), laid out in one line like the reference. */
.proof-logos{list-style:none;display:flex;justify-content:center;align-items:center;flex-wrap:wrap;gap:24px 56px;margin:32px 0 0;padding:0;opacity:.7}
.proof-logos li{display:flex;align-items:center}
.proof-logos img{display:block;height:26px;width:auto}

/* ---------- pour ---------- */
/* Drawn by funnel-grid.js in the well's frame: the plane continuing a short way below the hero and fading out before the clip grid. It lives in main so the hero's clipping does not cut it. main clips sideways because the frame is wider than narrow viewports. */
main{position:relative;overflow-x:clip}
.pour{position:absolute;top:0;left:0;z-index:1;pointer-events:none;color:var(--ink);opacity:0;transition:opacity .3s var(--ease)}
.pour.ready{opacity:1}
.pour canvas{display:block;width:100%;height:100%}

/* ---------- library ---------- */
/* The reaction library: a page of clips fetched by library.js, tools above
   the grid and pages below it. The top margin puts the first row's top edge
   in the first screen so the visitor has a reason to scroll. */
.library{margin-top:max(9px,calc(100svh - var(--hero-bottom,800px) - 215px));scroll-margin-top:88px}
/* The count hangs above the search box instead of taking a row of its own,
   so the box keeps the section's top edge and the grid sits close under it. */
.library-tools{position:relative;display:flex;align-items:center;gap:12px;flex-wrap:wrap;width:min(100%,1360px);margin:0 auto 12px;padding:0 40px}
.library-row{display:flex;gap:10px;flex-wrap:wrap;width:100%}
.library-input{flex:1 1 280px;height:44px;padding:0 14px;border:1px solid var(--line);background:var(--surface);color:var(--ink);font:inherit;font-size:15px;transition:border-color 120ms ease}
.library-go{flex:none;height:44px;padding:0 18px;white-space:nowrap}
.library-go[disabled]{opacity:.6;cursor:wait}
.library-sentence{display:grid;gap:6px;width:100%;font-size:13px;color:var(--ink2)}
.library-sentence input{height:44px;padding:0 14px;border:1px solid var(--line);background:var(--surface);color:var(--ink);font:inherit;font-size:15px}
/* Errors take the same line as the count, in the page's ink. */
.library-status.is-error{color:#ff6b6b}
/* These set their own display, which would beat the hidden attribute. */
.library-sentence[hidden],.tile-plug[hidden],.tile-cap[hidden]{display:none}
/* The poster as blocks while a caption is still being written; sharpens and
   goes when the caption lands. */
.library-grid{transition:opacity 240ms ease}
.library-grid.is-swapping{opacity:0}
.tile-pixels{position:absolute;inset:0;z-index:1;display:block;width:100%;height:100%;pointer-events:none;opacity:1;transition:opacity 220ms ease}
.tile-pixels.is-gone{opacity:0}
/* The caption, in the phone's own text style: TikTok Sans Bold, white with a
   black stroke of 12.5% of the font size painted behind the fill so 6.25%
   shows, line height 1.2, sized from the tile's width. It sits in the band
   the face leaves free, inside the TikTok and Instagram safe areas. */
@font-face{font-family:"TikTok Sans";font-weight:700;font-display:swap;src:url(/site/fonts/TikTokSans-Bold.ttf) format("truetype")}
.tile{container-type:inline-size}
.tile-cap{position:absolute;left:10%;right:10%;z-index:2;text-align:center;color:#fff;font-family:"TikTok Sans","Arial Black",system-ui,sans-serif;font-weight:700;line-height:1.2;paint-order:stroke fill;pointer-events:none}
.tile-cap p{margin:0;font-size:var(--fs);-webkit-text-stroke:calc(var(--fs) * .125) #000}
.tile-cap-main{--fs:6.6cqw}
.tile-cap.is-wall .tile-cap-main{--fs:5.4cqw}
.tile-cap .tile-cap-second{--fs:5cqw;margin-top:.3em}
.tile-cap[data-band="top"]{top:11%}
.tile-cap[data-band="bottom"]{bottom:29%}
.tile-cap[data-band="middle"]{top:50%;transform:translateY(-50%)}
.tile-cap{opacity:0;transition:opacity 260ms ease}
.tile-cap.is-on{opacity:1}
.library-input::placeholder{color:var(--dim)}
.library-input:hover{border-color:var(--dim)}
.library-input:focus-visible{outline:1.5px solid var(--ink2);outline-offset:2px}
.library-status{position:absolute;left:40px;right:40px;bottom:calc(100% + 8px);margin:0;font-family:"Geist Mono",monospace;font-size:12px;line-height:1.3;letter-spacing:.04em;color:var(--dim)}
.library-grid{list-style:none;display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:14px;width:min(100%,1360px);margin:0 auto;padding:0 40px}
.tile{position:relative;margin:0;aspect-ratio:9/16;overflow:hidden;border:1px solid var(--line);background:var(--elev1)}
/* platform.css gives every .tile a full-cover ::after for the home page's
   video wall sheen. Here it would sit above the actions and the mute button
   and take their clicks, so the library tiles have none. */
.library-grid .tile::after{content:none}
.tile.is-skeleton{border-color:transparent}
/* A phone shows the first thirty of a set; the rest wait behind one button. */
.tile.is-folded{display:none}
.library-more{grid-column:1/-1;margin:0;padding:4px 0 0}
.library-more-btn{width:100%;height:44px}
.tile video{display:block;width:100%;height:100%;object-fit:cover}
.library-empty{grid-column:1/-1;margin:0;padding:48px 0;text-align:center;color:var(--ink2)}
/* Actions show for the tile the pointer is moving over (is-pointing, set by
   library.js rather than :hover so tiles sliding under a resting cursor do
   not strobe) and while either action has focus. */
.tile-actions{position:absolute;left:0;right:0;bottom:0;display:grid;gap:6px;padding:8px;background:linear-gradient(rgba(5,5,5,0),rgba(5,5,5,.85) 40%);opacity:0;transition:opacity 120ms ease}
.tile.is-pointing .tile-actions,.tile:focus-within .tile-actions{opacity:1}
.tile-download,.tile-plug{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:34px;padding:6px 10px;font-size:12px;font-weight:500;line-height:1.2;text-align:center;text-decoration:none;transition:background 120ms ease,color 120ms ease}
.tile-download{background:#fff;color:#000}
/* platform.css greys every hovered link; the fill changes here, the text stays black. */
/* Hover only where there is a hover: a tapped button on a phone must not stay grey. */
@media (hover:hover){.tile-download:hover{background:#dbdbdb;color:#050505}}
.tile-download svg{display:block;flex:none}
.tile-plug{border:1px solid rgba(255,255,255,.4);background:rgba(5,5,5,.6);color:#fff}
@media (hover:hover){.tile-plug:hover{background:rgba(5,5,5,.85)}}
.tile-plug-icons{display:inline-flex;flex:none;gap:5px}
.tile-plug-icons svg{display:block}
/* On a narrow tile the label wraps; balanced lines keep "Post on IG" over
   "or TikTok" instead of a dangling word. */
.tile-plug-text{text-wrap:balance}
.tile-download:focus-visible,.tile-plug:focus-visible{outline:1.5px solid var(--ink2);outline-offset:2px}
/* A captioned download being rendered: the arrow gives way to a turning ring
   and the label reads Preparing; the actions stay up until the file arrives. */
.tile-download .tile-download-ring{display:none}
.tile-download.is-preparing{background:#dbdbdb;color:#050505;cursor:progress}
.tile-download.is-preparing .tile-download-icon{display:none}
.tile-download.is-preparing .tile-download-ring{display:block;animation:tile-ring 900ms linear infinite}
.tile.is-preparing .tile-actions{opacity:1}
@keyframes tile-ring{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){.tile-download.is-preparing .tile-download-ring{animation:none}}
/* Sound, top right, only on clips that carry an audio track; unmuting one
   tile mutes the others. */
.tile-mute{position:absolute;top:8px;right:8px;display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;padding:0;border:1px solid rgba(255,255,255,.4);background:rgba(5,5,5,.6);color:#fff;cursor:pointer;opacity:0;transition:opacity 120ms ease,background 120ms ease}
.tile.is-pointing .tile-mute,.tile-mute:focus-visible,.tile-mute[aria-pressed="true"]{opacity:1}
.tile-mute:hover{background:rgba(5,5,5,.85)}
.tile-mute:focus-visible{outline:1.5px solid var(--ink2);outline-offset:2px}
.tile-mute .ico-wave,.tile-mute[aria-pressed="true"] .ico-off{display:none}
.tile-mute[aria-pressed="true"] .ico-wave{display:block}
.library-pages{display:flex;justify-content:center;align-items:center;gap:6px;flex-wrap:wrap;width:min(100%,1360px);margin:28px auto 0;padding:0 40px}
.library-pages button{min-width:40px;height:40px;padding:0 12px;border:1px solid var(--line);background:var(--surface);color:var(--ink2);font-family:"Geist Mono",monospace;font-size:13px;cursor:pointer;transition:background 120ms ease,color 120ms ease}
.library-pages button:hover{background:#262626;color:#fff}
.library-pages button:focus-visible{outline:1.5px solid var(--ink2);outline-offset:2px}
.library-pages button[aria-current="page"]{border-color:#fff;background:#fff;color:#000}
.library-pages button:disabled{opacity:.4;cursor:default}
.library-pages span{color:var(--dim);font-family:"Geist Mono",monospace;font-size:13px}
@media (max-width:809px){
.funnel-hero{--hero-pad:24px}
/* Below the flank breakpoint the copy stacks above the eye: headline, then support and CTA. */
.flank{position:static;width:auto;translate:none;text-align:center;container-type:normal}
.flank-right{margin-top:24px}
.flank .eyebrow-pill{text-align:center}
.eyebrow-pill{height:32px;font-size:12px}
.flank h1{font-size:clamp(34px,9.5vw,44px)}
.flank-right .eyebrow-pill{margin-bottom:14px}
.flank .hero-support{margin:0 auto;max-width:440px;font-size:16px;line-height:1.45}
.flank .hero-actions{justify-content:center;margin-top:20px}
.btn-lg{height:48px;font-size:15px}
.funnel{width:1300px;--well-offset:24px}
.eye-stage{height:324px}
.proof{margin-top:60px;padding-bottom:32px}
.proof-logos{gap:12px 20px}
.library{margin-top:max(9px,calc(100svh - var(--hero-bottom,800px) - 215px))}
.library-tools,.library-pages{padding:0 20px}
.tile-download,.tile-plug{font-size:11px;padding:6px 8px}
/* On a phone the status line wraps to two lines, so it sits in the flow
   above the input instead of hanging over the logos: a little air above,
   the row gap below. */
.library-status{position:static;width:100%;margin:6px 0 0}
.library-go{flex:1 1 100%}
.library-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;padding:0 20px}
}
