diff --git a/css/mix.css b/css/mix.css new file mode 100644 index 0000000..4a32ff3 --- /dev/null +++ b/css/mix.css @@ -0,0 +1,150 @@ +/* ============================================================ + MIX — "Ink & Ember" creative layer over the Arsam Sabbagh + portfolio. Preloader, WebGL hero canvas, intro choreography, + giant footer CTA. All colors ride the site's theme variables + so light/dark + accent tweaks keep working. + ============================================================ */ + +/* ------------------------------------------------------------ + Preloader + ------------------------------------------------------------ */ +.mix-preloader { + position: fixed; inset: 0; z-index: 100000; + background: var(--bg, #F4F0E8); + display: flex; align-items: center; justify-content: center; + transition: background 0.4s ease; +} +.mix-preloader__inner { + display: flex; align-items: baseline; gap: 18px; +} +.mix-preloader__word { + margin: 0; + font-family: var(--serif, 'Instrument Serif', serif); + font-style: italic; + font-weight: 400; + font-size: clamp(28px, 4.5vw, 52px); + letter-spacing: -0.01em; + color: var(--ink, #1A1815); +} +.mix-preloader__count { + margin: 0; + font-family: var(--mono, 'JetBrains Mono', monospace); + font-size: 12px; + letter-spacing: 0.12em; + color: var(--accent, #0F6B73); +} +.mix-preloader__bar { + position: absolute; left: 0; bottom: 0; + width: 100%; height: 2px; + background: var(--rule, #d8d1be); +} +.mix-preloader__bar span { + display: block; width: 0%; height: 100%; + background: var(--accent, #0F6B73); +} + +/* ------------------------------------------------------------ + WebGL ember field in the hero + ------------------------------------------------------------ */ +.mix-ember { + position: absolute; inset: 0; + width: 100%; height: 100%; + display: block; + pointer-events: none; +} +/* the SVG mesh grid stays on top of the shader; its blobs retire */ +.hero.has-ember .hero-mesh { position: absolute; z-index: 1; } +.hero.has-ember .hero-mesh .blob { display: none; } +.hero.has-ember .hero-wrap { z-index: 2; will-change: transform, opacity; } + +/* the big wordmark leans with scroll velocity (js/mix.js) */ +.bw-text { will-change: transform; } + +/* ------------------------------------------------------------ + Hero intro choreography — initial (hidden) states. + html.mix-intro-wait is added by mix.js only when it will + actually run the intro, so nothing stays hidden if JS fails. + ------------------------------------------------------------ */ +html.mix-intro-wait .hero-kicker, +html.mix-intro-wait .hero-meta, +html.mix-intro-wait .hero-ctas, +html.mix-intro-wait .hero-foot { + opacity: 0; +} +html.mix-intro-wait .hero-name .hero-line { + opacity: 0; + transform: translateY(0.35em); + clip-path: inset(0 0 100% 0); +} + +/* ------------------------------------------------------------ + Giant footer CTA + ------------------------------------------------------------ */ +.mix-cta-wrap { + padding: clamp(8px, 2vw, 24px) 0 clamp(48px, 8vw, 110px); + border-bottom: 1px solid var(--rule); + margin-bottom: clamp(40px, 6vw, 80px); +} +.mix-cta-kicker { + margin: 0 0 clamp(18px, 3vw, 36px); + color: var(--accent); +} +.mix-cta { + display: block; + width: max-content; + max-width: 100%; +} +.mix-cta-line { + display: block; + font-family: var(--sans); + font-weight: 300; + font-size: clamp(64px, 15vw, 220px); + line-height: 0.88; + letter-spacing: -0.05em; + color: var(--ink); + transition: letter-spacing 0.8s cubic-bezier(0.2, 0.7, 0.2, 1), color 0.45s ease; +} +.mix-cta-line--stroke { + color: transparent; + -webkit-text-stroke: 1.5px var(--ink); + /* ink-fill sweep: gradient revealed through the glyphs on hover */ + background-image: linear-gradient(90deg, var(--accent), var(--accent)); + background-repeat: no-repeat; + background-size: 0% 100%; + background-position: 0 0; + -webkit-background-clip: text; + background-clip: text; + transition: letter-spacing 0.8s cubic-bezier(0.2, 0.7, 0.2, 1), + background-size 0.7s cubic-bezier(0.2, 0.7, 0.2, 1), + -webkit-text-stroke-color 0.45s ease; +} +.mix-cta:hover .mix-cta-line { letter-spacing: -0.01em; } +.mix-cta:hover .mix-cta-line--stroke { + background-size: 100% 100%; + -webkit-text-stroke-color: var(--accent); +} +html[lang="fa"] .mix-cta-line--stroke { background-position: 100% 0; } + +html[lang="fa"] .mix-cta-line { + font-family: var(--farsi-display, 'Lalezar', sans-serif); + font-weight: 400; + letter-spacing: 0; + line-height: 1.05; + font-size: clamp(56px, 13vw, 190px); +} +html[lang="fa"] .mix-cta-line--stroke { -webkit-text-stroke-width: 1.2px; } +html[lang="fa"] .mix-cta:hover .mix-cta-line { letter-spacing: 0.02em; } + +/* ------------------------------------------------------------ + Reduced motion + ------------------------------------------------------------ */ +@media (prefers-reduced-motion: reduce) { + .mix-preloader { display: none; } + html.mix-intro-wait .hero-kicker, + html.mix-intro-wait .hero-meta, + html.mix-intro-wait .hero-ctas, + html.mix-intro-wait .hero-foot, + html.mix-intro-wait .hero-name .hero-line { + opacity: 1; transform: none; clip-path: none; + } +}