/* Shared visual language for the release-announcement composition. New * compositions should import these tokens instead of inventing their own — * that's what keeps the library coherent as more clips merge in over time. * * One accent color, a near-black (never pure #000) ink field, warm off-white * (never pure #fff) text. A display face for headlines paired with a body * face for everything else. See motion/README.md for the design-bar rationale. */ @font-face { font-family: "Share Tech Mono"; src: url("../../public/fonts/ShareTechMono-Regular.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: block; } @font-face { font-family: "Inter"; src: url("../../public/fonts/Inter-Variable.woff2") format("woff2-variations"); font-weight: 400 600; font-style: normal; font-display: block; } :root { --color-ink: #0B0B10; --color-ink-raised: #15151C; --color-paper: #F5F2EA; --color-muted: #9C9891; --color-accent: #FF5A1F; --color-hairline: rgba(245, 242, 234, 0.12); --font-display: "Share Tech Mono"; --font-body: "Inter"; } * { box-sizing: border-box; margin: 0; padding: 0; } html, body { width: 100%; height: 100%; background: var(--color-ink); color: var(--color-paper); font-family: var(--font-body); -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; } #stage { position: relative; width: 1080px; height: 100%; overflow: hidden; background: var(--color-ink); } /* Scan line — the one continuous ambient motion. A thin hairline near the * top with a small accent marker that travels left→right across the whole * clip, so the frame never goes fully static once entrances land. */ .scan { position: absolute; left: 84px; right: 84px; height: 2px; background: var(--color-hairline); } .scan__marker { position: absolute; top: -3px; left: 0; width: 64px; height: 8px; border-radius: 4px; background: var(--color-accent); box-shadow: 0 0 28px var(--color-accent); transform: translateX(-50%); animation: scan-travel 10s linear forwards; } @keyframes scan-travel { from { left: -12%; } to { left: 112%; } } /* Content block anchored in the lower two-thirds, left-aligned. */ .content { position: absolute; left: 84px; right: 96px; bottom: var(--content-bottom, 148px); } .kicker { font-family: var(--font-body); font-size: 30px; font-weight: 600; letter-spacing: 6px; text-transform: uppercase; color: var(--color-accent); margin-bottom: 20px; opacity: 0; transform: translateY(16px); animation: enter-rise 0.9s cubic-bezier(0.22, 1, 0.36, 1) forwards; animation-delay: 0s; } .headline { font-family: var(--font-display); font-size: 148px; font-weight: 400; line-height: 1; color: var(--color-paper); margin-bottom: 28px; transform-origin: left bottom; opacity: 0; transform: translateY(22px) scale(0.94); animation: enter-rise-scale 0.9s cubic-bezier(0.22, 1, 0.36, 1) forwards; animation-delay: 0.267s; /* ~8 frames @30fps */ } .script { font-family: var(--font-body); font-size: 44px; font-weight: 500; line-height: 1.25; color: var(--color-paper); max-width: 820px; margin-bottom: 40px; opacity: 0; transform: translateY(22px); animation: enter-rise 0.9s cubic-bezier(0.22, 1, 0.36, 1) forwards; animation-delay: 0.8s; /* ~24 frames @30fps */ } .highlights { list-style: none; padding: 0; margin: 0; } .highlights__item { display: flex; align-items: center; font-family: var(--font-body); font-size: 34px; font-weight: 400; color: var(--color-paper); margin-bottom: 18px; opacity: 0; transform: translateX(-36px); animation: enter-slide 0.7s cubic-bezier(0.22, 1, 0.36, 1) forwards; } .highlights__item:nth-child(1) { animation-delay: 1.667s; } /* ~50 frames */ .highlights__item:nth-child(2) { animation-delay: 2.133s; } /* +14 frames */ .highlights__item:nth-child(3) { animation-delay: 2.6s; } /* +14 frames */ .highlights__item:nth-child(4) { animation-delay: 3.067s; } /* +14 frames */ .highlights__tick { display: inline-block; width: 22px; height: 3px; margin-right: 18px; flex-shrink: 0; background: var(--color-accent); } .outro { position: absolute; left: 84px; bottom: 56px; font-family: var(--font-body); font-size: 26px; font-weight: 500; letter-spacing: 2px; color: var(--color-muted); opacity: 0; transform: translateY(14px); animation: enter-rise 0.8s cubic-bezier(0.22, 1, 0.36, 1) forwards; animation-delay: 7.667s; /* durationInFrames - 70 = 230 frames @30fps */ } @keyframes enter-rise { to { opacity: 1; transform: translateY(0); } } @keyframes enter-rise-scale { to { opacity: 1; transform: translateY(0) scale(1); } } @keyframes enter-slide { to { opacity: 1; transform: translateX(0); } }