:root {
  --grid-2-col: repeat(2, 1fr);
  --grid-3-col: repeat(3, 1fr);
  --grid-4-col: repeat(4, 1fr);
  --grid-sidebar-left: 280px 1fr;
  --grid-sidebar-right: 1fr 280px;
  --grid-auto-responsive: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
  --color-text: #141412;
  --color-accent: #b4532a;
  --color-border: #DDDDD6;
  --color-primary: #b4532a;
  --color-surface: #F1F1ED;
  --color-footerBg: #141412;
  --color-headerBg: #FAFAF8;
  --color-onAccent: #ffffff;
  --color-textMuted: #5E5E57;
  --color-accentText: #b4532a;
  --color-background: #FAFAF8;
  --color-footerText: #EDEDE8;
  --color-headerText: #141412;
  --color-footerMuted: #969692;
  --color-footerAccent: #bd6a47;
  --easing-bounce: cubic-bezier(0.68, -0.55, 0.265, 1.55);
  --easing-smooth: cubic-bezier(0.23, 1, 0.32, 1);
  --easing-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --easing-ease-in: cubic-bezier(0.4, 0.0, 1, 1);
  --easing-ease-out: cubic-bezier(0.0, 0.0, 0.2, 1);
  --easing-ease-in-out: cubic-bezier(0.4, 0.0, 0.2, 1);
  --motion-duration-base: 560ms;
  --motion-duration-fast: 200ms;
  --motion-duration-slow: 1100ms;
  --motion-ease-emphasis: cubic-bezier(0.25, 0.46, 0.45, 0.94);
  --motion-ease-entrance: cubic-bezier(0.16, 1, 0.3, 1);
  --motion-ease-standard: cubic-bezier(0.22, 0.61, 0.36, 1);
  --motion-reveal-stagger: 0ms;
  --motion-spring-damping: 26;
  --motion-reveal-distance: 8px;
  --motion-scene3d-enabled: false;
  --motion-spring-stiffness: 120;
  --motion-scroll-scene-count: 0;
  --motion-parallax-depth-scale: 0.1;
  --motion-ambient-glow-intensity: 0.08;
  --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1);
  --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
  --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
  --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1);
  --shadow-none: none;
  --spacing-lg: 24px;
  --spacing-md: 16px;
  --spacing-sm: 8px;
  --spacing-xl: 32px;
  --spacing-xs: 4px;
  --spacing-2xl: 48px;
  --spacing-3xl: 64px;
  --spacing-4xl: 96px;
  --spacing-section: clamp(3.5rem, 7vw, 6rem);
  --branding-logo: ;
  --branding-favicon: ;
  --branding-siteName: My Site;
  --duration-fast: 150ms;
  --duration-slow: 500ms;
  --duration-normal: 300ms;
  --duration-slower: 700ms;
  --duration-slowest: 1000ms;
  --fontSize-lg: 1.125rem;
  --fontSize-sm: 0.875rem;
  --fontSize-xl: 1.25rem;
  --fontSize-xs: 0.75rem;
  --fontSize-2xl: 1.5rem;
  --fontSize-3xl: 1.875rem;
  --fontSize-4xl: 2.25rem;
  --fontSize-5xl: 3rem;
  --fontSize-base: 1rem;
  --fontSize-body: 1rem;
  --fontSize-lead: 1.125rem;
  --fontSize-detail: 0.875rem;
  --fontSize-caption: 0.75rem;
  --fontSize-display: clamp(2.25rem, 4vw, 3.5rem);
  --fontSize-cardTitle: 1.25rem;
  --fontSize-sectionHeading: clamp(1.5rem, 2.4vw, 2rem);
  --animation-spin: rxl-spin 1s linear infinite;
  --animation-float: rxl-float 6s ease-in-out infinite;
  --animation-pulse: rxl-pulse 2s ease-in-out infinite;
  --animation-flip-x: rxl-flip-x 0.6s ease-out both;
  --animation-flip-y: rxl-flip-y 0.6s ease-out both;
  --animation-fade-in: rxl-fade-in 0.6s ease-out both;
  --animation-fade-up: rxl-fade-up 0.6s ease-out both;
  --animation-zoom-in: rxl-zoom-in 0.5s ease-out both;
  --animation-slide-up: rxl-slide-up 0.5s ease-out both;
  --animation-zoom-out: rxl-zoom-out 0.5s ease-out both;
  --animation-bounce-in: rxl-bounce-in 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) both;
  --animation-fade-down: rxl-fade-down 0.6s ease-out both;
  --animation-fade-left: rxl-fade-left 0.6s ease-out both;
  --animation-fade-right: rxl-fade-right 0.6s ease-out both;
  --animation-slide-down: rxl-slide-down 0.5s ease-out both;
  --animation-slide-left: rxl-slide-left 0.5s ease-out both;
  --animation-slide-right: rxl-slide-right 0.5s ease-out both;
  --animation-gradient-shift: rxl-gradient-shift 15s ease infinite;
  --fontFamily-body: 'Inter', sans-serif;
  --fontFamily-mono: 'JetBrains Mono', 'Fira Code', monospace;
  --fontFamily-heading: 'Jost', sans-serif;
  --fontWeight-bold: 700;
  --fontWeight-medium: 500;
  --fontWeight-normal: 400;
  --fontWeight-heading: 400;
  --fontWeight-semibold: 600;
  --lineHeight-tight: 1.25;
  --lineHeight-normal: 1.5;
  --lineHeight-relaxed: 1.75;
  --borderRadius-lg: 12px;
  --borderRadius-md: 8px;
  --borderRadius-sm: 4px;
  --borderRadius-xl: 16px;
  --borderRadius-card: 2px;
  --borderRadius-full: 9999px;
  --borderRadius-none: 0;
  --borderRadius-button: 2px;
  --containerWidth-lg: 1024px;
  --containerWidth-md: 768px;
  --containerWidth-sm: 640px;
  --containerWidth-xl: 1280px;
  --color-primaryText: #b4532a;
  --color-onPrimary: #ffffff;
  --color-muted: #5E5E57;
}
:root { --color-muted: var(--color-textMuted); }
:root { --surface-canvas: var(--color-background, #ffffff); --surface-raised: color-mix(in srgb, var(--color-primary) 7%, color-mix(in srgb, black 3%, var(--color-surface, #f8fafc))); --surface-anchor: color-mix(in srgb, var(--color-primary) 72%, black); }
/* Base Reset */
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; }
img { max-width: 100%; height: auto; }
a { color: inherit; }
body { font-family: var(--fontFamily-body); color: var(--color-text); line-height: 1.6; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; font-feature-settings: 'kern','liga'; }
h1, h2, h3, h4, h5, h6 { font-family: var(--fontFamily-heading); font-weight: 600; text-wrap: balance; }
h1 { line-height: 1.08; letter-spacing: -0.015em; }
h2 { line-height: 1.15; letter-spacing: -0.012em; }
h3 { line-height: 1.25; letter-spacing: -0.006em; }
p { text-wrap: pretty; }
/* RampXL Animation Keyframes */
@keyframes rxl-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes rxl-fade-up { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: translateY(0); } }
@keyframes rxl-fade-down { from { opacity: 0; transform: translateY(-24px); } to { opacity: 1; transform: translateY(0); } }
@keyframes rxl-fade-left { from { opacity: 0; transform: translateX(24px); } to { opacity: 1; transform: translateX(0); } }
@keyframes rxl-fade-right { from { opacity: 0; transform: translateX(-24px); } to { opacity: 1; transform: translateX(0); } }
@keyframes rxl-zoom-in { from { opacity: 0; transform: scale(0.9); } to { opacity: 1; transform: scale(1); } }
@keyframes rxl-zoom-out { from { opacity: 0; transform: scale(1.1); } to { opacity: 1; transform: scale(1); } }
@keyframes rxl-slide-up { from { transform: translateY(100%); } to { transform: translateY(0); } }
@keyframes rxl-slide-down { from { transform: translateY(-100%); } to { transform: translateY(0); } }
@keyframes rxl-slide-left { from { transform: translateX(100%); } to { transform: translateX(0); } }
@keyframes rxl-slide-right { from { transform: translateX(-100%); } to { transform: translateX(0); } }
@keyframes rxl-flip-x { from { opacity: 0; transform: perspective(400px) rotateX(90deg); } to { opacity: 1; transform: perspective(400px) rotateX(0); } }
@keyframes rxl-flip-y { from { opacity: 0; transform: perspective(400px) rotateY(90deg); } to { opacity: 1; transform: perspective(400px) rotateY(0); } }
@keyframes rxl-bounce-in { from { opacity: 0; transform: scale(0.3); } 50% { transform: scale(1.05); } 70% { transform: scale(0.9); } to { opacity: 1; transform: scale(1); } }
@keyframes rxl-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
@keyframes rxl-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
@keyframes rxl-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-10px); } }
/* Scroll animation: hidden until in viewport — ONLY when JS is active.
   The hidden state is gated on html.rxl-js (added before paint by the motion boot
   script) so that with NO JS / a blocked or failed reveal script the content is
   visible by default (progressive enhancement — never a permanently-blank page). */
