// ===========================================================================
// PLAIN TEXT JS SOURCE FILE — iam/marketing v5 d4-shell
// ===========================================================================
//
// This file contains JavaScript and JSX source code.
// Loaded at runtime by Babel-standalone and compiled in the browser.
// Not intended to be parsed as HTML.
//
// Charset: UTF-8 · Line endings: LF · Filetype: text/plain
// ===========================================================================
// D4 Production · Shared primitives, tokens, nav, footer.
// Operator Console direction — terminal chrome, mono labels, status pips, marquees, // comments.
const D4P = {
// Surfaces
void: '#050506',
base: '#0A0A0B',
surface: '#0F0F11',
surfaceHi: '#161618',
// Foreground
bone: '#F2EFE6',
boneDim: 'rgba(242,239,230,0.78)', // bumped 0.72 → 0.78 for WCAG AA
muted: 'rgba(242,239,230,0.58)', // bumped 0.45 → 0.58 to clear 4.5:1 on void
faint: 'rgba(242,239,230,0.30)', // bumped 0.22 → 0.30 (decorative still, but readable)
// Accents
accent: '#C5D86D', // chartreuse — system-active
accentHi: '#D9EE7A',
warm: '#D4A574', // sand — secondary
danger: '#C97D7D', // red — broken state
cool: '#7AA8C9', // ice — info
// Lines
hair005: 'rgba(242,239,230,0.05)',
hair010: 'rgba(242,239,230,0.10)',
hair018: 'rgba(242,239,230,0.18)',
hair030: 'rgba(242,239,230,0.30)',
// Type stacks · v3 · Fraunces (variable serif) + Geist sans
serif: '"Fraunces", "Instrument Serif", "Times New Roman", Georgia, serif',
sans: '"Geist", "Inter", system-ui, -apple-system, sans-serif',
mono: '"JetBrains Mono", "IBM Plex Mono", ui-monospace, monospace',
// Tinted shadows · carry chartreuse hue instead of generic black
shadowSm: '0 2px 8px rgba(0,0,0,0.4), 0 0 24px -8px rgba(197,216,109,0.06)',
shadowMd: '0 8px 24px rgba(0,0,0,0.5), 0 0 40px -12px rgba(197,216,109,0.10)',
shadowLg: '0 24px 60px -16px rgba(0,0,0,0.6), 0 0 80px -16px rgba(197,216,109,0.14)',
shadowXl: '0 40px 100px -24px rgba(0,0,0,0.7), 0 0 120px -24px rgba(197,216,109,0.18)',
// Easing
springEase: 'cubic-bezier(0.34, 1.56, 0.64, 1)', // overshoot — buttons/CTAs
smoothEase: 'cubic-bezier(0.22, 1, 0.36, 1)', // standard ease-out
};
// ── Atoms ──────────────────────────────────────────────────────
const D4Mono = ({ children, accent, dim, muted, size = 11, style = {}, ...p }) => (
{children}
);
const D4Serif = ({ children, italic, size = 56, style = {}, as: Tag = 'span', ...p }) => (
{children}
);
const D4Pip = ({ children, status = 'ON', color = D4P.accent }) => (
{status}
{children && · {children}}
);
const D4Tag = ({ children, color = D4P.accent }) => (
{children}
);
// Logo · ascii-mono mark + lowercase wordmark
const D4Logo = ({ small }) => (
i
iam/marketing
);
// ── Nav ────────────────────────────────────────────────────────
const D4Nav = ({ current, lang = 'EN', mobile }) => {
// Nav consolidated to 5 items + CTA per site-architecture audit.
// Lead magnet, webinar, newsletter collapsed under /resources hub.
const items = [
['ai', 'AI Operator', '/en/ai-operator/'],
['cases', 'Cases', '/en/case-studies/'],
['resources', 'Resources', '/en/resources/'],
['partners', 'Partners', '/en/partners/'],
['about', 'About', '/en/about/'],
];
const [open, setOpen] = React.useState(false);
return (
);
};
// ── Footer ─────────────────────────────────────────────────────
const D4Footer = ({ lang = 'EN', mobile }) => {
const [submitState, setSubmitState] = React.useState('idle'); // idle | submitting | done | error
const [emailValue, setEmailValue] = React.useState('');
// Strict-but-friendly: must look like a real address, not a typo / role / disposable.
const validateEmail = (v) => {
const e = (v || '').trim().toLowerCase();
if (!/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(e)) return 'Format looks off — try operator@company.com';
if (/(^|@)(test|example|disposable|mailinator)\./.test(e)) return 'Use your work address — that one bounces';
return null;
};
const handleSubscribe = (e) => {
e.preventDefault();
if (submitState === 'submitting' || submitState === 'done') return;
const err = validateEmail(emailValue);
if (err) { setSubmitState('error'); return; }
setSubmitState('submitting');
setTimeout(() => setSubmitState('done'), 1100);
};
return (
);
};
// ── Marquee ────────────────────────────────────────────────────
const D4Marquee = ({ items = [], speed = 28, accent, mono, italic }) => {
const text = items.join(' · ');
return (
{[0,1,2].map(i => {text} · )}
);
};
// ── Page shell ─────────────────────────────────────────────────
const D4Page = ({ children, current, lang = 'EN', mobile }) => (
{children}
);
// ── Section primitives ─────────────────────────────────────────
// v2: every D4Section has a scroll-reveal entrance — IntersectionObserver,
// transform+opacity only, premium cubic-bezier, reduced-motion fallback.
const D4Section = ({ children, label, num, dark, full, mobile, id, style = {} }) => {
const ref = React.useRef(null);
const [revealed, setRevealed] = React.useState(false);
React.useEffect(() => {
const el = ref.current;
if (!el) return;
const reduced = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (reduced) { setRevealed(true); return; }
// Above-fold sections reveal immediately (one rAF tick so the transition still plays)
const rect = el.getBoundingClientRect();
if (rect.top < window.innerHeight && rect.bottom > 0) {
const id = requestAnimationFrame(() => setRevealed(true));
return () => cancelAnimationFrame(id);
}
const obs = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setRevealed(true);
obs.disconnect();
}
},
// threshold 0 = fire as soon as ANY part enters the viewport.
// Critical for tall sections (Hero 320vh, DIFF 400vh) where a higher
// ratio threshold would never satisfy and the section would stay at opacity 0.
{ threshold: 0, rootMargin: '0px 0px -12% 0px' }
);
obs.observe(el);
return () => obs.disconnect();
}, []);
// Move A · vertical rotated mono edge label — derived from `num` ("02 · MECHANISM" → "02 — MECHANISM")
const edgeLabel = num ? String(num).replace(' · ', ' — ').toUpperCase() : null;
return (
{edgeLabel && !mobile && (
{edgeLabel}
)}
{(label || num) && !full && (
{num && (() => {
// num arrives like "02 · MECHANISM" — split into editorial § marker + name
const [n, ...rest] = String(num).split(' · ');
const sectionName = rest.join(' · ');
return (
§{n.replace(/^0+/, '') || '0'}
{sectionName && {sectionName}}
);
})()}
{label &&
{label}}
)}
{children}
);
};
// Global motion CSS
(function injectD4Styles() {
if (document.getElementById('d4p-styles')) return;
const s = document.createElement('style');
s.id = 'd4p-styles';
s.textContent = `
@keyframes d4p-pulse { 0%,100%{opacity:1; transform:scale(1)} 50%{opacity:.5; transform:scale(.85)} }
@keyframes d4p-marq { 0%{transform:translateX(0)} 100%{transform:translateX(-33.33%)} }
@keyframes d4p-sweep { 0%{transform:translateX(-100%)} 100%{transform:translateX(100%)} }
@keyframes d4p-blink { 0%,49%,100%{opacity:1} 50%,99%{opacity:0} }
@keyframes d4p-typing { 0%{width:0} 60%,100%{width:100%} }
@keyframes d4p-grain { 0%,100%{transform:translate(0,0)} 25%{transform:translate(-2%,1%)} 50%{transform:translate(1%,-1%)} 75%{transform:translate(-1%,2%)} }
.d4p-pulse { animation: d4p-pulse 1.6s ease-in-out infinite; }
.d4p-blink { animation: d4p-blink 1s steps(1) infinite; }
.d4p-grain::after {
content: ''; position: absolute; inset: -10%; pointer-events: none;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence baseFrequency='0.85' /%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
opacity: 0.06; mix-blend-mode: overlay; animation: d4p-grain 4s steps(4) infinite;
}
@media (prefers-reduced-motion: reduce) {
.d4p-pulse, .d4p-marq, .d4p-blink { animation: none !important; }
}
/* ──── v5+ · EMIL-GRADE STAGE REVEAL ────
Smaller movement at higher quality. translateY(8px) + scale(0.99)
creates depth on entrance without shouting. cubic-bezier(0.16,1,0.3,1)
is Emil's signature ease-out (Sonner/Vaul). 600ms over 1100ms because
smaller movements need shorter durations to feel intentional. */
.d4-stage > * {
opacity: 0;
transform: translateY(8px) scale(0.99);
transition:
opacity 600ms cubic-bezier(0.16, 1, 0.3, 1) calc(var(--rd, 0) * 1ms),
transform 600ms cubic-bezier(0.16, 1, 0.3, 1) calc(var(--rd, 0) * 1ms);
}
.d4-stage > *:nth-child(1) { --rd: 0; }
.d4-stage > *:nth-child(2) { --rd: 80; }
.d4-stage > *:nth-child(3) { --rd: 160; }
.d4-stage > *:nth-child(4) { --rd: 240; }
.d4-stage > *:nth-child(5) { --rd: 320; }
.d4-stage > *:nth-child(6) { --rd: 400; }
.d4-stage > *:nth-child(n+7) { --rd: 480; }
.d4-section.is-revealed .d4-stage > * {
opacity: 1;
transform: translateY(0) scale(1);
}
@media (prefers-reduced-motion: reduce) {
.d4-stage > * { opacity: 1 !important; transform: none !important; transition: none !important; }
}
/* Move A · hide vertical edge labels on narrow viewports (already gated in JS, defensive CSS) */
@media (max-width: 768px) { .d4-edge-label { display: none !important; } }
/* Eliminate 300ms tap delay on touch devices */
button, a, [role="button"] { touch-action: manipulation; }
/* Emil-grade focus rings · layered chartreuse glow instead of hard outline.
Softer, more deliberate, doesn't compete with content like 2px solid does.
Uses box-shadow so it composites cheaply and stacks with existing shadows. */
*:focus-visible {
outline: none;
box-shadow:
0 0 0 2px rgba(197,216,109,0.55),
0 0 0 4px rgba(197,216,109,0.18);
border-radius: inherit;
}
/* Buttons/links with their own background keep the layered glow but no border-radius forcing */
a:focus-visible, button:focus-visible {
box-shadow:
0 0 0 2px rgba(197,216,109,0.55),
0 0 0 4px rgba(197,216,109,0.18),
${D4P.shadowSm};
}
/* Newsletter input — proper :focus-visible state replaces JS border-swap */
.d4-input { outline: none; transition: border-color 160ms ${D4P.smoothEase}; }
.d4-input:focus-visible {
border-color: ${D4P.accent};
box-shadow: 0 0 0 2px rgba(197,216,109,0.40), 0 0 0 4px rgba(197,216,109,0.14);
}
.d4-input::placeholder { color: ${D4P.muted}; }
/* v5 · Emil-grade CTA spring · cubic-bezier(0.32,0.72,0,1) is the Sonner curve.
Single property transition (transform) — never two motions where one will do.
Press feels weighty: scale below 1 + translateY back to baseline. */
.d4-cta-spring { transition: transform 200ms cubic-bezier(0.32, 0.72, 0, 1), box-shadow 240ms ${D4P.smoothEase}; }
.d4-cta-spring:hover { transform: translateY(-1px); box-shadow: ${D4P.shadowLg}; }
.d4-cta-spring:active { transform: translateY(0) scale(0.96); transition-duration: 120ms; }
/* v5 · Bracket links — brackets compress inward on hover, label nudges 1px.
Compositor-only (transform), 220ms cubic-bezier(0.32,0.72,0,1). */
.d4-bracket-link { position: relative; }
.d4-bracket-link .d4-bracket {
display: inline-block;
transition: transform 220ms cubic-bezier(0.32, 0.72, 0, 1);
}
.d4-bracket-link > span:not(.d4-bracket) {
display: inline-block;
transition: transform 220ms cubic-bezier(0.32, 0.72, 0, 1);
}
.d4-bracket-link:hover .d4-bracket:first-of-type { transform: translateX(2px); }
.d4-bracket-link:hover .d4-bracket:last-of-type { transform: translateX(-2px); }
.d4-bracket-link:hover > span:not(.d4-bracket) { transform: translateY(-1px); }
@media (prefers-reduced-motion: reduce) {
.d4-bracket-link .d4-bracket,
.d4-bracket-link > span:not(.d4-bracket) { transition: none !important; transform: none !important; }
.d4-cta-spring { transition: none !important; }
}
/* v5 · numeric polish — opt-in for any data block */
.d4-num { font-variant-numeric: tabular-nums; font-feature-settings: 'tnum' 1, 'lnum' 1; }
/* v5 · subtle alternating tint to break vertical monotony when sections stack */
.d4-section + .d4-section { /* no-op anchor for tooling */ }
/* v5 · physical primary CTA — used by raw /button without .d4-cta-spring class */
.d4-cta-primary { position: relative; transition: transform 240ms ${D4P.springEase}, box-shadow 240ms ${D4P.smoothEase}, background-color 200ms ${D4P.smoothEase}; }
.d4-cta-primary:hover { transform: translateY(-1px); }
.d4-cta-primary:active { transform: translateY(0) scale(0.98); transition-duration: 80ms; }
.d4-cta-primary:disabled { opacity: 0.55; cursor: not-allowed; transform: none; }
/* v3 · Fraunces variable axis · slightly lighter optical weight at display sizes */
.d4-display-serif { font-variation-settings: 'opsz' 144, 'wght' 460; }
/* Scrollbar */
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: ${D4P.base}; }
::-webkit-scrollbar-thumb { background: ${D4P.hair018}; border-radius: 1px; }
::-webkit-scrollbar-thumb:hover { background: ${D4P.accent}; }
`;
document.head.appendChild(s);
})();
Object.assign(window, { D4P, D4Mono, D4Serif, D4Pip, D4Tag, D4Logo, D4Nav, D4Footer, D4Marquee, D4Page, D4Section });