html.rxl-js [data-animate] { transform: translateY(18px); transition: transform 0.7s cubic-bezier(0.16,1,0.3,1); will-change: transform; }
[data-animate].rxl-visible { transform: none; }
@media (prefers-reduced-motion: reduce) { [data-animate] { transform: none !important; animation: none !important; transition: none !important; } }
/* Scroll entrance animations (Story 2.5) — triggered by Intersection Observer.
   Reveal distance + duration are driven by the brand-derived motion token layer
   (Slice 2): --motion-reveal-distance and --motion-duration-base, emitted as
   :root vars by TokenResolver from the selected signature's preset. Swapping a
   signature reskins every reveal. All keyframes are transform/opacity-only
   (CLS-safe). Fallbacks keep these valid for documents compiled without the
   motion token category. */
/* Transform-only entrance keyframes: content is ALWAYS opaque (legible even if a
   reveal is missed); only the position/scale animates. Robust by construction —
   a missed reveal can never leave a section faint or blank. */
/* Reveal distances are intentionally MORE PRONOUNCED than a bare hairline so the
   staggered cascade reads as motion on the page (operator: "still feels static").
   Still transform-only (content stays opaque, legible if a reveal is ever missed),
   still CLS-safe. A subtle scale on the primary fade adds a "settle" beat. */
@keyframes rxl-entrance-fade-in { from { transform: translateY(26px) scale(0.985); } to { transform: translateY(0) scale(1); } }
@keyframes rxl-entrance-slide-up { from { transform: translateY(var(--motion-reveal-distance, 48px)); } to { transform: translateY(0); } }
@keyframes rxl-entrance-fade-up { from { transform: translateY(var(--motion-reveal-distance, 32px)); } to { transform: translateY(0); } }
@keyframes rxl-entrance-slide-in-left { from { transform: translateX(calc(-1 * var(--motion-reveal-distance, 48px))); } to { transform: translateX(0); } }
@keyframes rxl-entrance-zoom-in { from { transform: scale(0.94); } to { transform: scale(1); } }
/* The base hidden state (until the in-view class lands) is a clearly-felt 28px
   drop with a longer eased settle — a visible cascade, not a 1px nudge. */
html.rxl-js [data-animation] { transform: translateY(32px); transition: transform 0.95s cubic-bezier(0.22,1,0.36,1); will-change: transform; }
[data-animation].anim-play { transform: none; }
[data-animation="fade"].anim-play,
[data-animation="fade-in"].anim-play { animation: rxl-entrance-fade-in var(--rxl-anim-dur, var(--motion-duration-base, 0.6s)) var(--motion-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1)) both; }
[data-animation="slideUp"].anim-play,
[data-animation="slide-up"].anim-play { animation: rxl-entrance-slide-up var(--rxl-anim-dur, var(--motion-duration-base, 0.6s)) var(--motion-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1)) both; }
[data-animation="fade-up"].anim-play { animation: rxl-entrance-fade-up var(--rxl-anim-dur, var(--motion-duration-base, 0.6s)) var(--motion-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1)) both; }
[data-animation="slide-in-left"].anim-play { animation: rxl-entrance-slide-in-left var(--rxl-anim-dur, var(--motion-duration-base, 0.6s)) var(--motion-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1)) both; }
[data-animation="zoom-in"].anim-play { animation: rxl-entrance-zoom-in var(--rxl-anim-dur, var(--motion-duration-base, 0.6s)) var(--motion-ease-entrance, cubic-bezier(0.22, 1, 0.36, 1)) both; }
/* S2 (judge finding: "a white gutter down the band's left edge"): a FULL-BLEED
   band (a top-level <section>) must never SCALE or slide HORIZONTALLY on entry —
   at 1440px a scale(0.985) start paints ~10px background slivers down both edges
   on every real scroll (and freezes into captures). Bands take the translate-only
   vertical entrance; INNER blocks keep the scale "settle" beat. */
section[data-animation="fade"].anim-play,
section[data-animation="fade-in"].anim-play,
section[data-animation="slide-in-left"].anim-play,
section[data-animation="zoom-in"].anim-play { animation-name: rxl-entrance-fade-up; }
/* ── Frontier: native CSS scroll-driven reveals (progressive enhancement) ──────────
   Where the browser supports a view() timeline, drive the SAME transform-only entrance
   keyframes off the element's own scroll position — compositor-thread, ZERO per-element
   JS, no IntersectionObserver callbacks. This is how a STATIC RampXL site out-performs a
   heavy-JS-animation competitor on Core Web Vitals while matching the feel. The JS
   .anim-play path above is the FALLBACK for browsers without it; these rules win by
   specificity when supported (so no double-animation). Still gated on html.rxl-js (no JS
   -> content visible), still transform-only (CLS-safe), still neutralized by the
   prefers-reduced-motion block below. animation-range completes as the element enters so
   it reveals on the way in and holds (fill: both). */
@supports (animation-timeline: view()) {
  html.rxl-js [data-animation] { transition: none; }
  html.rxl-js [data-animation="fade"], html.rxl-js [data-animation="fade-in"] { animation: rxl-entrance-fade-in both; animation-timeline: view(); animation-range: entry 5% cover 32%; }
  html.rxl-js [data-animation="slideUp"], html.rxl-js [data-animation="slide-up"] { animation: rxl-entrance-slide-up both; animation-timeline: view(); animation-range: entry 5% cover 32%; }
  html.rxl-js [data-animation="fade-up"] { animation: rxl-entrance-fade-up both; animation-timeline: view(); animation-range: entry 5% cover 32%; }
  html.rxl-js [data-animation="slide-in-left"] { animation: rxl-entrance-slide-in-left both; animation-timeline: view(); animation-range: entry 5% cover 32%; }
  html.rxl-js [data-animation="zoom-in"] { animation: rxl-entrance-zoom-in both; animation-timeline: view(); animation-range: entry 5% cover 32%; }
  /* S2: the full-bleed-band override for the scroll-driven path too (specificity
     beats the generic attribute rules above; timeline/range are inherited from
     the shorthand these extend). */
  html.rxl-js section[data-animation="fade"],
  html.rxl-js section[data-animation="fade-in"],
  html.rxl-js section[data-animation="slide-in-left"],
  html.rxl-js section[data-animation="zoom-in"] { animation-name: rxl-entrance-fade-up; }
}
@media (prefers-reduced-motion: reduce) { [data-animation] { opacity: 1 !important; transform: none !important; animation: none !important; transition: none !important; } }
/* Immersive decorative ambience (kinetic hero). PURELY DECORATIVE — these markers
   never hide content (no opacity:0 gate), animate transform/background-position
   only (CLS-safe), and are fully disabled under prefers-reduced-motion. They run
   with or without JS (no rxl-js gate) so the layered hero looks alive even with a
   blocked reveal script. */
@keyframes rxl-mesh-shift { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } }
@keyframes rxl-float { 0%, 100% { transform: translate3d(0,0,0); } 50% { transform: translate3d(0,-14px,0); } }
@keyframes rxl-glow-pulse { 0%, 100% { opacity: .5; } 50% { opacity: .85; } }
/* A slow ambient DRIFT for decorative texture layers (e.g. a dark band's dot grid):
   a gentle translate + scale loop so the texture breathes instead of sitting dead.
   Transform-only (CLS-safe), low amplitude, long period — premium, not busy. */
@keyframes rxl-drift { 0%, 100% { transform: translate3d(0,0,0) scale(1); } 50% { transform: translate3d(14px,-12px,0) scale(1.04); } }
[data-mesh] { background-size: 200% 200%; animation: rxl-mesh-shift 26s ease-in-out infinite; will-change: background-position; }
[data-floataccent] { animation: rxl-float 9s ease-in-out infinite; will-change: transform; }
[data-glow] { animation: rxl-glow-pulse 7s ease-in-out infinite; }
[data-drift] { animation: rxl-drift 30s ease-in-out infinite; will-change: transform; }
@media (prefers-reduced-motion: reduce) { [data-mesh], [data-floataccent], [data-glow], [data-drift] { animation: none !important; } }
@view-transition { navigation: auto; }
@media (prefers-reduced-motion: reduce) { ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; } }
[data-below-fold] { content-visibility: auto; contain-intrinsic-size: auto 760px; }
h1, h2, h3, h4, h5, h6, [id] { scroll-margin-top: 80px; }
