/* ==========================================================================
   Sam Studio — bundled stylesheet
   Auto-generated by concatenating the AETHER core/patterns modules plus
   this project's own site.css, in their original cascade order, into a
   single file — replacing ~25 chained @import requests with one.
   Source modules remain in css/aether/ for reference and future edits;
   re-run the same concatenation after changing any of them.
   Google Fonts / Fontshare @import removed from base/_typography.css —
   moved to <link rel="preconnect">+<link rel="stylesheet"> in each
   page's <head>, loaded in parallel instead of discovered mid-cascade.
   ========================================================================== */


/* ---- source: css/aether/core/tokens/_variables.css ---- */
/* ==========================================================================
   AETHER UI — Design Tokens
   "Building the future while studying the wisdom of the past."

   Every visual decision in the system traces back to a token defined here.
   Components never hardcode a color, size, or timing value — they reference
   a token. That's what makes the system feel like one coherent object
   instead of a pile of pages that happen to share a stylesheet.
   ========================================================================== */

:root {
  /* --------------------------------------------------------------------
     1. COLOR — raw scales
     Each scale runs 50 (lightest) → 950 (darkest/most saturated). Raw
     scale tokens are implementation detail; components should consume the
     SEMANTIC tokens in section 1b, not these directly. The scales exist so
     semantic tokens have somewhere to point, and so we can add new
     semantic tokens later without inventing new colors.
     -------------------------------------------------------------------- */

  /* Void — the navy the entire system floats on. 950 is Sam Studio's
     verified brand navy (matches the logo); every lighter step is a
     color-mix formula off that one anchor rather than a hand-picked hex,
     so the whole ladder stays consistent if the anchor ever changes.
     Never pure #000: true black kills the "depth" the observatory-at-
     night mood depends on. */
  --aether-void-950: #0a1830;
  --aether-void-900: color-mix(in oklch, var(--aether-void-950) 92%, white 8%);
  --aether-void-800: color-mix(in oklch, var(--aether-void-950) 84%, white 16%);
  --aether-void-700: color-mix(in oklch, var(--aether-void-950) 76%, white 24%);
  --aether-void-600: color-mix(in oklch, var(--aether-void-950) 66%, white 34%);
  --aether-void-500: color-mix(in oklch, var(--aether-void-950) 55%, white 45%);
  --aether-void-400: color-mix(in oklch, var(--aether-void-950) 40%, white 60%);
  --aether-void-300: color-mix(in oklch, var(--aether-void-950) 24%, white 76%);

  /* Royal blue — technology, intelligence, forward motion */
  --aether-blue-950: #0a1550;
  --aether-blue-900: #101f6e;
  --aether-blue-800: #162c93;
  --aether-blue-700: #1d3ab8;
  --aether-blue-600: #2947d6;
  --aether-blue-500: #3b5bff;
  --aether-blue-400: #6480ff;
  --aether-blue-300: #93a8ff;
  --aether-blue-200: #c2ceff;
  --aether-blue-100: #e2e7ff;

  /* Deep purple — depth, philosophy, the "night sky" half of the mood */
  --aether-violet-950: #170b3d;
  --aether-violet-900: #241357;
  --aether-violet-800: #351d7c;
  --aether-violet-700: #4827a3;
  --aether-violet-600: #5c34c4;
  --aether-violet-500: #7548e0;
  --aether-violet-400: #9770ea;
  --aether-violet-300: #b89bf1;
  --aether-violet-200: #d8c6f8;

  /* Gold — wisdom, craftsmanship, the one warm note in a cold palette.
     Kept antique/muted on purpose: bright yellow-gold reads as "cheap
     award badge," not "premium." */
  --aether-gold-900: #4a3512;
  --aether-gold-700: #83621f;
  --aether-gold-600: #a67e2b;
  --aether-gold-500: #c6a15b;
  --aether-gold-400: #d8b876;
  --aether-gold-300: #e8cf9c;
  --aether-gold-200: #f2e3c2;

  /* Neutrals — cool, slightly blue-shifted grays so they never fight the
     navy background the way true-gray (#888) does. */
  --aether-gray-950: #0c0f16;
  --aether-gray-900: #12151f;
  --aether-gray-800: #1b1f2c;
  --aether-gray-700: #2a2f40;
  --aether-gray-600: #3d4358;
  --aether-gray-500: #5a6178;
  --aether-gray-400: #7c8299;
  --aether-gray-300: #a3a9bd;
  --aether-gray-200: #c7cbdb;
  --aether-gray-100: #e4e6f0;
  --aether-gray-50: #f5f6fa;

  /* --------------------------------------------------------------------
     1b. COLOR — semantic tokens
     Components and utilities consume ONLY these. If a new component needs
     a color that isn't here, that's a sign to add a semantic token, not to
     reach for a raw scale value.
     -------------------------------------------------------------------- */

  /* Surfaces — the canvas, then three numbered elevation tiers.
     --aether-bg is the page itself (nothing sits "under" it). Every
     raised surface above that picks one of three tiers by how far off
     the canvas it sits, not by what component it happens to be:

       surface-1  first lift off the canvas — page-level cards, panels
       surface-2  content nested inside a surface-1 — a card inside a
                  card, an active tab panel, a dropdown menu
       surface-3  the highest resting elevation — modals, popovers,
                  toasts, tooltips: things that float above everything

     Each tier is exactly one --aether-void-* step lighter than the
     last, and each tier's hover state is one more step lighter again —
     a single continuous ladder, not three unrelated decisions. Themes
     re-tune the whole ladder at once (see _themes.css) rather than
     touching tiers individually. */
  --aether-bg: var(--aether-void-950);
  --aether-surface-1: var(--aether-void-800);
  --aether-surface-1-hover: var(--aether-void-700);
  --aether-surface-2: var(--aether-void-700);
  --aether-surface-2-hover: var(--aether-void-600);
  --aether-surface-3: var(--aether-void-600);
  --aether-surface-3-hover: var(--aether-void-500);

  --aether-border: var(--aether-void-400);
  --aether-border-strong: var(--aether-void-300);

  /* Brand */
  --aether-primary: var(--aether-blue-500);
  --aether-primary-hover: var(--aether-blue-400);
  --aether-primary-active: var(--aether-blue-600);
  --aether-secondary: var(--aether-violet-500);
  --aether-secondary-hover: var(--aether-violet-400);
  --aether-accent: var(--aether-gold-500);
  --aether-accent-hover: var(--aether-gold-400);

  /* Separate from --aether-accent on purpose: accent covers every "gold
     highlight" use (badges, quote marks, eyebrow labels), while --cta is
     specifically "the color of the button that makes money." They point
     to the same value by default, but a theme is free to split them —
     Commerce does, to make checkout buttons punchier without also
     making every small gold accent in the UI louder. */
  --aether-cta: var(--aether-accent);
  --aether-cta-hover: var(--aether-accent-hover);

  /* Text */
  --aether-text: var(--aether-gray-50);
  --aether-text-muted: var(--aether-gray-400);
  --aether-text-faint: var(--aether-gray-600);

  /* Text-on-color pairings — kept explicit per background rather than
     computed, so contrast can be checked and guaranteed AA rather than
     assumed. Themes that remap primary/secondary/accent to a different
     lightness MUST re-check (and if needed override) these three. */
  --aether-text-on-primary: var(--aether-gray-50);
  --aether-text-on-secondary: var(--aether-gray-50);
  --aether-text-on-accent: var(--aether-void-950);

  /* Feedback — desaturated enough to sit quietly in a dark UI. Hover
     states are derived via color-mix() (darken toward black) rather than
     hand-picked hex, the same formula-over-value approach as everything
     else in this file — keeps these self-consistent with the rest of the
     palette instead of being four one-off guesses. */
  --aether-success: #4ad9a3;
  --aether-success-hover: color-mix(in oklch, var(--aether-success) 85%, black 15%);
  --aether-warning: var(--aether-gold-500);
  --aether-warning-hover: var(--aether-gold-400);
  --aether-danger: #ef5b6b;
  --aether-danger-hover: color-mix(in oklch, var(--aether-danger) 85%, black 15%);
  --aether-info: var(--aether-blue-400);
  --aether-info-hover: var(--aether-blue-300);

  /* Text color for badges/alerts/buttons sitting on a feedback color —
     same value as --aether-text-on-primary, named separately because the
     pairing is semantically "on feedback," not "on brand." */
  --aether-text-on-feedback: var(--aether-gray-50);

  /* --------------------------------------------------------------------
     2. TYPOGRAPHY
     -------------------------------------------------------------------- */

  /* Serif for headings: carries the "wisdom / philosophy / editorial"
     register. Fraunces is used deliberately over the Playfair/Cormorant
     pairing every "elegant" template reaches for — its soft, slightly
     wonky optical curves read as considered rather than decorative. */
  --aether-font-heading: 'Fraunces', 'Iowan Old Style', 'Georgia', serif;

  /* Sans for body: Satoshi over Inter on purpose. Inter is the default
     face of every SaaS/AI landing page in 2026 — using it is the fastest
     way to look like a template. Satoshi keeps the geometric-clean
     legibility but has a warmer, more distinct personality. */
  --aether-font-body: 'Satoshi', 'General Sans', -apple-system, 'Segoe UI', sans-serif;

  /* Mono for code / data / technical labels */
  --aether-font-mono: 'JetBrains Mono', 'IBM Plex Mono', ui-monospace, 'SFMono-Regular', monospace;

  /* Fluid type scale — clamp(min, preferred, max). Preferred term uses vw
     so text scales smoothly between breakpoints instead of jumping at
     fixed media-query lines. Ratio ~1.25 (major third) between steps. */
  --aether-text-xs: clamp(0.75rem, 0.71rem + 0.2vw, 0.8rem);
  --aether-text-sm: clamp(0.875rem, 0.83rem + 0.22vw, 0.95rem);
  --aether-text-base: clamp(1rem, 0.94rem + 0.3vw, 1.125rem);
  --aether-text-md: clamp(1.125rem, 1.05rem + 0.35vw, 1.3rem);
  --aether-text-lg: clamp(1.3rem, 1.18rem + 0.6vw, 1.6rem);
  --aether-text-xl: clamp(1.6rem, 1.4rem + 1vw, 2.1rem);
  --aether-text-2xl: clamp(2rem, 1.7rem + 1.5vw, 2.75rem);
  --aether-text-3xl: clamp(2.5rem, 2.05rem + 2.25vw, 3.6rem);
  --aether-text-4xl: clamp(3.1rem, 2.4rem + 3.5vw, 4.75rem);
  --aether-text-5xl: clamp(3.8rem, 2.8rem + 5vw, 6.25rem);

  --aether-leading-tight: 1.1;
  --aether-leading-snug: 1.3;
  --aether-leading-normal: 1.6;
  --aether-leading-relaxed: 1.8;

  --aether-tracking-tight: -0.03em;
  --aether-tracking-normal: 0;
  --aether-tracking-wide: 0.04em;
  --aether-tracking-widest: 0.15em;

  --aether-weight-regular: 400;
  --aether-weight-medium: 500;
  --aether-weight-semibold: 600;
  --aether-weight-bold: 700;

  /* --------------------------------------------------------------------
     3. SPACING — 4px base unit. Referenced by every margin/padding/gap
     in the system so rhythm stays consistent across components.
     -------------------------------------------------------------------- */
  --aether-space-0: 0;
  --aether-space-1: 0.25rem;  /* 4px  */
  --aether-space-2: 0.5rem;   /* 8px  */
  --aether-space-3: 0.75rem;  /* 12px */
  --aether-space-4: 1rem;     /* 16px */
  --aether-space-5: 1.25rem;  /* 20px */
  --aether-space-6: 1.5rem;   /* 24px */
  --aether-space-8: 2rem;     /* 32px */
  --aether-space-10: 2.5rem;  /* 40px */
  --aether-space-12: 3rem;    /* 48px */
  --aether-space-16: 4rem;    /* 64px */
  --aether-space-20: 5rem;    /* 80px */
  --aether-space-24: 6rem;    /* 96px */
  --aether-space-32: 8rem;    /* 128px */
  --aether-space-40: 10rem;   /* 160px */

  /* --------------------------------------------------------------------
     4. LAYOUT
     Tokens only — Phase 2 (the Aether Layout Engine) is what turns these
     into actual .container/.section classes. Defined now so that work
     has a settled scale to build against instead of inventing pixel
     values in-flight.
     -------------------------------------------------------------------- */

  /* Container widths — the max-width ceiling of the outer layout shell.
     Deliberately its own scale rather than reusing --aether-bp-* — a
     container is meant to sit narrower than the viewport it lives in,
     leaving room for a gutter, so the two scales diverge by design even
     though they rhyme. */
  --aether-container-sm: 40rem;   /* 640px  — narrow content, auth forms */
  --aether-container-md: 48rem;   /* 768px  — article/reading layouts */
  --aether-container-lg: 64rem;   /* 1024px — standard page content */
  --aether-container-xl: 80rem;   /* 1280px — dashboards, wide layouts */
  --aether-container-2xl: 90rem;  /* 1440px — deliberate ceiling: wider
                                      than this and body copy starts
                                      reading as a spreadsheet, not a
                                      premium page */

  /* Content widths — optimal reading measure, in ch (character-width)
     units so it scales with font choice/size rather than viewport.
     Distinct from container widths: a container bounds a whole layout
     region, a content width bounds one column of prose inside it. */
  --aether-content-width-narrow: 45ch; /* captions, card copy, sidebars */
  --aether-content-width-normal: 68ch; /* body copy — the system default */
  --aether-content-width-wide: 85ch;   /* long-form editorial/blog */

  /* Section spacing — vertical rhythm between major page sections. A
     named *subset* of the spacing scale (not new raw values), so
     section rhythm always stays a clean multiple of the 4px base unit
     rather than drifting into arbitrary numbers over time. */
  --aether-section-spacing-sm: var(--aether-space-12); /* 48px  — tight, dashboard-density */
  --aether-section-spacing-md: var(--aether-space-20); /* 80px  — default */
  --aether-section-spacing-lg: var(--aether-space-32); /* 128px — hero-scale */
  --aether-section-spacing-xl: var(--aether-space-40); /* 160px — landing-page hero ceiling */

  /* --------------------------------------------------------------------
     5. RADIUS
     -------------------------------------------------------------------- */
  --aether-radius-sm: 6px;
  --aether-radius-md: 10px;
  --aether-radius-lg: 16px;
  --aether-radius-xl: 24px;
  --aether-radius-2xl: 32px;
  --aether-radius-full: 999px;

  /* --------------------------------------------------------------------
     6. SHADOW & GLOW
     Elevation shadows stay neutral (black-based); glows carry brand color
     via color-mix() so they always match whatever theme values above
     resolve to, instead of hardcoded rgba duplicates going stale.
     -------------------------------------------------------------------- */
  --aether-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
  --aether-shadow-md: 0 4px 16px rgba(0, 0, 0, 0.45);
  --aether-shadow-lg: 0 12px 40px rgba(0, 0, 0, 0.5);
  --aether-shadow-xl: 0 24px 70px rgba(0, 0, 0, 0.55);

  /* Glow is a *formula*, not a fixed value: color comes from whatever
     --aether-primary/secondary/accent currently resolve to, intensity
     comes from --aether-glow-strength, and spread comes from
     --aether-glow-blur. Themes override the two knobs (strength/blur)
     instead of redefining the shadow itself — a "restrained" theme like
     Business turns the knob down, a "expressive" one like Spiritual turns
     it up, and both stay perfectly in sync with their theme's colors.

     Deliberately NOT pre-assembled into a --aether-glow-primary-style
     composite token here. A custom property that itself contains var()
     references gets resolved once, at whichever element actually
     DECLARES it — if nothing overrides that same property further down
     the tree, descendants inherit the already-resolved result, not a
     live formula. That's invisible when a theme is applied to <html>
     (the composite and its ingredients resolve on the same element), but
     breaks the moment a theme is scoped to a subtree instead: a button
     inside <section data-theme="business"> would still see the ROOT's
     glow (wrong strength/blur/color), because nothing on that section
     redeclared the composite itself. Every consumer below (utilities,
     button, card) writes the box-shadow formula out directly instead —
     three real var() reads at the point of use, each resolving against
     whatever element it's actually on, correct at any nesting depth. */
  --aether-glow-strength: 45%;
  --aether-glow-blur: 40px;

  /* --------------------------------------------------------------------
     7. MOTION
     Motion should feel expensive: slower than default browser instincts,
     eased with curves that decelerate rather than linear or bouncy. Named
     after intent (what the motion is FOR) rather than shape, so a
     component author picks "emphasized" for a thing that should draw the
     eye without needing to know what a cubic-bezier curve does.
     -------------------------------------------------------------------- */

  /* Durations */
  --aether-duration-instant: 100ms;  /* micro-feedback: checkbox, toggle */
  --aether-duration-fast: 150ms;     /* hover states, small UI */
  --aether-duration-base: 250ms;     /* default — most transitions */
  --aether-duration-slow: 450ms;     /* panels, dropdowns, reveals */
  --aether-duration-slower: 800ms;   /* hero/scroll reveals */
  --aether-duration-slowest: 1200ms; /* full page transitions (Phase 4) */

  /* Easings — three registers, each with a job:
       standard   — safe default, symmetric, unremarkable on purpose
       smooth     — gentle ease-in-out for ambient/background motion
                    (floating elements, slow pulses) that should never
                    feel mechanical
       emphasized — decisive, front-loaded deceleration for anything that
                    should draw the eye (modals opening, hero elements,
                    page transitions). Split into enter/exit variants
                    because "arriving" and "leaving" read differently:
                    entrances decelerate hard, exits accelerate away. */
  --aether-ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
  --aether-ease-smooth: cubic-bezier(0.25, 0.1, 0.25, 1);
  --aether-ease-emphasized: cubic-bezier(0.16, 1, 0.3, 1);
  --aether-ease-emphasized-decelerate: cubic-bezier(0.05, 0.7, 0.1, 1);
  --aether-ease-emphasized-accelerate: cubic-bezier(0.3, 0, 0.8, 0.15);
  --aether-ease-in-out-quart: cubic-bezier(0.76, 0, 0.24, 1);

  /* Ready-to-use composites — duration + easing, so most components never
     touch the raw tokens above directly. */
  --aether-transition-fast: var(--aether-duration-fast) var(--aether-ease-standard);
  --aether-transition-base: var(--aether-duration-base) var(--aether-ease-standard);
  --aether-transition-slow: var(--aether-duration-slow) var(--aether-ease-smooth);
  --aether-transition-emphasized: var(--aether-duration-slow) var(--aether-ease-emphasized);

  /* --------------------------------------------------------------------
     8. GLASS
     Shared recipe for the frosted-glass surfaces used across cards, nav,
     and modals — centralized so "glass" looks identical everywhere.
     -------------------------------------------------------------------- */
  --aether-glass-bg: color-mix(in oklch, var(--aether-void-700) 55%, transparent);
  --aether-glass-border: color-mix(in oklch, var(--aether-gray-50) 12%, transparent);
  --aether-glass-blur: 20px;

  /* --------------------------------------------------------------------
     9. Z-INDEX SCALE
     Named layers prevent the classic "z-index: 9999" arms race.
     -------------------------------------------------------------------- */
  --aether-z-dropdown: 100;
  --aether-z-sticky: 200;
  --aether-z-overlay: 300;
  --aether-z-modal: 400;
  --aether-z-toast: 500;
  --aether-z-tooltip: 600;

  /* --------------------------------------------------------------------
     10. ACCESSIBILITY
     Tokens consumed by core/base/_accessibility.css. Kept here
     rather than hardcoded there so themes can adjust them too (e.g. a
     theme could widen the focus ring without touching the a11y file).
     -------------------------------------------------------------------- */
  --aether-focus-ring-width: 2px;
  --aether-focus-ring-offset: 3px;
  --aether-focus-ring-color: var(--aether-primary-hover);

  /* WCAG 2.5.5 (AAA) minimum — every clickable target should be at least
     this tall/wide, padding included. */
  --aether-tap-target-min: 2.75rem; /* 44px */
}

/* --------------------------------------------------------------------
   11. BREAKPOINTS
   CSS custom properties can't be interpolated inside @media conditions,
   so these values are documented here as the single source of truth and
   hand-copied into media queries throughout the system. They're also
   exposed as unitless custom properties so JavaScript can read them via
   getComputedStyle() and stay in sync without a second source of truth.

     --aether-bp-sm : 480px   phones (landscape)
     --aether-bp-md : 768px   tablets
     --aether-bp-lg : 1024px  small laptops
     --aether-bp-xl : 1280px  desktops
     --aether-bp-2xl: 1536px  large desktops
   -------------------------------------------------------------------- */
:root {
  --aether-bp-sm: 480;
  --aether-bp-md: 768;
  --aether-bp-lg: 1024;
  --aether-bp-xl: 1280;
  --aether-bp-2xl: 1536;
}

/* ---- source: css/aether/core/themes/_themes.css ---- */
/* ==========================================================================
   AETHER UI — Themes
   One system, four personalities. Components are built against SEMANTIC
   tokens only (--aether-primary, --aether-surface-1, --aether-glow-strength,
   etc.) — never against raw color scales or literal values. That
   indirection is what makes this file possible: a theme block just
   re-points the semantic tokens, and every component built in later
   phases re-skins for free, with zero component-level changes.

   USAGE
   Apply to <html> for a whole site, or to any subtree for a themed
   section within an otherwise-default page (custom properties inherit):

     <html data-theme="business">          whole site
     <section data-theme="commerce">...    just this section

   No attribute = the default "Portfolio" identity defined at :root in
   _variables.css (the moody, expressive, gold-accented observatory mood
   from Phase 1). It never needs its own [data-theme="portfolio"] block —
   that IS the root definition.

   RULE FOR ADDING A NEW THEME
   Override semantic tokens only. Reach for the existing raw scales
   (--aether-blue-*, --aether-violet-*, --aether-gold-*, --aether-void-*)
   and color-mix() between them — never introduce a new hex value here.
   That constraint is what keeps four "personalities" reading as one
   family instead of four unrelated sites that happen to share a
   stylesheet.
   ========================================================================== */

/* --------------------------------------------------------------------
   BUSINESS — Stripe-register: structured, restrained, trustworthy.
   Same blue, but the violet and gold roles get demoted to "used
   sparingly" rather than "expressive." Tighter radii read as more
   engineered; a quieter glow and shallower glass read as more serious.
   -------------------------------------------------------------------- */
[data-theme='business'] {
  /* Shifts the whole surface ladder one void-step darker/flatter than
     Portfolio's — less separation between elevation tiers reads as more
     structured/enterprise, less "expressive stack of floating panels." */
  --aether-surface-1: var(--aether-void-900);
  --aether-surface-1-hover: var(--aether-void-800);
  --aether-surface-2: var(--aether-void-800);
  --aether-surface-2-hover: var(--aether-void-700);
  --aether-surface-3: var(--aether-void-700);
  --aether-surface-3-hover: var(--aether-void-600);

  --aether-secondary: var(--aether-violet-700);
  --aether-secondary-hover: var(--aether-violet-600);
  --aether-accent: var(--aether-gold-600);
  --aether-accent-hover: var(--aether-gold-500);

  /* Business doesn't want CTA to diverge from accent the way Commerce
     does — but --aether-cta is still its own token (declared once, at
     :root, as `var(--aether-accent)`), so it has to be redeclared here
     explicitly to pick up the accent override above. A custom property
     that isn't redeclared on this element inherits its value already
     resolved from whichever ancestor DID declare it — in a scoped
     `<section data-theme="business">` usage, that ancestor is :root, not
     this block, so skipping this line would silently leave CTA buttons
     on Portfolio's gold instead of Business's. See the note on
     --aether-glow-strength in _variables.css for the general version of
     this gotcha. */
  --aether-cta: var(--aether-accent);
  --aether-cta-hover: var(--aether-accent-hover);

  --aether-radius-lg: 12px;
  --aether-radius-xl: 16px;
  --aether-radius-2xl: 20px;

  --aether-glow-strength: 22%;
  --aether-glow-blur: 28px;
  --aether-glass-blur: 12px;
}

/* --------------------------------------------------------------------
   COMMERCE — warmer and more persuasive. Gold is promoted from "quiet
   premium accent" to "the color that sells" via --aether-cta, radii
   soften up (friendlier, more huggable product cards), and the glow
   comes back up from Business's restraint to give hero products and
   pricing moments some sparkle.
   -------------------------------------------------------------------- */
[data-theme='commerce'] {
  --aether-accent: var(--aether-gold-400);
  --aether-accent-hover: var(--aether-gold-300);
  --aether-cta: var(--aether-gold-400);
  --aether-cta-hover: var(--aether-gold-300);

  --aether-radius-lg: 20px;
  --aether-radius-xl: 28px;
  --aether-radius-2xl: 36px;

  --aether-glow-strength: 32%;
  --aether-glow-blur: 36px;
}

/* --------------------------------------------------------------------
   SPIRITUAL — introspective, philosophical, slower. Violet moves from
   "secondary depth color" to leading the palette, the background itself
   is warmed with a violet undertone (color-mix, not a new hex), radii go
   fully soft/organic, the glow turns diffuse and ethereal (lower
   precision, wider blur), and reading rhythm loosens — more line-height,
   slightly more letter-spacing — for contemplative long-form pages.
   -------------------------------------------------------------------- */
[data-theme='spiritual'] {
  --aether-bg: color-mix(in oklch, var(--aether-void-950) 80%, var(--aether-violet-950) 20%);

  /* Same void-step ladder as Portfolio, with a consistent violet tint
     mixed through every tier — depth that reads as dusk, not just dark. */
  --aether-surface-1: color-mix(in oklch, var(--aether-void-800) 78%, var(--aether-violet-900) 22%);
  --aether-surface-1-hover: color-mix(in oklch, var(--aether-void-700) 78%, var(--aether-violet-800) 22%);
  --aether-surface-2: color-mix(in oklch, var(--aether-void-700) 78%, var(--aether-violet-800) 22%);
  --aether-surface-2-hover: color-mix(in oklch, var(--aether-void-600) 78%, var(--aether-violet-700) 22%);
  --aether-surface-3: color-mix(in oklch, var(--aether-void-600) 78%, var(--aether-violet-700) 22%);
  --aether-surface-3-hover: color-mix(in oklch, var(--aether-void-500) 78%, var(--aether-violet-600) 22%);

  --aether-primary: var(--aether-violet-500);
  --aether-primary-hover: var(--aether-violet-400);
  --aether-primary-active: var(--aether-violet-600);
  --aether-secondary: var(--aether-blue-500);
  --aether-secondary-hover: var(--aether-blue-400);
  --aether-accent: var(--aether-gold-400);
  --aether-accent-hover: var(--aether-gold-300);
  --aether-cta: var(--aether-gold-400);
  --aether-cta-hover: var(--aether-gold-300);

  --aether-radius-lg: 20px;
  --aether-radius-xl: 32px;
  --aether-radius-2xl: 40px;

  --aether-glow-strength: 55%;
  --aether-glow-blur: 64px;

  --aether-leading-relaxed: 1.9;
  --aether-tracking-wide: 0.06em;
}

/* --------------------------------------------------------------------
   DAYLIGHT — the first theme in this file that's actually light, not a
   tinted variant of the dark base. Every other theme above only retunes
   surface/accent/radius/glow; this one redefines bg, the surface ladder,
   text, and border from scratch, because there's no dark ancestor value
   worth inheriting on a light ground.

   Two colors do double duty across the whole system, deliberately:
   Portfolio's void-950 (now the studio's real brand navy — see
   _variables.css) is BOTH the page background in the dark theme and the
   primary/cta/text color here. Gold is the reverse: the expressive
   accent when it's the one warm note on navy, demoted to a quieter
   accent-only role here since navy itself already provides the strong,
   high-contrast actionable color on a light ground. Same two colors,
   swapped roles by which one actually pops on the given background —
   not two unrelated palettes.

   Every text pairing below is verified (contrast computed against
   these literal values, not assumed): ink-on-bg 16.2:1, ink-on-white
   17.7:1, muted-on-bg 5.4:1, accent-on-bg 4.6:1. The raw dark-theme
   gold (--aether-gold-500) fails badly here (2.2:1) — do not use it
   for text on this theme; it's fine for non-text use (borders, dots).
   Feedback colors below follow the same "deepen for light" logic but
   are unverified against real usage — re-check before shipping the
   first light-theme alert/badge that uses them.

   Scope this to a subtree, not :root — <div data-theme="daylight"> —
   the way every other theme in this file is designed to be used.
   -------------------------------------------------------------------- */
[data-theme='daylight'] {
  --aether-bg: #f6f5f1;
  --aether-surface-1: #ffffff;
  --aether-surface-1-hover: #fbfaf7;
  --aether-surface-2: #f0efe9;
  --aether-surface-2-hover: #e9e7df;
  --aether-surface-3: #ffffff;
  --aether-surface-3-hover: #fbfaf7;

  --aether-border: #dedcd2;
  --aether-border-strong: #c7c4b6;

  --aether-text: #0a1830;
  --aether-text-muted: #5b6478;
  --aether-text-faint: #8a92a3;

  /* Navy is the strong actionable color here — it's what pops on a
     light ground, the same way gold pops on the dark ground. */
  --aether-primary: #0a1830;
  --aether-primary-hover: color-mix(in oklch, #0a1830 85%, white 15%);
  --aether-primary-active: color-mix(in oklch, #0a1830 92%, black 8%);
  --aether-secondary: #5c3fa8;
  --aether-secondary-hover: #6f52ba;

  /* Deepened from the dark theme's gold-500 specifically so it holds
     AA as text/label color on this background — see file header. */
  --aether-accent: #8a6a2a;
  --aether-accent-hover: #71531f;

  --aether-cta: var(--aether-primary);
  --aether-cta-hover: var(--aether-primary-hover);

  --aether-text-on-primary: #f6f5f1;
  --aether-text-on-secondary: #f6f5f1;
  --aether-text-on-accent: #f6f5f1;
  --aether-text-on-feedback: #f6f5f1;

  --aether-success: #2f7a52;
  --aether-success-hover: color-mix(in oklch, #2f7a52 85%, black 15%);
  --aether-warning: var(--aether-accent);
  --aether-warning-hover: var(--aether-accent-hover);
  --aether-danger: #b8384a;
  --aether-danger-hover: color-mix(in oklch, #b8384a 85%, black 15%);
  --aether-info: #3a5fb0;
  --aether-info-hover: color-mix(in oklch, #3a5fb0 85%, black 15%);

  --aether-glass-bg: rgba(246, 245, 241, 0.82);
  --aether-glass-border: rgba(10, 24, 48, 0.1);

  --aether-glow-strength: 12%;
  --aether-glow-blur: 32px;
}

/* --------------------------------------------------------------------
   Atelier — Sam Studio's approved portfolio redesign direction
   ("Atelier Daylight" + "The Seal"). Portfolio-specific, not a general
   AETHER theme: exact hex values as specified in the approved design
   brief, not derived from the existing gold/void raw scales the way
   'dark'/'daylight' are — this is the Sam Studio *product* asserting
   its own identity on top of AETHER the *tool*, per that brief's
   explicit instruction not to let AETHER's prior appearance dictate it.

   Verified contrast (computed, not assumed):
     ink    #241F1A on paper #F6EFE1   14.27:1  — body text, headings
     muted  #6B5F4C on paper #F6EFE1    5.45:1  — secondary text (passes AA)
     ember  #B2451F on paper #F6EFE1    4.88:1  — accent text/links (passes AA)
     navy   #1B2A4A on paper #F6EFE1   12.43:1  — available as text if needed
     paper  #F6EFE1 on navy  #1B2A4A   12.43:1  — the one deliberate dark band
     gold   #D9A441 on paper #F6EFE1    1.97:1  — FAILS AA as text; decorative
                                                   /large-mark use only (seal,
                                                   numerals, borders), never
                                                   small text on paper
     gold   #D9A441 on ink   #241F1A    7.26:1  — safe as text on dark bands
     gold   #D9A441 on navy  #1B2A4A    6.32:1  — safe as text on the navy band
     ember  #B2451F on ink   #241F1A    2.93:1  — FAILS; do not pair these two
   -------------------------------------------------------------------- */
[data-theme='atelier'] {
  --aether-bg: #f6efe1;
  --aether-surface-1: #fbf6ea;
  --aether-surface-1-hover: #f3ecd9;
  --aether-surface-2: #fefcf6;
  --aether-surface-2-hover: #f6efe1;
  --aether-surface-3: #ffffff;
  --aether-surface-3-hover: #fbf6ea;

  --aether-border: #e1d5bd;
  --aether-border-strong: #cbb894;

  --aether-text: #241f1a;
  --aether-text-muted: #6b5f4c;
  --aether-text-faint: #948564;

  /* Ink is the strong actionable color here — solid CTA buttons — so
     ember stays a deliberate, occasional accent rather than "everywhere". */
  --aether-primary: #241f1a;
  --aether-primary-hover: color-mix(in oklch, #241f1a 85%, white 15%);
  --aether-primary-active: color-mix(in oklch, #241f1a 92%, black 8%);
  --aether-secondary: #1b2a4a;
  --aether-secondary-hover: color-mix(in oklch, #1b2a4a 85%, white 15%);

  --aether-accent: #b2451f;
  --aether-accent-hover: color-mix(in oklch, #b2451f 80%, black 20%);

  --aether-cta: var(--aether-primary);
  --aether-cta-hover: var(--aether-primary-hover);

  --aether-text-on-primary: #f6efe1;
  --aether-text-on-secondary: #f6efe1;
  --aether-text-on-accent: #f6efe1;
  --aether-text-on-feedback: #f6efe1;

  --aether-success: #2f7a52;
  --aether-success-hover: color-mix(in oklch, #2f7a52 85%, black 15%);
  --aether-warning: #a1791f;
  --aether-warning-hover: color-mix(in oklch, #a1791f 85%, black 15%);
  --aether-danger: #a1341f;
  --aether-danger-hover: color-mix(in oklch, #a1341f 85%, black 15%);
  --aether-info: #2f4f8a;
  --aether-info-hover: color-mix(in oklch, #2f4f8a 85%, black 15%);

  --aether-glass-bg: rgba(246, 239, 225, 0.86);
  --aether-glass-border: rgba(36, 31, 26, 0.1);

  --aether-glow-strength: 10%;
  --aether-glow-blur: 28px;
}

/* ---- source: css/aether/core/base/_reset.css ---- */
/* ==========================================================================
   AETHER UI — Reset
   A modern, opinionated reset. The goal is not "remove all browser
   styling" — it's "remove the styling decisions that fight the system,
   keep the ones that preserve accessibility (like focus outlines until we
   replace them deliberately in base.css)."
   ========================================================================== */

*,
*::before,
*::after {
  box-sizing: border-box;
}

* {
  margin: 0;
  padding: 0;
}

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  min-height: 100dvh;
  line-height: var(--aether-leading-normal);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Media elements default to block and never overflow their container */
img,
picture,
video,
canvas,
svg {
  display: block;
  max-width: 100%;
  height: auto;
}

/* Form elements inherit typography instead of reverting to the OS default */
input,
button,
textarea,
select {
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
}

button {
  background: none;
  border: none;
  cursor: pointer;
}

/* Headings/paragraphs get their sizing from the type-scale system in
   typography.css, not from browser defaults */
h1,
h2,
h3,
h4,
h5,
h6,
p {
  font-size: inherit;
  font-weight: inherit;
  text-wrap: balance;
}

p,
li {
  text-wrap: pretty;
}

a {
  color: inherit;
  text-decoration: none;
}

ul[role='list'],
ol[role='list'] {
  list-style: none;
}

table {
  border-collapse: collapse;
  border-spacing: 0;
}

/* Respect reduced-motion at the reset level, before any component gets a
   chance to add an animation */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

#root,
#__next {
  isolation: isolate;
}

/* ---- source: css/aether/core/base/_typography.css ---- */
/* ==========================================================================
   AETHER UI — Typography

   Self-hosted (see assets/fonts/) — fetched once from Google Fonts /
   Fontshare's own CDN response and vendored here with the exact
   font-weight/style/unicode-range values each service returned, so
   subsetting behavior is unchanged from the CDN version. No third-party
   font request, no render-blocking cross-origin dependency. Re-fetch
   and re-run the same extraction if a font/weight is ever added.
   ========================================================================== */

@font-face {
  font-family: 'Fraunces';
  src: url('../assets/fonts/fraunces/fraunces-1.woff2') format('woff2');
  font-weight: 300 700;
  font-style: italic;
  font-display: swap;
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}

@font-face {
  font-family: 'Fraunces';
  src: url('../assets/fonts/fraunces/fraunces-2.woff2') format('woff2');
  font-weight: 300 700;
  font-style: italic;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Fraunces';
  src: url('../assets/fonts/fraunces/fraunces-3.woff2') format('woff2');
  font-weight: 300 700;
  font-style: italic;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Fraunces';
  src: url('../assets/fonts/fraunces/fraunces-4.woff2') format('woff2');
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}

@font-face {
  font-family: 'Fraunces';
  src: url('../assets/fonts/fraunces/fraunces-5.woff2') format('woff2');
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Fraunces';
  src: url('../assets/fonts/fraunces/fraunces-6.woff2') format('woff2');
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'JetBrains Mono';
  src: url('../assets/fonts/jetbrains-mono/jetbrains-mono-1.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}

@font-face {
  font-family: 'JetBrains Mono';
  src: url('../assets/fonts/jetbrains-mono/jetbrains-mono-2.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: 'JetBrains Mono';
  src: url('../assets/fonts/jetbrains-mono/jetbrains-mono-3.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}

@font-face {
  font-family: 'JetBrains Mono';
  src: url('../assets/fonts/jetbrains-mono/jetbrains-mono-4.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}

@font-face {
  font-family: 'JetBrains Mono';
  src: url('../assets/fonts/jetbrains-mono/jetbrains-mono-5.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'JetBrains Mono';
  src: url('../assets/fonts/jetbrains-mono/jetbrains-mono-6.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'JetBrains Mono';
  src: url('../assets/fonts/jetbrains-mono/jetbrains-mono-7.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}

@font-face {
  font-family: 'JetBrains Mono';
  src: url('../assets/fonts/jetbrains-mono/jetbrains-mono-8.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: 'JetBrains Mono';
  src: url('../assets/fonts/jetbrains-mono/jetbrains-mono-9.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}

@font-face {
  font-family: 'JetBrains Mono';
  src: url('../assets/fonts/jetbrains-mono/jetbrains-mono-10.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}

@font-face {
  font-family: 'JetBrains Mono';
  src: url('../assets/fonts/jetbrains-mono/jetbrains-mono-11.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'JetBrains Mono';
  src: url('../assets/fonts/jetbrains-mono/jetbrains-mono-12.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'JetBrains Mono';
  src: url('../assets/fonts/jetbrains-mono/jetbrains-mono-13.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}

@font-face {
  font-family: 'JetBrains Mono';
  src: url('../assets/fonts/jetbrains-mono/jetbrains-mono-14.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: 'JetBrains Mono';
  src: url('../assets/fonts/jetbrains-mono/jetbrains-mono-15.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}

@font-face {
  font-family: 'JetBrains Mono';
  src: url('../assets/fonts/jetbrains-mono/jetbrains-mono-16.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}

@font-face {
  font-family: 'JetBrains Mono';
  src: url('../assets/fonts/jetbrains-mono/jetbrains-mono-17.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'JetBrains Mono';
  src: url('../assets/fonts/jetbrains-mono/jetbrains-mono-18.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Satoshi';
  src: url('../assets/fonts/satoshi/satoshi-1.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Satoshi';
  src: url('../assets/fonts/satoshi/satoshi-2.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Satoshi';
  src: url('../assets/fonts/satoshi/satoshi-3.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Satoshi';
  src: url('../assets/fonts/satoshi/satoshi-4.woff2') format('woff2');
  font-weight: 900;
  font-style: normal;
  font-display: swap;
}

/* --------------------------------------------------------------------
   Base element typography
   -------------------------------------------------------------------- */

body {
  font-family: var(--aether-font-body);
  font-size: var(--aether-text-base);
  font-weight: var(--aether-weight-regular);
  color: var(--aether-text);
  letter-spacing: var(--aether-tracking-normal);
}

h1,
h2,
h3,
h4,
h5,
h6 {
  font-family: var(--aether-font-heading);
  font-weight: var(--aether-weight-semibold);
  line-height: var(--aether-leading-tight);
  letter-spacing: var(--aether-tracking-tight);
  color: var(--aether-text);
}

h1 {
  font-size: var(--aether-text-5xl);
}

h2 {
  font-size: var(--aether-text-4xl);
}

h3 {
  font-size: var(--aether-text-3xl);
}

h4 {
  font-size: var(--aether-text-2xl);
}

h5 {
  font-size: var(--aether-text-xl);
  font-weight: var(--aether-weight-medium);
}

h6 {
  font-size: var(--aether-text-md);
  font-weight: var(--aether-weight-medium);
}

p {
  max-width: var(--aether-content-width-normal);
  line-height: var(--aether-leading-relaxed);
  color: var(--aether-text);
}

small {
  font-size: var(--aether-text-sm);
  color: var(--aether-text-muted);
}

strong,
b {
  font-weight: var(--aether-weight-semibold);
}

em,
i {
  font-style: italic;
}

blockquote {
  font-family: var(--aether-font-heading);
  font-size: var(--aether-text-md);
  font-style: italic;
  line-height: var(--aether-leading-relaxed);
  color: var(--aether-text-muted);
  border-left: 2px solid var(--aether-accent);
  padding-left: var(--aether-space-6);
}

code,
kbd,
samp {
  font-family: var(--aether-font-mono);
  font-size: 0.9em;
}

code {
  background: var(--aether-surface-2);
  border: 1px solid var(--aether-border);
  border-radius: var(--aether-radius-sm);
  padding: 0.15em 0.45em;
  color: var(--aether-accent-hover);
}

pre {
  font-family: var(--aether-font-mono);
  background: var(--aether-surface-1);
  border: 1px solid var(--aether-border);
  border-radius: var(--aether-radius-md);
  padding: var(--aether-space-5);
  overflow-x: auto;
  line-height: var(--aether-leading-normal);
}

pre code {
  background: none;
  border: none;
  padding: 0;
  color: inherit;
}

a {
  color: var(--aether-primary-hover);
  transition: color var(--aether-transition-base);
}

a:hover {
  color: var(--aether-accent);
}

/* --------------------------------------------------------------------
   Typographic utility classes
   These sit here (rather than utilities.css) because they're purely
   typographic — no layout, spacing, or color-system implications beyond
   font tokens already defined above.
   -------------------------------------------------------------------- */

.u-font-heading {
  font-family: var(--aether-font-heading);
}

.u-font-body {
  font-family: var(--aether-font-body);
}

.u-font-mono {
  font-family: var(--aether-font-mono);
}

.u-eyebrow {
  font-family: var(--aether-font-mono);
  font-size: var(--aether-text-xs);
  font-weight: var(--aether-weight-medium);
  letter-spacing: var(--aether-tracking-widest);
  text-transform: uppercase;
  color: var(--aether-accent);
}

/* Signature "premium" text treatment — a restrained gradient sweep across
   headline text, used sparingly (hero headlines, not body copy). */
.u-text-gradient {
  background: linear-gradient(
    100deg,
    var(--aether-text) 20%,
    var(--aether-primary-hover) 50%,
    var(--aether-accent) 80%
  );
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
}

/* ---- source: css/aether/core/base/_base.css ---- */
/* ==========================================================================
   AETHER UI — Base
   Global, non-component styling: the canvas everything else sits on.
   Reset strips defaults, typography.css handles type, this file handles
   "what does the page itself look and feel like."
   ========================================================================== */

html {
  background: var(--aether-bg);
  color-scheme: dark;
}

body {
  background: var(--aether-bg);
  /* A faint radial wash of primary/secondary at the far corners is the
     "observatory at night" cue — depth and curiosity without literally
     drawing stars. Fixed so it doesn't repeat or shift oddly on scroll. */
  background-image:
    radial-gradient(ellipse 80% 50% at 15% -10%, color-mix(in oklch, var(--aether-primary) 16%, transparent), transparent),
    radial-gradient(ellipse 60% 40% at 90% 10%, color-mix(in oklch, var(--aether-secondary) 12%, transparent), transparent);
  background-attachment: fixed;
  background-repeat: no-repeat;
}

/* --------------------------------------------------------------------
   Selection
   A themed selection color is a small detail with disproportionate
   signal — one of the fastest tells that a UI was actually designed
   rather than defaulted. Focus-ring handling lives in
   _accessibility.css, not here — it needs to coordinate with
   prefers-contrast and forced-colors, which are accessibility concerns
   more than "base look" concerns.
   -------------------------------------------------------------------- */

::selection {
  background: color-mix(in oklch, var(--aether-accent) 35%, transparent);
  color: var(--aether-text);
}

/* --------------------------------------------------------------------
   Scrollbar
   Restyled on both engines so the scrollbar doesn't puncture the dark
   surface with a bright OS-default gray track.
   -------------------------------------------------------------------- */

html {
  scrollbar-width: thin;
  scrollbar-color: var(--aether-border-strong) transparent;
}

::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}

::-webkit-scrollbar-track {
  background: transparent;
}

::-webkit-scrollbar-thumb {
  background: var(--aether-border-strong);
  border-radius: var(--aether-radius-full);
  border: 2px solid var(--aether-bg);
}

::-webkit-scrollbar-thumb:hover {
  background: var(--aether-text-faint);
}

/* --------------------------------------------------------------------
   Disabled state — shared across any interactive element
   -------------------------------------------------------------------- */

[disabled],
[aria-disabled='true'] {
  opacity: 0.45;
  cursor: not-allowed;
}

/* --------------------------------------------------------------------
   Horizontal rule
   -------------------------------------------------------------------- */

hr {
  border: none;
  border-top: 1px solid var(--aether-border);
  margin-block: var(--aether-space-8);
}

/* ---- source: css/aether/core/base/_accessibility.css ---- */
/* ==========================================================================
   AETHER UI — Accessibility
   Premium and accessible are not in tension — a UI that only "feels
   expensive" for sighted mouse users with default OS settings isn't
   actually premium, it's just decorated. This file is the foundation
   layer's contract: every component built on top of AETHER UI inherits
   these behaviors for free, so accessibility doesn't have to be
   re-litigated component by component.
   ========================================================================== */

/* --------------------------------------------------------------------
   Focus — the single most important a11y primitive in the system.
   Reset.css already sets `:focus { outline: none }` is NOT what we do —
   instead we replace the default outline with a deliberate one, always
   visible for keyboard users, always absent for mouse users. Never
   remove focus outlines without replacing them; that's a WCAG 2.4.7
   failure and it's one of the first things a keyboard user will notice.
   -------------------------------------------------------------------- */

:focus {
  outline: none;
}

:focus-visible {
  outline: var(--aether-focus-ring-width) solid var(--aether-focus-ring-color);
  outline-offset: var(--aether-focus-ring-offset);
  border-radius: var(--aether-radius-sm);
}

/* Forced Colors Mode (Windows High Contrast). The browser strips custom
   backgrounds/gradients/shadows here and substitutes a flat, user-chosen
   palette — glass panels and glow effects would otherwise vanish into
   nothing. We don't fight the mode (that defeats its purpose); we just
   make sure focus and borders survive it using system color keywords. */
@media (forced-colors: active) {
  :focus-visible {
    outline: 2px solid CanvasText;
  }

  .u-glass,
  .u-surface-1,
  .u-surface-2,
  .u-surface-3 {
    border: 1px solid CanvasText;
    forced-color-adjust: none;
    background: Canvas;
    color: CanvasText;
  }
}

/* A visible keyboard-focus ring for custom interactive components (divs
   with role="button", custom selects, etc.) that can't rely on the
   browser's native :focus-visible heuristics alone. Apply alongside
   tabindex="0" and appropriate ARIA role. */
.u-focus-ring:focus-visible {
  outline: var(--aether-focus-ring-width) solid var(--aether-focus-ring-color);
  outline-offset: var(--aether-focus-ring-offset);
}

/* --------------------------------------------------------------------
   Minimum tap target
   WCAG 2.5.5 / 2.5.8 — anything clickable should be reachable by an
   imprecise pointer (touch, tremor, low vision + magnification). Apply
   to icon buttons, close (×) controls, and other small hit areas that
   don't get their size from padded text.
   -------------------------------------------------------------------- */

.u-tap-target {
  min-width: var(--aether-tap-target-min);
  min-height: var(--aether-tap-target-min);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* --------------------------------------------------------------------
   Reduced motion
   Reset.css already collapses animation/transition duration to ~0 for
   prefers-reduced-motion. That's the blunt, universal guarantee. The
   rules below are for ambient/looping motion (parallax, floating/
   pulsing elements, scroll-linked effects) that doesn't just need to be *fast* —
   they need to not happen at all, because they're the category of
   motion most likely to trigger vestibular symptoms. Components that
   add that kind of motion should gate it behind .u-motion-safe rather
   than relying on the duration override alone.

   Paused by default, running only once the user's OS has confirmed no
   preference against motion — deliberately the more cautious direction
   (most reduced-motion code instead defaults to "on" and only switches
   off inside a `prefers-reduced-motion: reduce` query, which leaves
   ambient/looping motion running for the common case of a browser or OS
   that simply hasn't reported a preference either way). Note this uses
   the `animation-play-state` longhand, not the `animation` shorthand —
   the shorthand would reset `animation-name` too, which no later rule
   (regardless of specificity) can un-set back to a real keyframe name.
   -------------------------------------------------------------------- */

.u-motion-safe {
  animation-play-state: paused;
}

@media (prefers-reduced-motion: no-preference) {
  .u-motion-safe {
    animation-play-state: running;
  }
}

/* --------------------------------------------------------------------
   Reduced transparency
   Glass surfaces depend on backdrop-filter + a translucent background.
   Some users disable transparency system-wide (motion sensitivity,
   low vision, or just readability) — honor it by swapping glass for a
   flat, fully opaque surface using the same tone.
   -------------------------------------------------------------------- */

@media (prefers-reduced-transparency: reduce) {
  .u-glass {
    background: var(--aether-surface-2);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
}

/* --------------------------------------------------------------------
   Increased contrast
   prefers-contrast: more signals the user needs stronger separation
   between foreground/background than our default premium-but-subtle
   borders provide. Strengthen borders and mutes without abandoning the
   theme's color identity.
   -------------------------------------------------------------------- */

@media (prefers-contrast: more) {
  :root {
    --aether-border: var(--aether-border-strong);
    --aether-text-muted: var(--aether-gray-300);
    --aether-glass-bg: var(--aether-surface-2);
    --aether-glow-strength: 65%;
  }

  .u-glass {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
}

/* --------------------------------------------------------------------
   Keyboard navigation
   Real keyboard interaction lives with each component that needs it
   (the navbar's dropdown, the mobile toggle, tooltip :focus-within) —
   this is the one global rule every component still relies on:
   [hidden] must genuinely remove content from both the visual canvas
   and the tab order, a common source of "invisible but still
   focusable" keyboard traps.
   -------------------------------------------------------------------- */

[hidden] {
  display: none !important;
}

/* ---- source: css/aether/core/utilities/_utilities.css ---- */
/* ==========================================================================
   AETHER UI — Utilities
   Single-purpose classes for the cases where a full component is
   overkill. Spacing/gap utilities below are mechanically generated from
   the spacing scale in variables.css (see scripts note at bottom) — don't
   hand-edit the numbers, edit the scale and regenerate instead.
   ========================================================================== */

/* --------------------------------------------------------------------
   Accessibility
   -------------------------------------------------------------------- */

.u-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.u-skip-link {
  position: absolute;
  top: -100%;
  left: var(--aether-space-4);
  z-index: var(--aether-z-toast);
  background: var(--aether-primary);
  color: var(--aether-text);
  padding: var(--aether-space-2) var(--aether-space-4);
  border-radius: var(--aether-radius-sm);
  transition: top var(--aether-transition-base);
}

.u-skip-link:focus {
  top: var(--aether-space-4);
}

/* --------------------------------------------------------------------
   Surfaces — glass & elevation
   The one "glass" recipe, reused everywhere, so every frosted panel in
   every project looks like it belongs to the same system.
   -------------------------------------------------------------------- */

.u-glass {
  background: var(--aether-glass-bg);
  border: 1px solid var(--aether-glass-border);
  backdrop-filter: blur(var(--aether-glass-blur));
  -webkit-backdrop-filter: blur(var(--aether-glass-blur));
}

.u-surface-1 {
  background: var(--aether-surface-1);
  border: 1px solid var(--aether-border);
}

.u-surface-2 {
  background: var(--aether-surface-2);
  border: 1px solid var(--aether-border);
}

.u-surface-3 {
  background: var(--aether-surface-3);
  border: 1px solid var(--aether-border);
}

/* --------------------------------------------------------------------
   Glow — the signature "sophisticated observatory" accent. Use on
   interactive or focal elements only; overuse flattens the effect.
   -------------------------------------------------------------------- */

.u-glow-primary {
  box-shadow: 0 0 var(--aether-glow-blur) color-mix(in oklch, var(--aether-primary) var(--aether-glow-strength), transparent);
}

.u-glow-secondary {
  box-shadow: 0 0 var(--aether-glow-blur) color-mix(in oklch, var(--aether-secondary) var(--aether-glow-strength), transparent);
}

.u-glow-accent {
  box-shadow: 0 0 var(--aether-glow-blur) color-mix(in oklch, var(--aether-accent) var(--aether-glow-strength), transparent);
}

/* --------------------------------------------------------------------
   Shadow (elevation only, no color)
   -------------------------------------------------------------------- */

.u-shadow-sm { box-shadow: var(--aether-shadow-sm); }
.u-shadow-md { box-shadow: var(--aether-shadow-md); }
.u-shadow-lg { box-shadow: var(--aether-shadow-lg); }
.u-shadow-xl { box-shadow: var(--aether-shadow-xl); }

/* --------------------------------------------------------------------
   Radius
   -------------------------------------------------------------------- */

.u-radius-sm { border-radius: var(--aether-radius-sm); }
.u-radius-md { border-radius: var(--aether-radius-md); }
.u-radius-lg { border-radius: var(--aether-radius-lg); }
.u-radius-xl { border-radius: var(--aether-radius-xl); }
.u-radius-2xl { border-radius: var(--aether-radius-2xl); }
.u-radius-full { border-radius: var(--aether-radius-full); }

/* --------------------------------------------------------------------
   Text color
   -------------------------------------------------------------------- */

.u-text { color: var(--aether-text); }
.u-text-muted { color: var(--aether-text-muted); }
.u-text-faint { color: var(--aether-text-faint); }
.u-text-primary { color: var(--aether-primary-hover); }
.u-text-secondary { color: var(--aether-secondary-hover); }
.u-text-accent { color: var(--aether-accent); }

/* --------------------------------------------------------------------
   Text alignment / weight
   -------------------------------------------------------------------- */

.u-text-left { text-align: left; }
.u-text-center { text-align: center; }
.u-text-right { text-align: right; }

.u-weight-regular { font-weight: var(--aether-weight-regular); }
.u-weight-medium { font-weight: var(--aether-weight-medium); }
.u-weight-semibold { font-weight: var(--aether-weight-semibold); }
.u-weight-bold { font-weight: var(--aether-weight-bold); }

/* --------------------------------------------------------------------
   Display (minimal set — the full layout system arrives in Phase 2)
   -------------------------------------------------------------------- */

.u-block { display: block; }
.u-inline-block { display: inline-block; }
.u-flex { display: flex; }
.u-inline-flex { display: inline-flex; }
.u-grid { display: grid; }
.u-hidden { display: none; }

/* --------------------------------------------------------------------
   Spacing — margin / padding
   Generated from the 15-step spacing scale × {m, mt, mr, mb, ml, mx, my,
   p, pt, pr, pb, pl, px, py}. Regenerate with:
     node scripts/generate-spacing.js
   and paste the output over this section if the scale in
   core/tokens/_variables.css ever changes.
   -------------------------------------------------------------------- */

.u-m-0 { margin: var(--aether-space-0); }
.u-m-1 { margin: var(--aether-space-1); }
.u-m-2 { margin: var(--aether-space-2); }
.u-m-3 { margin: var(--aether-space-3); }
.u-m-4 { margin: var(--aether-space-4); }
.u-m-5 { margin: var(--aether-space-5); }
.u-m-6 { margin: var(--aether-space-6); }
.u-m-8 { margin: var(--aether-space-8); }
.u-m-10 { margin: var(--aether-space-10); }
.u-m-12 { margin: var(--aether-space-12); }
.u-m-16 { margin: var(--aether-space-16); }
.u-m-20 { margin: var(--aether-space-20); }
.u-m-24 { margin: var(--aether-space-24); }
.u-m-32 { margin: var(--aether-space-32); }
.u-m-40 { margin: var(--aether-space-40); }

.u-mt-0 { margin-top: var(--aether-space-0); }
.u-mt-1 { margin-top: var(--aether-space-1); }
.u-mt-2 { margin-top: var(--aether-space-2); }
.u-mt-3 { margin-top: var(--aether-space-3); }
.u-mt-4 { margin-top: var(--aether-space-4); }
.u-mt-5 { margin-top: var(--aether-space-5); }
.u-mt-6 { margin-top: var(--aether-space-6); }
.u-mt-8 { margin-top: var(--aether-space-8); }
.u-mt-10 { margin-top: var(--aether-space-10); }
.u-mt-12 { margin-top: var(--aether-space-12); }
.u-mt-16 { margin-top: var(--aether-space-16); }
.u-mt-20 { margin-top: var(--aether-space-20); }
.u-mt-24 { margin-top: var(--aether-space-24); }
.u-mt-32 { margin-top: var(--aether-space-32); }
.u-mt-40 { margin-top: var(--aether-space-40); }

.u-mr-0 { margin-right: var(--aether-space-0); }
.u-mr-1 { margin-right: var(--aether-space-1); }
.u-mr-2 { margin-right: var(--aether-space-2); }
.u-mr-3 { margin-right: var(--aether-space-3); }
.u-mr-4 { margin-right: var(--aether-space-4); }
.u-mr-5 { margin-right: var(--aether-space-5); }
.u-mr-6 { margin-right: var(--aether-space-6); }
.u-mr-8 { margin-right: var(--aether-space-8); }
.u-mr-10 { margin-right: var(--aether-space-10); }
.u-mr-12 { margin-right: var(--aether-space-12); }
.u-mr-16 { margin-right: var(--aether-space-16); }
.u-mr-20 { margin-right: var(--aether-space-20); }
.u-mr-24 { margin-right: var(--aether-space-24); }
.u-mr-32 { margin-right: var(--aether-space-32); }
.u-mr-40 { margin-right: var(--aether-space-40); }

.u-mb-0 { margin-bottom: var(--aether-space-0); }
.u-mb-1 { margin-bottom: var(--aether-space-1); }
.u-mb-2 { margin-bottom: var(--aether-space-2); }
.u-mb-3 { margin-bottom: var(--aether-space-3); }
.u-mb-4 { margin-bottom: var(--aether-space-4); }
.u-mb-5 { margin-bottom: var(--aether-space-5); }
.u-mb-6 { margin-bottom: var(--aether-space-6); }
.u-mb-8 { margin-bottom: var(--aether-space-8); }
.u-mb-10 { margin-bottom: var(--aether-space-10); }
.u-mb-12 { margin-bottom: var(--aether-space-12); }
.u-mb-16 { margin-bottom: var(--aether-space-16); }
.u-mb-20 { margin-bottom: var(--aether-space-20); }
.u-mb-24 { margin-bottom: var(--aether-space-24); }
.u-mb-32 { margin-bottom: var(--aether-space-32); }
.u-mb-40 { margin-bottom: var(--aether-space-40); }

.u-ml-0 { margin-left: var(--aether-space-0); }
.u-ml-1 { margin-left: var(--aether-space-1); }
.u-ml-2 { margin-left: var(--aether-space-2); }
.u-ml-3 { margin-left: var(--aether-space-3); }
.u-ml-4 { margin-left: var(--aether-space-4); }
.u-ml-5 { margin-left: var(--aether-space-5); }
.u-ml-6 { margin-left: var(--aether-space-6); }
.u-ml-8 { margin-left: var(--aether-space-8); }
.u-ml-10 { margin-left: var(--aether-space-10); }
.u-ml-12 { margin-left: var(--aether-space-12); }
.u-ml-16 { margin-left: var(--aether-space-16); }
.u-ml-20 { margin-left: var(--aether-space-20); }
.u-ml-24 { margin-left: var(--aether-space-24); }
.u-ml-32 { margin-left: var(--aether-space-32); }
.u-ml-40 { margin-left: var(--aether-space-40); }

.u-mx-0 { margin-left: var(--aether-space-0); margin-right: var(--aether-space-0); }
.u-mx-1 { margin-left: var(--aether-space-1); margin-right: var(--aether-space-1); }
.u-mx-2 { margin-left: var(--aether-space-2); margin-right: var(--aether-space-2); }
.u-mx-3 { margin-left: var(--aether-space-3); margin-right: var(--aether-space-3); }
.u-mx-4 { margin-left: var(--aether-space-4); margin-right: var(--aether-space-4); }
.u-mx-5 { margin-left: var(--aether-space-5); margin-right: var(--aether-space-5); }
.u-mx-6 { margin-left: var(--aether-space-6); margin-right: var(--aether-space-6); }
.u-mx-8 { margin-left: var(--aether-space-8); margin-right: var(--aether-space-8); }
.u-mx-10 { margin-left: var(--aether-space-10); margin-right: var(--aether-space-10); }
.u-mx-12 { margin-left: var(--aether-space-12); margin-right: var(--aether-space-12); }
.u-mx-16 { margin-left: var(--aether-space-16); margin-right: var(--aether-space-16); }
.u-mx-20 { margin-left: var(--aether-space-20); margin-right: var(--aether-space-20); }
.u-mx-24 { margin-left: var(--aether-space-24); margin-right: var(--aether-space-24); }
.u-mx-32 { margin-left: var(--aether-space-32); margin-right: var(--aether-space-32); }
.u-mx-40 { margin-left: var(--aether-space-40); margin-right: var(--aether-space-40); }

.u-my-0 { margin-top: var(--aether-space-0); margin-bottom: var(--aether-space-0); }
.u-my-1 { margin-top: var(--aether-space-1); margin-bottom: var(--aether-space-1); }
.u-my-2 { margin-top: var(--aether-space-2); margin-bottom: var(--aether-space-2); }
.u-my-3 { margin-top: var(--aether-space-3); margin-bottom: var(--aether-space-3); }
.u-my-4 { margin-top: var(--aether-space-4); margin-bottom: var(--aether-space-4); }
.u-my-5 { margin-top: var(--aether-space-5); margin-bottom: var(--aether-space-5); }
.u-my-6 { margin-top: var(--aether-space-6); margin-bottom: var(--aether-space-6); }
.u-my-8 { margin-top: var(--aether-space-8); margin-bottom: var(--aether-space-8); }
.u-my-10 { margin-top: var(--aether-space-10); margin-bottom: var(--aether-space-10); }
.u-my-12 { margin-top: var(--aether-space-12); margin-bottom: var(--aether-space-12); }
.u-my-16 { margin-top: var(--aether-space-16); margin-bottom: var(--aether-space-16); }
.u-my-20 { margin-top: var(--aether-space-20); margin-bottom: var(--aether-space-20); }
.u-my-24 { margin-top: var(--aether-space-24); margin-bottom: var(--aether-space-24); }
.u-my-32 { margin-top: var(--aether-space-32); margin-bottom: var(--aether-space-32); }
.u-my-40 { margin-top: var(--aether-space-40); margin-bottom: var(--aether-space-40); }

.u-p-0 { padding: var(--aether-space-0); }
.u-p-1 { padding: var(--aether-space-1); }
.u-p-2 { padding: var(--aether-space-2); }
.u-p-3 { padding: var(--aether-space-3); }
.u-p-4 { padding: var(--aether-space-4); }
.u-p-5 { padding: var(--aether-space-5); }
.u-p-6 { padding: var(--aether-space-6); }
.u-p-8 { padding: var(--aether-space-8); }
.u-p-10 { padding: var(--aether-space-10); }
.u-p-12 { padding: var(--aether-space-12); }
.u-p-16 { padding: var(--aether-space-16); }
.u-p-20 { padding: var(--aether-space-20); }
.u-p-24 { padding: var(--aether-space-24); }
.u-p-32 { padding: var(--aether-space-32); }
.u-p-40 { padding: var(--aether-space-40); }

.u-pt-0 { padding-top: var(--aether-space-0); }
.u-pt-1 { padding-top: var(--aether-space-1); }
.u-pt-2 { padding-top: var(--aether-space-2); }
.u-pt-3 { padding-top: var(--aether-space-3); }
.u-pt-4 { padding-top: var(--aether-space-4); }
.u-pt-5 { padding-top: var(--aether-space-5); }
.u-pt-6 { padding-top: var(--aether-space-6); }
.u-pt-8 { padding-top: var(--aether-space-8); }
.u-pt-10 { padding-top: var(--aether-space-10); }
.u-pt-12 { padding-top: var(--aether-space-12); }
.u-pt-16 { padding-top: var(--aether-space-16); }
.u-pt-20 { padding-top: var(--aether-space-20); }
.u-pt-24 { padding-top: var(--aether-space-24); }
.u-pt-32 { padding-top: var(--aether-space-32); }
.u-pt-40 { padding-top: var(--aether-space-40); }

.u-pr-0 { padding-right: var(--aether-space-0); }
.u-pr-1 { padding-right: var(--aether-space-1); }
.u-pr-2 { padding-right: var(--aether-space-2); }
.u-pr-3 { padding-right: var(--aether-space-3); }
.u-pr-4 { padding-right: var(--aether-space-4); }
.u-pr-5 { padding-right: var(--aether-space-5); }
.u-pr-6 { padding-right: var(--aether-space-6); }
.u-pr-8 { padding-right: var(--aether-space-8); }
.u-pr-10 { padding-right: var(--aether-space-10); }
.u-pr-12 { padding-right: var(--aether-space-12); }
.u-pr-16 { padding-right: var(--aether-space-16); }
.u-pr-20 { padding-right: var(--aether-space-20); }
.u-pr-24 { padding-right: var(--aether-space-24); }
.u-pr-32 { padding-right: var(--aether-space-32); }
.u-pr-40 { padding-right: var(--aether-space-40); }

.u-pb-0 { padding-bottom: var(--aether-space-0); }
.u-pb-1 { padding-bottom: var(--aether-space-1); }
.u-pb-2 { padding-bottom: var(--aether-space-2); }
.u-pb-3 { padding-bottom: var(--aether-space-3); }
.u-pb-4 { padding-bottom: var(--aether-space-4); }
.u-pb-5 { padding-bottom: var(--aether-space-5); }
.u-pb-6 { padding-bottom: var(--aether-space-6); }
.u-pb-8 { padding-bottom: var(--aether-space-8); }
.u-pb-10 { padding-bottom: var(--aether-space-10); }
.u-pb-12 { padding-bottom: var(--aether-space-12); }
.u-pb-16 { padding-bottom: var(--aether-space-16); }
.u-pb-20 { padding-bottom: var(--aether-space-20); }
.u-pb-24 { padding-bottom: var(--aether-space-24); }
.u-pb-32 { padding-bottom: var(--aether-space-32); }
.u-pb-40 { padding-bottom: var(--aether-space-40); }

.u-pl-0 { padding-left: var(--aether-space-0); }
.u-pl-1 { padding-left: var(--aether-space-1); }
.u-pl-2 { padding-left: var(--aether-space-2); }
.u-pl-3 { padding-left: var(--aether-space-3); }
.u-pl-4 { padding-left: var(--aether-space-4); }
.u-pl-5 { padding-left: var(--aether-space-5); }
.u-pl-6 { padding-left: var(--aether-space-6); }
.u-pl-8 { padding-left: var(--aether-space-8); }
.u-pl-10 { padding-left: var(--aether-space-10); }
.u-pl-12 { padding-left: var(--aether-space-12); }
.u-pl-16 { padding-left: var(--aether-space-16); }
.u-pl-20 { padding-left: var(--aether-space-20); }
.u-pl-24 { padding-left: var(--aether-space-24); }
.u-pl-32 { padding-left: var(--aether-space-32); }
.u-pl-40 { padding-left: var(--aether-space-40); }

.u-px-0 { padding-left: var(--aether-space-0); padding-right: var(--aether-space-0); }
.u-px-1 { padding-left: var(--aether-space-1); padding-right: var(--aether-space-1); }
.u-px-2 { padding-left: var(--aether-space-2); padding-right: var(--aether-space-2); }
.u-px-3 { padding-left: var(--aether-space-3); padding-right: var(--aether-space-3); }
.u-px-4 { padding-left: var(--aether-space-4); padding-right: var(--aether-space-4); }
.u-px-5 { padding-left: var(--aether-space-5); padding-right: var(--aether-space-5); }
.u-px-6 { padding-left: var(--aether-space-6); padding-right: var(--aether-space-6); }
.u-px-8 { padding-left: var(--aether-space-8); padding-right: var(--aether-space-8); }
.u-px-10 { padding-left: var(--aether-space-10); padding-right: var(--aether-space-10); }
.u-px-12 { padding-left: var(--aether-space-12); padding-right: var(--aether-space-12); }
.u-px-16 { padding-left: var(--aether-space-16); padding-right: var(--aether-space-16); }
.u-px-20 { padding-left: var(--aether-space-20); padding-right: var(--aether-space-20); }
.u-px-24 { padding-left: var(--aether-space-24); padding-right: var(--aether-space-24); }
.u-px-32 { padding-left: var(--aether-space-32); padding-right: var(--aether-space-32); }
.u-px-40 { padding-left: var(--aether-space-40); padding-right: var(--aether-space-40); }

.u-py-0 { padding-top: var(--aether-space-0); padding-bottom: var(--aether-space-0); }
.u-py-1 { padding-top: var(--aether-space-1); padding-bottom: var(--aether-space-1); }
.u-py-2 { padding-top: var(--aether-space-2); padding-bottom: var(--aether-space-2); }
.u-py-3 { padding-top: var(--aether-space-3); padding-bottom: var(--aether-space-3); }
.u-py-4 { padding-top: var(--aether-space-4); padding-bottom: var(--aether-space-4); }
.u-py-5 { padding-top: var(--aether-space-5); padding-bottom: var(--aether-space-5); }
.u-py-6 { padding-top: var(--aether-space-6); padding-bottom: var(--aether-space-6); }
.u-py-8 { padding-top: var(--aether-space-8); padding-bottom: var(--aether-space-8); }
.u-py-10 { padding-top: var(--aether-space-10); padding-bottom: var(--aether-space-10); }
.u-py-12 { padding-top: var(--aether-space-12); padding-bottom: var(--aether-space-12); }
.u-py-16 { padding-top: var(--aether-space-16); padding-bottom: var(--aether-space-16); }
.u-py-20 { padding-top: var(--aether-space-20); padding-bottom: var(--aether-space-20); }
.u-py-24 { padding-top: var(--aether-space-24); padding-bottom: var(--aether-space-24); }
.u-py-32 { padding-top: var(--aether-space-32); padding-bottom: var(--aether-space-32); }
.u-py-40 { padding-top: var(--aether-space-40); padding-bottom: var(--aether-space-40); }

.u-gap-0 { gap: var(--aether-space-0); }
.u-gap-1 { gap: var(--aether-space-1); }
.u-gap-2 { gap: var(--aether-space-2); }
.u-gap-3 { gap: var(--aether-space-3); }
.u-gap-4 { gap: var(--aether-space-4); }
.u-gap-5 { gap: var(--aether-space-5); }
.u-gap-6 { gap: var(--aether-space-6); }
.u-gap-8 { gap: var(--aether-space-8); }
.u-gap-10 { gap: var(--aether-space-10); }
.u-gap-12 { gap: var(--aether-space-12); }
.u-gap-16 { gap: var(--aether-space-16); }
.u-gap-20 { gap: var(--aether-space-20); }
.u-gap-24 { gap: var(--aether-space-24); }
.u-gap-32 { gap: var(--aether-space-32); }
.u-gap-40 { gap: var(--aether-space-40); }

/* ---- source: css/aether/core/layout/_container.css ---- */
/* ==========================================================================
   AETHER UI — Layout: Container
   The outer shell that centers and bounds page content. Namespaced `.l-`
   (layout) rather than `.u-` (utility, single CSS property) or a bare
   class — this is structural scaffolding with its own responsive
   behavior, and the distinction keeps a future `.card` component from
   colliding with whatever a consuming project already calls `.container`.

   Breakpoints are hardcoded to the pixel values documented in
   _variables.css (--aether-bp-*) rather than interpolated — CSS custom
   properties can't be substituted inside an @media condition, so those
   tokens exist for JS to read, and this file is the second, deliberate
   place the same numbers live.
   ========================================================================== */

.l-container {
  width: 100%;
  margin-inline: auto;
  padding-inline: var(--aether-space-5);
  max-width: var(--aether-container-xl);
}

@media (min-width: 768px) {
  .l-container {
    padding-inline: var(--aether-space-8);
  }
}

@media (min-width: 1280px) {
  .l-container {
    padding-inline: var(--aether-space-10);
  }
}

/* Size modifiers — override the default xl ceiling. */
.l-container--sm { max-width: var(--aether-container-sm); }
.l-container--md { max-width: var(--aether-container-md); }
.l-container--lg { max-width: var(--aether-container-lg); }
.l-container--xl { max-width: var(--aether-container-xl); }
.l-container--2xl { max-width: var(--aether-container-2xl); }

/* Edge-to-edge: keeps the responsive gutter, drops the max-width ceiling.
   For full-bleed sections (hero backgrounds, image bands) that still
   need their inner content indented consistently with the rest of the
   page. */
.l-container--fluid { max-width: none; }

/* ---- source: css/aether/core/layout/_section.css ---- */
/* ==========================================================================
   AETHER UI — Layout: Section
   Vertical rhythm between major page regions, plus the reading-measure
   primitive for prose. Two different jobs, same file, because they're
   the two ways `_variables.css`'s Layout tokens (section-spacing,
   content-width) actually get consumed.
   ========================================================================== */

.l-section {
  padding-block: var(--aether-section-spacing-md);
}

.l-section--sm { padding-block: var(--aether-section-spacing-sm); }
.l-section--lg { padding-block: var(--aether-section-spacing-lg); }
.l-section--xl { padding-block: var(--aether-section-spacing-xl); }

/* Zero out one edge — the common case is a hero directly under a sticky
   nav (no top gap wanted) or two sections that should read as one visual
   block with a divider between them (no double gap at the seam). */
.l-section--flush-top { padding-top: 0; }
.l-section--flush-bottom { padding-bottom: 0; }

/* --------------------------------------------------------------------
   Prose — bounds a column of text to a readable measure. Distinct from
   .l-container: a container bounds a whole layout region (which might
   hold a grid, a hero, images at full width); .l-prose bounds one column
   of continuous reading text inside it.
   -------------------------------------------------------------------- */

.l-prose {
  max-width: var(--aether-content-width-normal);
  margin-inline: auto;
}

.l-prose--narrow { max-width: var(--aether-content-width-narrow); }
.l-prose--wide { max-width: var(--aether-content-width-wide); }

/* ---- source: css/aether/core/layout/_grid.css ---- */
/* ==========================================================================
   AETHER UI — Layout: Grid
   Two grid patterns cover almost everything: a fixed N-column grid that
   collapses predictably at wider breakpoints (dashboards, pricing
   tables, product listings with a known count), and a self-wrapping
   auto-fit grid that needs no breakpoints at all (card walls, portfolio
   showcases, anything where the item count isn't known ahead of time).

   Gap is intentionally NOT baked into each modifier — pair any .l-grid
   with a spacing utility from _utilities.css (.u-gap-4, .u-gap-8, ...)
   to control density. Default gap below is just a sane fallback.
   ========================================================================== */

.l-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--aether-space-6);
}

/* Fixed column counts — mobile-first: always 1 column below md (768px),
   then the requested count from lg (1024px) up. md itself is an
   intermediate 2-column step so tablets don't jump straight from 1 to 6. */
.l-grid--2,
.l-grid--3,
.l-grid--4,
.l-grid--6,
.l-grid--12 {
  grid-template-columns: 1fr;
}

@media (min-width: 768px) {
  .l-grid--2 { grid-template-columns: repeat(2, 1fr); }
  .l-grid--3 { grid-template-columns: repeat(2, 1fr); }
  .l-grid--4 { grid-template-columns: repeat(2, 1fr); }
  .l-grid--6 { grid-template-columns: repeat(3, 1fr); }
  .l-grid--12 { grid-template-columns: repeat(4, 1fr); }
}

@media (min-width: 1024px) {
  .l-grid--3 { grid-template-columns: repeat(3, 1fr); }
  .l-grid--4 { grid-template-columns: repeat(4, 1fr); }
  .l-grid--6 { grid-template-columns: repeat(6, 1fr); }
  .l-grid--12 { grid-template-columns: repeat(12, 1fr); }
}

/* Auto-fit — no breakpoints needed, wraps based on available width.
   --l-grid-min sets the minimum column width before it wraps; override
   inline (style="--l-grid-min: 280px") per instance rather than adding
   a new class for every size. */
.l-grid--auto {
  grid-template-columns: repeat(auto-fit, minmax(var(--l-grid-min, 240px), 1fr));
}

/* Column/row span helpers for grid children */
.l-grid-span-2 { grid-column: span 2; }
.l-grid-span-3 { grid-column: span 3; }
.l-grid-span-full { grid-column: 1 / -1; }

/* ---- source: css/aether/core/layout/_flex.css ---- */
/* ==========================================================================
   AETHER UI — Layout: Flex
   The other half of the layout toolkit — one-dimensional arrangement
   where grid would be overkill (a toolbar, a card's header row, a
   button group). Pair with .u-gap-* for spacing between items.
   ========================================================================== */

.l-flex {
  display: flex;
}

.l-flex--col { flex-direction: column; }
.l-flex--wrap { flex-wrap: wrap; }
.l-flex--nowrap { flex-wrap: nowrap; }

.l-flex--items-start { align-items: flex-start; }
.l-flex--items-center { align-items: center; }
.l-flex--items-end { align-items: flex-end; }
.l-flex--items-stretch { align-items: stretch; }

.l-flex--justify-start { justify-content: flex-start; }
.l-flex--justify-center { justify-content: center; }
.l-flex--justify-end { justify-content: flex-end; }
.l-flex--justify-between { justify-content: space-between; }
.l-flex--justify-around { justify-content: space-around; }

/* Child utilities */
.l-flex-1 { flex: 1 1 0%; }       /* grow to fill remaining space */
.l-flex-none { flex: none; }      /* never grow or shrink */

/* Mobile-first responsive stacking: column on small screens (the safe
   default for two things that can't both fit narrow), row from md
   (768px) up. The single most common "responsive layout" request —
   named for the breakpoint it switches at, not for what it's stacking,
   since the same class serves a nav, a hero split, or a form row. */
.l-flex--row-md {
  flex-direction: column;
}

@media (min-width: 768px) {
  .l-flex--row-md {
    flex-direction: row;
  }
}

/* ---- source: css/aether/core/motion/_keyframes.css ---- */
/* ==========================================================================
   AETHER UI — Motion: Keyframes
   Named animation definitions only — no classes here. _motion.css applies
   these to real, reusable classes with the durations/easings from the
   Motion tokens in _variables.css. Splitting the two keeps a keyframe's
   shape (what it moves) separate from its timing (how long, what curve),
   the same separation of concerns as tokens vs. the things that consume
   them everywhere else in this system.
   ========================================================================== */

/* --------------------------------------------------------------------
   Fade
   Opacity only — deliberately doesn't touch transform. Two separate
   utility CLASSES on one element can't combine (whichever sets
   `animation` last in the cascade wins outright, it doesn't merge with
   the other) — but two KEYFRAME NAMES referenced together in one
   `animation` declaration do run concurrently, each only touching the
   properties it declares. That's what this split is actually for: a
   future component can write its own
   `animation: aetherFadeIn .., aetherSlideInUp ..;` and get a real
   fade+slide combo, because neither keyframe fights the other for the
   same property. The Reveal keyframe below (aetherRevealUp) is exactly
   that combination, pre-assembled and exposed as .m-reveal-in in
   _motion.css.
   -------------------------------------------------------------------- */

@keyframes aetherFadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes aetherFadeOut {
  from { opacity: 1; }
  to { opacity: 0; }
}

/* --------------------------------------------------------------------
   Slide
   Transform only, for the same reason Fade is opacity-only. Distance is
   a fixed value here rather than a token — motion distance is a
   different kind of scale than spacing-between-elements, and forcing it
   onto --aether-space-* would make a spacing-scale change silently
   change how far every entrance animation travels.
   -------------------------------------------------------------------- */

@keyframes aetherSlideInUp {
  from { transform: translateY(24px); }
  to { transform: translateY(0); }
}

@keyframes aetherSlideInDown {
  from { transform: translateY(-24px); }
  to { transform: translateY(0); }
}

@keyframes aetherSlideInLeft {
  from { transform: translateX(-24px); }
  to { transform: translateX(0); }
}

@keyframes aetherSlideInRight {
  from { transform: translateX(24px); }
  to { transform: translateX(0); }
}

/* --------------------------------------------------------------------
   Reveal
   The opinionated combination of fade + a shorter rise than Slide uses —
   the "this content has arrived" entrance, distinct from a generic
   directional slide. One keyframe (not two composed) because reveal is
   meant to be a single deliberate effect, not a build-your-own.
   -------------------------------------------------------------------- */

@keyframes aetherRevealUp {
  from {
    opacity: 0;
    transform: translateY(16px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* --------------------------------------------------------------------
   Float
   Ambient, continuous, decorative — a different time register entirely
   from interaction motion (seconds, not the millisecond Motion-token
   scale built for UI feedback). Kept as a literal duration in
   _motion.css for that reason; see the comment there.
   -------------------------------------------------------------------- */

@keyframes aetherFloat {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-12px); }
}

/* --------------------------------------------------------------------
   Glow pulse
   Reads --m-glow-color (set by a modifier class in _motion.css, default
   --aether-primary) so one keyframe serves every glow color instead of
   one keyframe per tint. Strength/blur intensify at the peak using
   calc() on top of the existing --aether-glow-strength/-blur tokens, so
   a theme that turns glow down (Business) or up (Spiritual) changes the
   whole pulse range automatically, not just its resting state.
   -------------------------------------------------------------------- */

@keyframes aetherGlowPulse {
  0%, 100% {
    box-shadow: 0 0 var(--aether-glow-blur) color-mix(in oklch, var(--m-glow-color, var(--aether-primary)) var(--aether-glow-strength), transparent);
  }
  50% {
    box-shadow: 0 0 calc(var(--aether-glow-blur) * 1.6) color-mix(in oklch, var(--m-glow-color, var(--aether-primary)) calc(var(--aether-glow-strength) + 20%), transparent);
  }
}

/* --------------------------------------------------------------------
   Spin
   Added in Phase 3 for loading states (button loading, the feedback
   spinner) — kept here rather than duplicated in two component files,
   since "rotate 360deg forever" is exactly the kind of primitive this
   module exists to hold. A functional/status animation, not a
   decorative one, so components using it do NOT pair it with
   .u-motion-safe the way Float/Glow pulse do — reset.css's blanket
   reduced-motion override (near-zero duration, single iteration) is
   the right amount of restraint for something communicating "busy."
   -------------------------------------------------------------------- */

@keyframes aetherSpin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

/* ---- source: css/aether/core/motion/_motion.css ---- */
/* ==========================================================================
   AETHER UI — Motion
   Reusable animation primitives — not component animations. Nothing here
   knows about a card, a button, or a nav; these are the six raw moves
   (reveal, fade, slide, float, glow, hover lift) that Core components
   apply, the same way components apply .u-radius-lg or .l-flex rather
   than reinventing radius or layout.

   Namespaced `.m-` (motion) — the same reasoning as `.l-` for layout in
   core/layout/: this is multi-property, stateful behavior (an animation
   or a hover interaction), not a single CSS property like a `.u-`
   utility, and it deserves its own namespace so a component class
   never collides with it.

   Every duration/easing below comes from the Motion tokens in
   core/tokens/_variables.css (--aether-duration-*, --aether-ease-*) —
   nothing here invents its own timing. The one exception is Float's
   loop duration; see the comment on that class for why.
   ========================================================================== */

/* --------------------------------------------------------------------
   Fade
   Standalone opacity change. For a fade THAT ALSO moves, don't stack
   .m-fade-in with .m-slide-up — see the note in _keyframes.css: separate
   utility classes both setting `animation` don't combine, only one wins.
   Use .m-reveal-in for a pre-combined fade+rise, or write a component's
   own `animation: aetherFadeIn .., aetherSlideInUp ..;` to combine any
   two keyframes deliberately.
   -------------------------------------------------------------------- */

.m-fade-in {
  animation: aetherFadeIn var(--aether-duration-slow) var(--aether-ease-standard) both;
}

.m-fade-out {
  animation: aetherFadeOut var(--aether-duration-slow) var(--aether-ease-standard) both;
}

/* --------------------------------------------------------------------
   Slide
   Directional, transform-only entrances. Emphasized-decelerate is the
   easing built specifically for arrivals — front-loaded deceleration
   reads as "this landed here" rather than a mechanical linear move.
   -------------------------------------------------------------------- */

.m-slide-up {
  animation: aetherSlideInUp var(--aether-duration-slow) var(--aether-ease-emphasized-decelerate) both;
}

.m-slide-down {
  animation: aetherSlideInDown var(--aether-duration-slow) var(--aether-ease-emphasized-decelerate) both;
}

.m-slide-left {
  animation: aetherSlideInLeft var(--aether-duration-slow) var(--aether-ease-emphasized-decelerate) both;
}

.m-slide-right {
  animation: aetherSlideInRight var(--aether-duration-slow) var(--aether-ease-emphasized-decelerate) both;
}

/* --------------------------------------------------------------------
   Reveal
   Two flavors of the same idea, because "reveal" means two different
   things in practice:

     .m-reveal-in   plays once, immediately, on mount — a hero, a modal's
                    content, anything that should arrive as soon as it
                    exists in the DOM. No JS required.

     .m-reveal      a SCROLL reveal: starts hidden and stays hidden until
                    something external adds .is-visible (an
                    IntersectionObserver, wired up in Phase 4 — this is
                    the CSS half of that pattern, ready for it). Because
                    that trigger is external, an element can get stuck
                    invisible forever if the JS never runs — so
                    prefers-reduced-motion doesn't just speed this one
                    up, it forces the visible end-state outright,
                    independent of whether .is-visible ever gets added.
   -------------------------------------------------------------------- */

.m-reveal-in {
  animation: aetherRevealUp var(--aether-duration-slower) var(--aether-ease-emphasized-decelerate) both;
}

.m-reveal {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity var(--aether-duration-slower) var(--aether-ease-emphasized-decelerate),
              transform var(--aether-duration-slower) var(--aether-ease-emphasized-decelerate);
}

.m-reveal.is-visible {
  opacity: 1;
  transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  .m-reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* --------------------------------------------------------------------
   Float
   Ambient, continuous, decorative — a hero graphic, a floating badge,
   an icon that should feel alive without asking for attention. Runs on
   its own literal duration rather than a Motion token: 6s/8s sit in a
   completely different register than the millisecond scale
   (--aether-duration-fast..slowest) built for UI feedback, and forcing
   ambient-loop timing onto that scale would either make "float" too
   fast to read as ambient, or pull the whole interaction-duration scale
   out toward multi-second values it was never meant to hold.

   This is exactly the "not just fast, actually off" category of motion
   _accessibility.css calls out — pair with .u-motion-safe (paused until
   the OS confirms no preference against motion) on anything where the
   float is purely decorative rather than load-bearing:
     <div class="m-float u-motion-safe">
   -------------------------------------------------------------------- */

.m-float {
  animation: aetherFloat 6s var(--aether-ease-smooth) infinite;
}

.m-float--slow {
  animation-duration: 8s;
}

/* --------------------------------------------------------------------
   Glow pulse
   The animated counterpart to the static .u-glow-primary/secondary/
   accent utilities from _utilities.css — same color formula, breathing
   instead of fixed. Same accessibility guidance as Float: decorative,
   not load-bearing, pair with .u-motion-safe where appropriate.
   -------------------------------------------------------------------- */

.m-glow-pulse {
  animation: aetherGlowPulse 3s var(--aether-ease-smooth) infinite;
}

.m-glow-pulse--secondary {
  --m-glow-color: var(--aether-secondary);
}

.m-glow-pulse--accent {
  --m-glow-color: var(--aether-accent);
}

/* --------------------------------------------------------------------
   Spin
   Status motion (loading), not decorative — see the note in
   _keyframes.css on why this one isn't paired with .u-motion-safe.
   -------------------------------------------------------------------- */

.m-spin {
  animation: aetherSpin 0.6s linear infinite;
}

/* --------------------------------------------------------------------
   Hover lift
   Interaction motion, not autoplay — a transition between two states
   (rest / hovered), not a keyframe. Fast duration on purpose: hover
   feedback needs to feel immediate, not cinematic. Also responds to
   :focus-visible so the same lift reaches keyboard users, not just a
   mouse — and to :active with a smaller, closer offset for the "being
   pressed" moment, which reads as considered rather than just a hover
   effect that happens to also apply on click.
   -------------------------------------------------------------------- */

.m-hover-lift {
  transition: transform var(--aether-transition-fast), box-shadow var(--aether-transition-fast);
}

.m-hover-lift:hover,
.m-hover-lift:focus-visible {
  transform: translateY(-4px);
  box-shadow: var(--aether-shadow-lg);
}

.m-hover-lift:active {
  transform: translateY(-1px);
}

/* ---- source: css/aether/core/components/buttons/_button.css ---- */
/* ==========================================================================
   AETHER UI — Component: Button
   Namespaced `.c-` (component) — distinct from `.u-` (single-property
   utility), `.l-` (structural layout), and `.m-` (raw animation
   primitive). A button is all four things at once — spacing, color,
   motion, interaction — so it earns its own layer rather than being
   assembled from utilities on every use.

   The base .c-button carries everything variant-independent (shape,
   type, motion, focus, disabled/loading behavior). Variant classes only
   ever set color — swapping a variant should never change size, radius,
   or how the hover/press motion feels. That split is what keeps six
   variants reading as one button family instead of six different
   buttons that happen to sit near each other.
   ========================================================================== */

/* --------------------------------------------------------------------
   Base
   -------------------------------------------------------------------- */

.c-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--aether-space-2);
  position: relative;
  min-height: var(--aether-tap-target-min);
  padding: var(--aether-space-3) var(--aether-space-6);
  border: 1px solid transparent;
  border-radius: var(--aether-radius-md);
  font-family: var(--aether-font-body);
  font-size: var(--aether-text-base);
  font-weight: var(--aether-weight-semibold);
  line-height: 1;
  white-space: nowrap;
  text-decoration: none;
  user-select: none;
  cursor: pointer;
  transition: background-color var(--aether-transition-fast),
              border-color var(--aether-transition-fast),
              color var(--aether-transition-fast),
              transform var(--aether-transition-fast),
              box-shadow var(--aether-transition-fast);
}

/* Press feedback — a small settle-down on every variant, independent of
   whichever hover treatment (lift, glow) that variant adds on top. */
.c-button:active {
  transform: translateY(1px);
}

.c-button[disabled],
.c-button[aria-disabled='true'] {
  transform: none;
  box-shadow: none;
}

/* --------------------------------------------------------------------
   Sizes
   min-height stays constant across sizes (accessibility floor, not a
   visual one) — only padding and type scale change.
   -------------------------------------------------------------------- */

.c-button--sm {
  padding: var(--aether-space-2) var(--aether-space-4);
  font-size: var(--aether-text-sm);
  gap: var(--aether-space-1);
}

.c-button--lg {
  padding: var(--aether-space-4) var(--aether-space-8);
  font-size: var(--aether-text-md);
}

/* --------------------------------------------------------------------
   Variants
   Each hover treatment matches the variant's register: filled variants
   (primary/secondary/CTA) get a lift + glow, because they're meant to
   feel substantial and premium. Ghost/outline stay quieter — a glow on
   a low-emphasis button would fight its own purpose.
   -------------------------------------------------------------------- */

.c-button--primary {
  background: var(--aether-primary);
  color: var(--aether-text-on-primary);
}

.c-button--primary:hover {
  background: var(--aether-primary-hover);
  transform: translateY(-2px);
  box-shadow: 0 0 var(--aether-glow-blur) color-mix(in oklch, var(--aether-primary) var(--aether-glow-strength), transparent);
}

.c-button--secondary {
  background: var(--aether-secondary);
  color: var(--aether-text-on-secondary);
}

.c-button--secondary:hover {
  background: var(--aether-secondary-hover);
  transform: translateY(-2px);
  box-shadow: 0 0 var(--aether-glow-blur) color-mix(in oklch, var(--aether-secondary) var(--aether-glow-strength), transparent);
}

/* Ghost — the quietest variant. No fill, no border; a background tint
   on hover is the only feedback. For tertiary actions that shouldn't
   compete with a primary/CTA button on the same screen. */
.c-button--ghost {
  background: transparent;
  color: var(--aether-text-muted);
}

.c-button--ghost:hover {
  background: var(--aether-surface-2);
  color: var(--aether-text);
}

/* Outline — visible boundary without the weight of a fill. Reads as
   "secondary action with more presence than Ghost," e.g. paired next to
   a Primary button as its "Cancel"/"Learn more" counterpart. */
.c-button--outline {
  background: transparent;
  border-color: var(--aether-border-strong);
  color: var(--aether-text);
}

.c-button--outline:hover {
  border-color: var(--aether-primary-hover);
  color: var(--aether-primary-hover);
  background: color-mix(in oklch, var(--aether-primary) 8%, transparent);
}

/* CTA — the button that makes money. Uses --aether-cta rather than
   --aether-accent directly (see _variables.css) so Commerce can make
   checkout buttons punchier without every other gold accent in the UI
   following along. Slightly bolder weight and a stronger lift than
   Primary/Secondary — this is the one button on the page that should
   feel like the obvious next step. */
.c-button--cta {
  background: var(--aether-cta);
  color: var(--aether-text-on-accent);
  font-weight: var(--aether-weight-bold);
}

.c-button--cta:hover {
  background: var(--aether-cta-hover);
  transform: translateY(-3px);
  box-shadow: 0 0 var(--aether-glow-blur) color-mix(in oklch, var(--aether-cta) var(--aether-glow-strength), transparent);
}

.c-button--danger {
  background: var(--aether-danger);
  color: var(--aether-text-on-feedback);
}

.c-button--danger:hover {
  background: var(--aether-danger-hover);
  transform: translateY(-2px);
  box-shadow: 0 0 var(--aether-glow-blur) color-mix(in oklch, var(--aether-danger) var(--aether-glow-strength), transparent);
}

/* --------------------------------------------------------------------
   Loading
   Text stays visible (color isn't touched) — a spinner is inserted
   before it via ::before, so the button keeps its label and doesn't
   reflow-jump when the state changes. currentColor means the spinner
   automatically matches whichever variant it's applied to. Consumers
   should pair this class with the real `disabled` attribute (or
   `aria-disabled="true"`) and `aria-busy="true"` — a CSS class alone
   can't stop form submission or announce the state to assistive tech.
   -------------------------------------------------------------------- */

.c-button--loading {
  pointer-events: none;
  opacity: 0.85;
}

.c-button--loading::before {
  content: '';
  width: 1em;
  height: 1em;
  border: 2px solid color-mix(in oklch, currentColor 30%, transparent);
  border-top-color: currentColor;
  border-radius: var(--aether-radius-full);
  animation: aetherSpin 0.6s linear infinite;
}

/* ---- source: css/aether/core/components/cards/_card.css ---- */
/* ==========================================================================
   AETHER UI — Component: Card
   One flexible primitive rather than twelve bespoke components. Every
   card type this system needs to support — project, skill, service,
   pricing, product, article, quote, reflection, stat — is a composition
   of the same .c-card shell plus a handful of __ sub-parts, not a
   separate class per named use case. That's the "coherent design
   language" the brief asks for: the vocabulary is shared, only the
   content inside changes.

   Anatomy:
     .c-card                 shell — border, radius, background, motion
       .c-card__media        optional image, bleeds to the card's edges
       .c-card__body         padded content area (everything below media)
         .c-card__title / __description / __footer / __list / __stat
       .c-card__corner       absolute-positioned slot over .media (badge, price tag)

   The shell itself carries no padding — .c-card__media (if present) can
   then run edge-to-edge, with .c-card__body owning the internal padding.
   Text content always lives inside .c-card__body, whether or not the
   card has media above it; a text-only card just omits __media.
   ========================================================================== */

/* --------------------------------------------------------------------
   Shell
   -------------------------------------------------------------------- */

.c-card {
  display: block;
  position: relative;
  background: var(--aether-surface-1);
  border: 1px solid var(--aether-border);
  border-radius: var(--aether-radius-lg);
  overflow: hidden;
  transition: border-color var(--aether-transition-base),
              transform var(--aether-transition-base),
              box-shadow var(--aether-transition-base);
}

.c-card__body {
  display: flex;
  flex-direction: column;
  gap: var(--aether-space-3);
  padding: var(--aether-space-6);
}

.c-card__media {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
}

/* Slot for a badge/price-tag/discount pill floated over the media —
   pairs with .c-badge from the Feedback components. */
.c-card__corner {
  position: absolute;
  top: var(--aether-space-4);
  right: var(--aether-space-4);
  z-index: var(--aether-z-dropdown);
}

.c-card__title {
  font-family: var(--aether-font-heading);
  font-size: var(--aether-text-lg);
  font-weight: var(--aether-weight-semibold);
  color: var(--aether-text);
}

.c-card__description {
  font-size: var(--aether-text-sm);
  line-height: var(--aether-leading-relaxed);
  color: var(--aether-text-muted);
}

.c-card__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--aether-space-4);
  margin-top: auto;
  padding-top: var(--aether-space-4);
  border-top: 1px solid var(--aether-border);
}

/* Feature/pricing list — checkmark via ::before so the marker inherits
   the accent color without needing an icon dependency. */
.c-card__list {
  display: flex;
  flex-direction: column;
  gap: var(--aether-space-2);
  list-style: none;
}

.c-card__list-item {
  display: flex;
  align-items: baseline;
  gap: var(--aether-space-2);
  font-size: var(--aether-text-sm);
  color: var(--aether-text-muted);
}

.c-card__list-item::before {
  content: '✓';
  color: var(--aether-accent);
  font-weight: var(--aether-weight-bold);
}

/* Stat — the large-number treatment for statistics/dashboard cards.
   Mono font reads as "measured/precise," matching the Business
   register this card type is built for. */
.c-card__stat {
  font-family: var(--aether-font-mono);
  font-size: var(--aether-text-3xl);
  font-weight: var(--aether-weight-semibold);
  color: var(--aether-primary-hover);
  line-height: var(--aether-leading-tight);
}

.c-card__stat-label {
  font-size: var(--aether-text-xs);
  text-transform: uppercase;
  letter-spacing: var(--aether-tracking-wide);
  color: var(--aether-text-faint);
}

/* --------------------------------------------------------------------
   Variants
   -------------------------------------------------------------------- */

.c-card--glass {
  background: var(--aether-glass-bg);
  border-color: var(--aether-glass-border);
  backdrop-filter: blur(var(--aether-glass-blur));
  -webkit-backdrop-filter: blur(var(--aether-glass-blur));
}

.c-card--elevated {
  background: var(--aether-surface-2);
  box-shadow: var(--aether-shadow-lg);
}

/* Interactive — the card itself is the click target (wrap in <a>, or
   add tabindex="0" + an appropriate role if it triggers JS). Lift +
   border animation on both :hover and :focus-visible so keyboard users
   get identical feedback to a mouse. */
.c-card--interactive {
  cursor: pointer;
}

.c-card--interactive:hover,
.c-card--interactive:focus-visible {
  transform: translateY(-4px);
  border-color: var(--aether-primary-hover);
  box-shadow: var(--aether-shadow-lg);
}

/* Featured — a persistent accent treatment for "most popular"/"selected
   work" callouts, not just a hover state. Top accent bar + a resting
   (not pulsing) glow at reduced strength so it reads as premium rather
   than distracting. */
.c-card--featured {
  border-color: var(--aether-accent);
  border-top: 3px solid var(--aether-accent);
  box-shadow: 0 0 var(--aether-glow-blur) color-mix(in oklch, var(--aether-accent) calc(var(--aether-glow-strength) / 2), transparent);
}

/* Quote — for testimonials, philosophy pages, reflection entries. A
   large decorative opening mark in the heading serif, sized and faded
   independently of the actual quote text so it reads as texture, not
   as content (hence aria-hidden guidance in the demo/README). */
.c-card--quote {
  text-align: center;
}

.c-card--quote .c-card__body {
  align-items: center;
  gap: var(--aether-space-4);
}

.c-card--quote .c-card__body::before {
  content: '"';
  font-family: var(--aether-font-heading);
  font-size: var(--aether-text-4xl);
  line-height: 1;
  color: var(--aether-accent);
  opacity: 0.5;
}

.c-card--quote blockquote {
  border-left: none;
  padding-left: 0;
  font-size: var(--aether-text-md);
}

/* ---- source: css/aether/core/components/navigation/_navbar.css ---- */
/* ==========================================================================
   AETHER UI — Component: Navigation
   Outer bar / inner row split, the same separation Phase 2's layout
   engine uses for container vs. content: .c-navbar is the full-bleed bar
   that owns background, border, and sticky behavior; .c-navbar__inner is
   the width-constrained flex row that actually aligns brand/links/CTA.
   Splitting them means a glass or sticky nav can span edge-to-edge while
   its *content* still lines up with the rest of the page's container.

   State vs. variant naming follows the convention set in Phase 2.5:
   `--modifier` classes are author-chosen (glass vs. solid, which variant
   to render); `.is-*` classes are runtime state toggled by JS (open vs.
   closed) — same pattern as .m-reveal's `.is-visible`.
   ========================================================================== */

/* --------------------------------------------------------------------
   Bar
   -------------------------------------------------------------------- */

.c-navbar {
  width: 100%;
  z-index: var(--aether-z-sticky);
  border-bottom: 1px solid transparent;
  transition: background-color var(--aether-transition-base),
              border-color var(--aether-transition-base);
}

.c-navbar--sticky {
  position: sticky;
  top: 0;
}

.c-navbar--glass {
  background: var(--aether-glass-bg);
  border-bottom-color: var(--aether-glass-border);
  backdrop-filter: blur(var(--aether-glass-blur));
  -webkit-backdrop-filter: blur(var(--aether-glass-blur));
}

.c-navbar--solid {
  background: var(--aether-bg);
  border-bottom-color: var(--aether-border);
}

.c-navbar__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--aether-space-6);
  max-width: var(--aether-container-xl);
  margin-inline: auto;
  padding-inline: var(--aether-space-5);
  padding-block: var(--aether-space-4);
}

@media (min-width: 768px) {
  .c-navbar__inner {
    padding-inline: var(--aether-space-8);
  }
}

.c-navbar__brand {
  display: flex;
  align-items: center;
  gap: var(--aether-space-2);
  font-family: var(--aether-font-heading);
  font-size: var(--aether-text-md);
  font-weight: var(--aether-weight-semibold);
  color: var(--aether-text);
}

/* --------------------------------------------------------------------
   Links
   -------------------------------------------------------------------- */

.c-nav-links {
  display: flex;
  align-items: center;
  gap: var(--aether-space-8);
  list-style: none;
}

.c-nav-link {
  position: relative;
  padding-block: var(--aether-space-2);
  font-size: var(--aether-text-sm);
  font-weight: var(--aether-weight-medium);
  color: var(--aether-text-muted);
  transition: color var(--aether-transition-fast);
}

.c-nav-link:hover {
  color: var(--aether-text);
}

/* Animated underline — grows from 0 on hover, and stays full-width for
   the current page via [aria-current="page"]. Real navigation state
   (aria-current) drives it, not a decorative-only class, so a screen
   reader gets the same "you are here" signal a sighted user sees. */
.c-nav-link::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  width: 0;
  height: 2px;
  background: var(--aether-primary-hover);
  transition: width var(--aether-transition-base);
}

.c-nav-link:hover::after,
.c-nav-link[aria-current='page']::after {
  width: 100%;
}

.c-nav-link[aria-current='page'] {
  color: var(--aether-text);
}

/* --------------------------------------------------------------------
   Mobile
   .c-navbar__toggle is a real <button> (aria-expanded reflects
   .is-open, aria-controls points at the links list id) — the three
   spans become an X via transform, not by swapping icons, so the
   animation is one continuous motion rather than a cut.
   -------------------------------------------------------------------- */

.c-navbar__toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: var(--aether-tap-target-min);
  height: var(--aether-tap-target-min);
  background: none;
  border: none;
  cursor: pointer;
}

.c-navbar__toggle-line {
  display: block;
  width: 22px;
  height: 2px;
  background: var(--aether-text);
  border-radius: var(--aether-radius-full);
  transition: transform var(--aether-transition-base), opacity var(--aether-transition-fast);
}

.c-navbar__toggle.is-open .c-navbar__toggle-line:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}

.c-navbar__toggle.is-open .c-navbar__toggle-line:nth-child(2) {
  opacity: 0;
}

.c-navbar__toggle.is-open .c-navbar__toggle-line:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

@media (max-width: 767px) {
  .c-navbar__toggle {
    display: flex;
  }

  .c-nav-links {
    position: absolute;
    inset-inline: 0;
    top: 100%;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: var(--aether-surface-1);
    border-bottom: 1px solid var(--aether-border);
    padding: var(--aether-space-4) var(--aether-space-5);
    opacity: 0;
    visibility: hidden;
    transform: translateY(-8px);
    transition: opacity var(--aether-transition-base),
                transform var(--aether-transition-base),
                visibility 0s linear var(--aether-duration-base);
  }

  .c-nav-links.is-open {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
    transition: opacity var(--aether-transition-base),
                transform var(--aether-transition-base),
                visibility 0s;
  }

  .c-nav-link {
    padding-block: var(--aether-space-3);
  }

  .c-nav-link::after {
    display: none;
  }
}

/* --------------------------------------------------------------------
   Dropdown foundation
   Generic enough for a user menu, a mega-nav trigger, or a settings
   popover — not specific to top-nav. Elevation tier is surface-3 on
   purpose: a dropdown is exactly the "floats above everything" case
   that tier exists for (see the Surface hierarchy in _variables.css).
   -------------------------------------------------------------------- */

.c-dropdown {
  position: relative;
}

.c-dropdown__menu {
  position: absolute;
  top: calc(100% + var(--aether-space-2));
  left: 0;
  min-width: 200px;
  z-index: var(--aether-z-dropdown);
  background: var(--aether-surface-3);
  border: 1px solid var(--aether-border);
  border-radius: var(--aether-radius-md);
  box-shadow: var(--aether-shadow-lg);
  padding: var(--aether-space-2);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity var(--aether-transition-fast),
              transform var(--aether-transition-fast),
              visibility 0s linear var(--aether-duration-fast);
}

.c-dropdown__menu--right {
  left: auto;
  right: 0;
}

.c-dropdown__menu.is-open {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  transition: opacity var(--aether-transition-fast),
              transform var(--aether-transition-fast),
              visibility 0s;
}

.c-dropdown__item {
  display: block;
  width: 100%;
  text-align: left;
  padding: var(--aether-space-2) var(--aether-space-3);
  border-radius: var(--aether-radius-sm);
  font-size: var(--aether-text-sm);
  color: var(--aether-text-muted);
  transition: background-color var(--aether-transition-fast), color var(--aether-transition-fast);
}

.c-dropdown__item:hover,
.c-dropdown__item:focus-visible {
  background: var(--aether-surface-2-hover);
  color: var(--aether-text);
}

/* ---- source: css/aether/core/components/typography/_typography.css ---- */
/* ==========================================================================
   AETHER UI — Component: Typography
   Reusable text TREATMENTS, not just font-family/size pairs — each of
   these earns its place as a component (rather than a plain <h1>/<p>)
   because it carries a specific compositional role in a page: the one
   big statement, the section label, the pull-quote, the paragraph that
   has to hook a reader.

   Eyebrow labels intentionally are NOT redefined here — .u-eyebrow from
   the foundation utility layer already is that component (a single
   visual treatment: mono, uppercase, tracked-out, accent-colored). It
   composes fine with the components below; duplicating it into a `.c-`
   class would just be two names for the same six lines of CSS.
   ========================================================================== */

/* --------------------------------------------------------------------
   Hero heading
   The one big statement on a page — a home hero, a case-study opener.
   Sits on the largest step of the type scale with the tightest tracking,
   and defaults to the system's signature gradient sweep since a hero
   headline is exactly the "use it sparingly, once per page" moment that
   treatment was designed for.
   -------------------------------------------------------------------- */

.c-hero-heading {
  font-family: var(--aether-font-heading);
  font-size: var(--aether-text-5xl);
  font-weight: var(--aether-weight-semibold);
  line-height: var(--aether-leading-tight);
  letter-spacing: var(--aether-tracking-tight);
  color: var(--aether-text);
}

.c-hero-heading--gradient {
  background: linear-gradient(
    100deg,
    var(--aether-text) 20%,
    var(--aether-primary-hover) 50%,
    var(--aether-accent) 80%
  );
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
}

/* --------------------------------------------------------------------
   Section heading
   The recurring "what this block of the page is" title — smaller and
   more restrained than Hero, meant to repeat several times down a page
   without competing with itself.
   -------------------------------------------------------------------- */

.c-section-heading {
  font-family: var(--aether-font-heading);
  font-size: var(--aether-text-3xl);
  font-weight: var(--aether-weight-semibold);
  line-height: var(--aether-leading-tight);
  letter-spacing: var(--aether-tracking-tight);
  color: var(--aether-text);
}

/* --------------------------------------------------------------------
   Quote block
   For a testimonial, pull-quote, or philosophy passage set directly in
   page flow (for the same treatment scoped inside a card boundary, see
   .c-card--quote). Large, italic, serif — reads as a considered
   statement rather than body copy that happens to be in quotes.
   -------------------------------------------------------------------- */

.c-quote {
  max-width: var(--aether-content-width-wide);
  margin-inline: auto;
  font-family: var(--aether-font-heading);
  font-style: italic;
  font-size: var(--aether-text-xl);
  line-height: var(--aether-leading-relaxed);
  text-align: center;
  color: var(--aether-text);
}

.c-quote__cite {
  display: block;
  margin-top: var(--aether-space-4);
  font-family: var(--aether-font-mono);
  font-style: normal;
  font-size: var(--aether-text-xs);
  text-transform: uppercase;
  letter-spacing: var(--aether-tracking-wide);
  color: var(--aether-text-faint);
}

.c-quote__cite::before {
  content: '— ';
}

/* --------------------------------------------------------------------
   Article introduction
   The opening paragraph of long-form content — set apart from the body
   copy that follows it by size and full-contrast color (body text uses
   --aether-text at the same value, so the real distinction is scale +
   position, not a muted/loud contrast trick).
   -------------------------------------------------------------------- */

.c-article-intro {
  max-width: var(--aether-content-width-wide);
  font-family: var(--aether-font-body);
  font-size: var(--aether-text-md);
  font-weight: var(--aether-weight-regular);
  line-height: var(--aether-leading-relaxed);
  color: var(--aether-text);
}

/* --------------------------------------------------------------------
   Feature text
   Icon/number + title + description, the recurring pattern for feature
   lists, service breakdowns, and "how it works" steps. __icon is a
   sized slot, not an icon system — drop an SVG, emoji, or a number in.
   -------------------------------------------------------------------- */

.c-feature {
  display: flex;
  gap: var(--aether-space-4);
}

.c-feature__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: var(--aether-space-10);
  height: var(--aether-space-10);
  background: var(--aether-surface-1);
  border-radius: var(--aether-radius-md);
  color: var(--aether-primary-hover);
}

.c-feature__title {
  font-family: var(--aether-font-heading);
  font-size: var(--aether-text-md);
  font-weight: var(--aether-weight-semibold);
  color: var(--aether-text);
  margin-bottom: var(--aether-space-1);
}

.c-feature__description {
  font-size: var(--aether-text-sm);
  line-height: var(--aether-leading-relaxed);
  color: var(--aether-text-muted);
}

/* ---- source: css/aether/core/components/feedback/_feedback.css ---- */
/* ==========================================================================
   AETHER UI — Component: Feedback
   Badge, tooltip foundation, alert, notification, loading indicator —
   the vocabulary a UI uses to say "here's a status" without interrupting
   the user. All five inherit the same three things from the layers
   below them: theme (semantic color tokens only), motion (Motion
   primitives, not bespoke keyframes), and accessibility (real
   :focus-visible, prefers-reduced-motion already handled globally).
   ========================================================================== */

/* --------------------------------------------------------------------
   Badge
   Small status/category pill. Neutral by default (surface-based, no
   semantic claim); color variants borrow the same feedback tokens
   Alert uses below, so a "danger" badge and a "danger" alert are always
   the same red.
   -------------------------------------------------------------------- */

.c-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--aether-space-1);
  padding: var(--aether-space-1) var(--aether-space-3);
  border-radius: var(--aether-radius-full);
  font-family: var(--aether-font-mono);
  font-size: var(--aether-text-xs);
  font-weight: var(--aether-weight-medium);
  text-transform: uppercase;
  letter-spacing: var(--aether-tracking-wide);
  background: var(--aether-surface-2);
  color: var(--aether-text-muted);
}

.c-badge--primary { background: var(--aether-primary); color: var(--aether-text-on-primary); }
.c-badge--accent { background: var(--aether-accent); color: var(--aether-text-on-accent); }
.c-badge--success { background: var(--aether-success); color: var(--aether-text-on-feedback); }
.c-badge--warning { background: var(--aether-warning); color: var(--aether-text-on-feedback); }
.c-badge--danger { background: var(--aether-danger); color: var(--aether-text-on-feedback); }
.c-badge--info { background: var(--aether-info); color: var(--aether-text-on-feedback); }

/* --------------------------------------------------------------------
   Tooltip foundation
   CSS-only, statically positioned — a foundation for a future
   JS-positioned version (Popper-style, flips to stay in viewport), not
   a complete solution. Triggers on :hover AND :focus-within so a
   keyboard user tabbing to the trigger sees it too, not just a mouse
   user hovering. Content is inert until shown (visibility, not just
   opacity) so it's never in the tab order or hit-testable while hidden.
   -------------------------------------------------------------------- */

.c-tooltip {
  position: relative;
  display: inline-flex;
}

.c-tooltip__content {
  position: absolute;
  bottom: calc(100% + var(--aether-space-2));
  left: 50%;
  transform: translate(-50%, 4px);
  z-index: var(--aether-z-tooltip);
  width: max-content;
  max-width: 220px;
  padding: var(--aether-space-2) var(--aether-space-3);
  border-radius: var(--aether-radius-sm);
  background: var(--aether-surface-3);
  border: 1px solid var(--aether-border);
  box-shadow: var(--aether-shadow-md);
  font-size: var(--aether-text-xs);
  color: var(--aether-text);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity var(--aether-transition-fast), transform var(--aether-transition-fast);
}

.c-tooltip:hover .c-tooltip__content,
.c-tooltip:focus-within .c-tooltip__content {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0);
}

.c-tooltip__content--bottom {
  bottom: auto;
  top: calc(100% + var(--aether-space-2));
  transform: translate(-50%, -4px);
}

.c-tooltip:hover .c-tooltip__content--bottom,
.c-tooltip:focus-within .c-tooltip__content--bottom {
  transform: translate(-50%, 0);
}

/* --------------------------------------------------------------------
   Alert
   A boxed, persistent message — left border carries the severity color
   so it reads at a glance even for someone skimming. Use role="alert"
   (assertive) for something that interrupts, role="status" (polite)
   for something that doesn't; this component doesn't set either for
   you, since only the consumer knows which one a given message is.
   -------------------------------------------------------------------- */

.c-alert {
  display: flex;
  gap: var(--aether-space-3);
  padding: var(--aether-space-4) var(--aether-space-5);
  border-radius: var(--aether-radius-md);
  border: 1px solid var(--aether-border);
  border-left: 3px solid var(--aether-border-strong);
  background: var(--aether-surface-1);
}

.c-alert__icon {
  flex-shrink: 0;
}

.c-alert__title {
  font-weight: var(--aether-weight-semibold);
  color: var(--aether-text);
  margin-bottom: var(--aether-space-1);
}

.c-alert__description {
  font-size: var(--aether-text-sm);
  color: var(--aether-text-muted);
}

.c-alert--info { border-left-color: var(--aether-info); }
.c-alert--success { border-left-color: var(--aether-success); }
.c-alert--warning { border-left-color: var(--aether-warning); }
.c-alert--danger { border-left-color: var(--aether-danger); }

/* --------------------------------------------------------------------
   Notification (toast)
   The individual message box; .c-notification-stack is the fixed-
   position container that holds a column of them in a page corner.
   Spawning/removing/auto-dismiss timers are JS the consuming project
   owns — this is the visual foundation, at the z-toast layer.
   -------------------------------------------------------------------- */

.c-notification-stack {
  position: fixed;
  top: var(--aether-space-5);
  right: var(--aether-space-5);
  z-index: var(--aether-z-toast);
  display: flex;
  flex-direction: column;
  gap: var(--aether-space-3);
  width: min(360px, calc(100vw - var(--aether-space-10)));
}

.c-notification {
  display: flex;
  gap: var(--aether-space-3);
  padding: var(--aether-space-4);
  border-radius: var(--aether-radius-md);
  background: var(--aether-surface-3);
  border: 1px solid var(--aether-border);
  box-shadow: var(--aether-shadow-lg);
  animation: aetherSlideInRight var(--aether-duration-base) var(--aether-ease-emphasized-decelerate) both;
}

.c-notification__title {
  font-weight: var(--aether-weight-semibold);
  color: var(--aether-text);
  margin-bottom: var(--aether-space-1);
}

.c-notification__description {
  font-size: var(--aether-text-sm);
  color: var(--aether-text-muted);
}

.c-notification__close {
  flex-shrink: 0;
  margin-left: auto;
  color: var(--aether-text-faint);
  transition: color var(--aether-transition-fast);
}

.c-notification__close:hover {
  color: var(--aether-text);
}

/* --------------------------------------------------------------------
   Loading indicator
   Built on the shared aetherSpin keyframe from the Motion module (same
   one .c-button--loading uses) — one spin animation for the whole
   system, not one per component that happens to need it.
   -------------------------------------------------------------------- */

.c-spinner {
  display: inline-block;
  width: var(--aether-space-6);
  height: var(--aether-space-6);
  border: 2px solid var(--aether-border);
  border-top-color: var(--aether-primary-hover);
  border-radius: var(--aether-radius-full);
  animation: aetherSpin 0.6s linear infinite;
}

.c-spinner--sm {
  width: var(--aether-space-4);
  height: var(--aether-space-4);
  border-width: 2px;
}

.c-spinner--lg {
  width: var(--aether-space-10);
  height: var(--aether-space-10);
  border-width: 3px;
}

/* ---- source: css/aether/patterns/shell/shell.css ---- */
/* ==========================================================================
   AETHER UI — Pattern: Shell
   Namespaced `.p-` (pattern) — the layer sitting above `.c-` components
   the way a sentence sits above its words. Components answer "what is
   this object" (a card, a button); patterns answer "how do these
   objects tell a story" (in what order, with how much room between
   them, does a Hero become a Feature section become a closing CTA).

   Rule for everything under patterns/: compose Core, don't duplicate
   it. A pattern may set ITS OWN opinion (how much padding a Hero wants,
   what a CTA's background glow looks like) but reaches for
   `.l-container`/`.l-grid`/`.l-flex` for structure and `.c-*` for
   objects rather than reimplementing either. If a `.p-*` file starts
   hardcoding a max-width or a card, that's a sign the thing it needs
   already exists in Core.

   Shell is the outermost wrapper for any page: it makes the classic
   "sticky footer" skeleton (content grows to fill the viewport, footer
   never floats mid-page on short content) available without every
   project re-deriving the same three lines of flexbox. It's kept here
   in Patterns rather than promoted into Core's layout primitives
   because it hasn't yet been proven reusable across two independent
   real projects — see the Promotion Rule in the project README.

   Assumes core/aether.css is already loaded by whatever page imports
   this file — see the note in patterns/hero/hero.css.
   ========================================================================== */

.p-page-shell {
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
}

/* The <main> (or whatever holds the actual page content) grows to fill
   whatever space the navbar + footer don't use. */
.p-page-shell__main {
  flex: 1 1 auto;
}

/* ---- source: css/aether/patterns/hero/hero.css ---- */
/* ==========================================================================
   AETHER UI — Pattern: Hero
   The opening statement of a page. One structure, two arrangements
   (centered / split), built to hold four completely different
   registers without changing a line of this file:

     Business    "Grow your company with intelligent solutions"
     Portfolio   "Developer building digital worlds"
     Commerce    "Premium products"
     Spiritual   "Explore knowledge and consciousness"

   That's the point of separating content from composition: the words
   above live in a project's own content/data, never in this file.
   .p-hero only knows there's an eyebrow, a heading, a subtext, and a
   row of actions. This is a Pattern — it depends on Core only (see the
   import below) and Core never depends back on it.

   USAGE (centered — the default)
     <section class="p-hero">
       <div class="l-container">
         <div class="p-hero__content">
           <p class="u-eyebrow">Eyebrow</p>
           <h1 class="c-hero-heading c-hero-heading--gradient">Headline</h1>
           <p class="p-hero__subtext">Supporting line.</p>
           <div class="p-hero__actions">
             <button class="c-button c-button--cta">Primary action</button>
             <button class="c-button c-button--ghost">Secondary</button>
           </div>
         </div>
       </div>
     </section>

   USAGE (split — text + media side by side)
     <section class="p-hero p-hero--split">
       <div class="l-container">
         <div class="l-flex l-flex--row-md l-flex--items-center u-gap-10">
           <div class="p-hero__content">...</div>
           <div class="p-hero__media"><img ...></div>
         </div>
       </div>
     </section>

   Split reaches for .l-flex--row-md (already stacks on mobile, sits
   side by side from 768px) instead of Hero inventing its own responsive
   two-column logic — composing the Layout Engine, not duplicating it.
   Assumes core/aether.css is already loaded by whatever page imports
   this file — same convention Core's own internal files use, so
   combining several patterns on one page never re-imports Core more
   than once.
   ========================================================================== */

.p-hero {
  padding-block: var(--aether-section-spacing-lg);
  text-align: center;
}

.p-hero--split {
  text-align: left;
}

.p-hero--split .p-hero__content,
.p-hero--split .p-hero__media {
  flex: 1 1 0%;
}

.p-hero__subtext {
  max-width: var(--aether-content-width-normal);
  margin-inline: auto;
  margin-block: var(--aether-space-6) 0;
  font-size: var(--aether-text-md);
  line-height: var(--aether-leading-relaxed);
  color: var(--aether-text-muted);
}

.p-hero--split .p-hero__subtext {
  margin-inline: 0;
}

.p-hero__actions {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: var(--aether-space-4);
  flex-wrap: wrap;
  margin-top: var(--aether-space-8);
}

.p-hero--split .p-hero__actions {
  justify-content: flex-start;
}

/* A placeholder treatment for the media slot — a real project drops an
   <img>/<video> in; this just makes an empty or loading slot look
   intentional rather than like a broken layout. */
.p-hero__media {
  aspect-ratio: 4 / 3;
  border-radius: var(--aether-radius-lg);
  background: var(--aether-surface-1);
  border: 1px solid var(--aether-border);
  overflow: hidden;
}

.p-hero__media img,
.p-hero__media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ---- source: css/aether/patterns/features/features.css ---- */
/* ==========================================================================
   AETHER UI — Pattern: Feature
   A centered header followed by a grid of .c-feature items (icon/number
   + title + description). Named with the "-section" suffix on purpose,
   distinct from .c-feature itself — this is a Pattern-layer arrangement
   of several Core components, not another name for the same thing.
   Depends on Core only.

   USAGE
     <section class="p-feature-section">
       <div class="l-container">
         <div class="p-feature-section__header">
           <p class="u-eyebrow">Eyebrow</p>
           <h2 class="c-section-heading">Section heading</h2>
           <p class="p-feature-section__intro">One supporting line.</p>
         </div>
         <div class="l-grid l-grid--3 u-gap-8">
           <div class="c-feature">...</div>
           <div class="c-feature">...</div>
           <div class="c-feature">...</div>
         </div>
       </div>
     </section>
   Assumes core/aether.css is already loaded by whatever page imports
   this file — see the note in patterns/hero/hero.css.
   ========================================================================== */

.p-feature-section {
  padding-block: var(--aether-section-spacing-md);
}

.p-feature-section__header {
  max-width: var(--aether-content-width-wide);
  margin-inline: auto;
  margin-bottom: var(--aether-space-12);
  text-align: center;
}

.p-feature-section__intro {
  margin-top: var(--aether-space-4);
  font-size: var(--aether-text-md);
  color: var(--aether-text-muted);
}

/* ---- source: css/aether/patterns/cta/cta.css ---- */
/* ==========================================================================
   AETHER UI — Pattern: CTA
   The closing argument — usually the last thing before the footer.
   Deliberately more visually assertive than the patterns above it: a
   radial glow wash (color-mix() off --aether-primary, resolved at this
   element directly rather than through a composite token — see the note
   on --aether-glow-strength in core/tokens/_variables.css for why that
   distinction matters for theme-safety) and a tighter container so the
   message reads as a single focused idea, not another content section.
   Depends on Core only.

   USAGE
     <section class="p-cta-section">
       <div class="l-container l-container--sm">
         <p class="u-eyebrow">Eyebrow</p>
         <h2 class="c-section-heading">Ready when you are.</h2>
         <p class="p-cta-section__subtext">One supporting line.</p>
         <div class="p-cta-section__actions">
           <button class="c-button c-button--cta">Get started</button>
         </div>
       </div>
     </section>
   Assumes core/aether.css is already loaded by whatever page imports
   this file — see the note in patterns/hero/hero.css.
   ========================================================================== */

.p-cta-section {
  padding-block: var(--aether-section-spacing-lg);
  text-align: center;
  background: radial-gradient(
    ellipse 60% 100% at 50% 100%,
    color-mix(in oklch, var(--aether-primary) 18%, transparent),
    transparent
  );
}

.p-cta-section__subtext {
  max-width: var(--aether-content-width-normal);
  margin-inline: auto;
  margin-block: var(--aether-space-4) var(--aether-space-8);
  font-size: var(--aether-text-md);
  color: var(--aether-text-muted);
}

.p-cta-section__actions {
  display: flex;
  justify-content: center;
  gap: var(--aether-space-4);
  flex-wrap: wrap;
}

/* ---- source: css/aether/patterns/grid/grid.css ---- */
/* ==========================================================================
   AETHER UI — Pattern: Grid
   The generic "showcase a collection of .c-card" pattern — the single
   most reusable pattern in this set, because "a heading, maybe a 'view
   all' link, and a grid of cards" is the same shape whether the cards
   are Portfolio projects, Commerce products, Business services, or
   Spiritual articles. The content decides what's different; this
   pattern never does. Depends on Core only.

   USAGE
     <section class="p-grid-section">
       <div class="l-container">
         <div class="p-grid-section__header">
           <h2 class="c-section-heading">Selected work</h2>
           <a href="/work" class="p-grid-section__link">View all →</a>
         </div>
         <div class="l-grid l-grid--3 u-gap-6">
           <div class="c-card">...</div>
           <div class="c-card">...</div>
           <div class="c-card">...</div>
         </div>
       </div>
     </section>
   Assumes core/aether.css is already loaded by whatever page imports
   this file — see the note in patterns/hero/hero.css.
   ========================================================================== */

.p-grid-section {
  padding-block: var(--aether-section-spacing-md);
}

.p-grid-section__header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--aether-space-6);
  margin-bottom: var(--aether-space-10);
}

.p-grid-section__link {
  flex-shrink: 0;
  font-size: var(--aether-text-sm);
  font-weight: var(--aether-weight-medium);
  color: var(--aether-text-muted);
  transition: color var(--aether-transition-fast);
}

.p-grid-section__link:hover {
  color: var(--aether-primary-hover);
}

/* ---- source: css/aether/patterns/article/article.css ---- */
/* ==========================================================================
   AETHER UI — Pattern: Article
   The long-form reading layout — a Spiritual article/teaching, a
   Portfolio case study, a Business blog post. Three parts: a centered
   header (eyebrow, title, meta), a width-constrained body with
   consistent rhythm between whatever content blocks it holds, and a
   closing footer (author bio, tags, next/prev). Depends on Core only.

   The __meta fields (author, date, reading time) are a direct match for
   whatever shape a project's own article content takes — this pattern
   and that content are meant to be read side by side.
   Assumes core/aether.css is already loaded by whatever page imports
   this file — see the note in patterns/hero/hero.css.
   ========================================================================== */

.p-article-layout {
  padding-block: var(--aether-section-spacing-md);
}

.p-article-layout__header {
  max-width: var(--aether-content-width-normal);
  margin-inline: auto;
  margin-bottom: var(--aether-space-10);
  text-align: center;
}

.p-article-layout__meta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--aether-space-3);
  margin-top: var(--aether-space-4);
  font-family: var(--aether-font-mono);
  font-size: var(--aether-text-xs);
  color: var(--aether-text-faint);
}

.p-article-layout__meta-item + .p-article-layout__meta-item::before {
  content: '·';
  margin-right: var(--aether-space-3);
  color: var(--aether-text-faint);
}

.p-article-layout__body {
  max-width: var(--aether-content-width-normal);
  margin-inline: auto;
}

/* "Lobotomized owl" rhythm — every content block gets consistent space
   above it, regardless of what mix of paragraphs/headings/blockquotes/
   images an article happens to contain. Means an author never has to
   remember a spacing utility on every element. */
.p-article-layout__body > * + * {
  margin-top: var(--aether-space-6);
}

.p-article-layout__footer {
  max-width: var(--aether-content-width-normal);
  margin-inline: auto;
  margin-top: var(--aether-space-12);
  padding-top: var(--aether-space-8);
  border-top: 1px solid var(--aether-border);
}

/* ---- source: css/aether/patterns/footer/footer.css ---- */
/* ==========================================================================
   AETHER UI — Pattern: Footer
   The closing landmark — brand + link columns, then a copyright bar.
   The one pattern in this set styled as a real <footer> rather than a
   generic <section>, since it's a page landmark screen readers and
   browser "jump to" tooling both look for by tag, not by class.
   Depends on Core only.

   USAGE
     <footer class="p-footer">
       <div class="l-container">
         <div class="p-footer__top">
           <div class="p-footer__brand">
             <span class="c-navbar__brand">Aether</span>
             <p class="p-footer__tagline">One line about the thing.</p>
           </div>
           <div class="p-footer__links">
             <div class="p-footer__group">
               <p class="p-footer__group-title">Product</p>
               <a class="p-footer__link" href="#">Link</a>
             </div>
           </div>
         </div>
         <div class="p-footer__bottom">
           <p class="p-footer__copyright">© 2026 Aether</p>
           <div class="p-footer__social">...</div>
         </div>
       </div>
     </footer>
   Assumes core/aether.css is already loaded by whatever page imports
   this file — see the note in patterns/hero/hero.css.
   ========================================================================== */

.p-footer {
  padding-block: var(--aether-section-spacing-md);
  border-top: 1px solid var(--aether-border);
}

.p-footer__top {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--aether-space-10);
  padding-bottom: var(--aether-space-10);
}

.p-footer__tagline {
  max-width: 32ch;
  margin-top: var(--aether-space-2);
  font-size: var(--aether-text-sm);
  color: var(--aether-text-muted);
}

.p-footer__links {
  display: flex;
  gap: var(--aether-space-12);
  flex-wrap: wrap;
}

/* Measured 1.81:1 on the navy shell at --aether-text-faint, which fails
   AA for 12.8px text — and this is a real heading, not decoration.
   Muted clears it while staying quieter than the links beneath. */
.p-footer__group-title {
  margin-bottom: var(--aether-space-3);
  font-family: var(--aether-font-mono);
  font-size: var(--aether-text-xs);
  text-transform: uppercase;
  letter-spacing: var(--aether-tracking-wide);
  color: var(--aether-text-muted);
}

.p-footer__link {
  display: block;
  padding-block: var(--aether-space-1);
  font-size: var(--aether-text-sm);
  color: var(--aether-text-muted);
  transition: color var(--aether-transition-fast);
}

.p-footer__link:hover {
  color: var(--aether-text);
}

.p-footer__bottom {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--aether-space-4);
  padding-top: var(--aether-space-8);
  border-top: 1px solid var(--aether-border);
}

/* Same 1.81:1 failure as the group title above. */
.p-footer__copyright {
  font-size: var(--aether-text-xs);
  color: var(--aether-text-muted);
}

.p-footer__social {
  display: flex;
  gap: var(--aether-space-4);
}

/* ---- source: css/aether/patterns/_landing-layout.css ---- */
/* ==========================================================================
   AETHER UI — Pattern: Landing (cross-pattern sequencing)
   Not a named pattern on its own — a thin, shared wrapper for a stacked
   sequence of OTHER patterns (Hero → Feature → Grid → Testimonial →
   CTA → Footer). Each pattern already owns its own vertical rhythm via
   a --aether-section-spacing-* token, so sections stacking directly
   need no extra gap logic between them — the "landing page" concern
   this file actually owns is the subtle rhythm that separates sections
   from each other visually. Depends on Core only.

   USAGE
     <main class="p-landing-layout">
       <section class="p-hero">...</section>
       <section class="p-feature-section p-landing-layout__section--alt">...</section>
       <section class="p-grid-section">...</section>
       ...
     </main>

   __section--alt is opt-in, not automatic (no nth-of-type magic) — a
   Hero or CTA section usually wants its OWN background treatment
   (a gradient glow, in CTA's case), and blind positional alternation
   would fight that. Apply --alt explicitly to whichever plain sections
   should read as "the other stripe."

   For sections that should sit flush against each other (a Hero
   directly under a sticky nav, or two sections meant to read as one
   visual block), reach for .l-section--flush-top/--flush-bottom rather
   than anything here — that's a Core Layout concern, already solved.
   For scroll-triggered entrance choreography, pair each section with
   .m-reveal (see core/motion/_motion.css) — that's a Core Motion
   concern, also already solved. This file exists only for what neither
   of those two layers owns: the "is this page too information-dense to
   read" overflow guard, and opt-in section-to-section contrast.

   Assumes core/aether.css is already loaded by whatever page imports
   this file — see the note in patterns/hero/hero.css.
   ========================================================================== */

.p-landing-layout {
  /* A glow/blur bleeding a few pixels past a section's own edge (Hero's
     gradient wash, a card's box-shadow) is fine — it becoming a
     horizontal scrollbar on the whole page is not. */
  overflow-x: clip;
}

.p-landing-layout__section--alt {
  background: var(--aether-surface-1);
}

/* ---- source: css/site.css (this project's own rules) ---- */
:root {
  /* Named aliases onto existing AETHER tokens — nothing new declared,
     just legible names for the values this file uses most. */
  --s-gold-dim: var(--aether-gold-700);

  /* The saturated gold actually used across the case-study work itself
     (Bénin Horizons #E7A93E, Luna Bistro #E8A33D) — reserved for
     decorative marks/borders in daylight zones, never small text
     (gold-500 doesn't hold AA as text on the daylight background,
     which is exactly why --s-gold-dim/gold-700 exists for that job). */
  --s-gold-bright: var(--aether-gold-500);

  /* Atelier direction's seal gold — an explicit hex from the approved
     brief (#D9A441), not derived from AETHER's raw gold scale like the
     two above. Fails AA as text on paper (1.97:1, see themes file) —
     decorative use only: seal rings, numerals, borders. Never small text. */
  --s-atelier-gold: #d9a441;
}

/* The hero constellation motif deliberately bleeds toward the viewport
   edge (see .s-hero__field's negative offset) — contained here rather
   than by pulling the offset in, so the bleed stays a bleed instead of
   a hard-clipped corner. */
html,
body {
  overflow-x: hidden;
}

/* --------------------------------------------------------------------
   Navbar brand mark — placeholder hexagon monogram + italic Fraunces
   wordmark, consistent with the two reference logo images shared for
   Direction C. Swap the background-image data URI for the real vector
   the moment final logo files are provided; nothing else about the nav
   needs to change. Pure CSS additions to the EXISTING .c-navbar__brand
   class, so this needs zero HTML changes across the site.

   The nav is intentionally never given [data-theme="daylight"] — it
   stays on the root theme throughout the page regardless of what's
   scrolling beneath it, so it reads as a constant brand presence
   rather than adapting per section. That's a placement decision (see
   index.html), not something this file needs to enforce.
   -------------------------------------------------------------------- */
.c-navbar__brand {
  position: relative;
  font-family: var(--aether-font-heading);
  font-style: italic;
  font-weight: 500;
  display: inline-flex;
  align-items: center;
  gap: 9px;
}

/* Tap-target fix: the mark + wordmark render shorter than 44px on
   their own (~30-33px). A min-height on the link itself would make it
   the tallest child in .c-navbar__inner's flex row and grow the whole
   navbar — measured, not assumed: it added ~10px to the bar on
   desktop. Instead, an absolutely-positioned ::after overlay extends
   the hit area outside the link's own box, which is excluded from
   layout flow, so it enlarges only the clickable region — logo, text,
   and navbar height stay pixel-identical. -8px top/bottom covers the
   shortest case (mobile, ~30px content) up to 46px; :hover/:focus
   styling stays on the link itself, unaffected by this overlay. */
.c-navbar__brand::after {
  content: '';
  position: absolute;
  inset-block: -8px;
  inset-inline: 0;
}

/* Tap-target fix: primary nav links measure ~35px tall on desktop —
   .c-nav-link already has position:relative (_navbar.css), so an
   invisible ::before overlay extends the hit area the same way the
   brand mark's ::after does above. Desktop-only: .c-navbar__inner has
   enough headroom to absorb this without growing (same proof as the
   brand fix), and the 32px gap between links (--aether-space-8) easily
   absorbs -5px of horizontal growth per side with room to spare.
   Scoped out of mobile deliberately — the dropdown stacks links with
   zero gap (_navbar.css), where this overlay would bleed into the
   neighboring link's hit area and blur the click boundary between
   them; that context gets real padding instead, below. */
@media (min-width: 768px) {
  .c-nav-link::before {
    content: '';
    position: absolute;
    inset-block: -6px;
    inset-inline: -5px;
  }
}

/* Same fix, mobile dropdown: real padding instead of an overlay, since
   each link is its own row in the dropdown's column layout — growing
   one doesn't grow or crowd its neighbors, unlike the shared-row cases
   above. ~42px before; --aether-space-4 clears 44px with margin.
   display:block is required here, not cosmetic: .c-nav-link is a bare
   <a> (inline by default) inside an <li>. padding-block on an inline
   element paints but doesn't contribute to layout height, so the <li>
   stayed sized to the text alone — measured, not assumed: the padded
   links visually overlapped 24px into their neighbors above and below
   before this line was added. display:block makes the <li> size to
   the link's real padded box, so stacked links stay contiguous. */
@media (max-width: 767px) {
  .c-nav-link {
    display: block;
    padding-block: var(--aether-space-4);
  }
}

/* Tap-target fix: footer nav links measure ~32px tall — each is its
   own block-level row with no competing siblings, so real padding is
   safe here too (same reasoning as the mobile nav-link fix above). */
.p-footer__link {
  padding-block: var(--aether-space-3);
}

/* Wherever a real mark is present in the nav brand — the Seal
   originally, the real logo (.s-brand-mark) now — suppress the old
   bare diamond/arrow ::before glyph it replaces, so the two never
   double up. Tied to either mark's actual presence rather than to a
   theme or to one specific selector, so this doesn't silently regress
   again the next time the brand mark changes. */
.c-navbar__brand:has(.s-seal, .s-brand-mark)::before {
  content: none;
}

.c-navbar__brand::before {
  content: '';
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18'%3E%3Cpath d='M9 1 L16.5 5.25 V13.75 L9 18 L1.5 13.75 V5.25 Z' stroke='%23f5f6fa' stroke-width='0.9' fill='none'/%3E%3Cpath d='M5.5 6.8 L12.5 6.8 L5.5 11.2 L12.5 11.2' stroke='%23f5f6fa' stroke-width='1.1' fill='none' stroke-linecap='round'/%3E%3Cpath d='M12.5 6.8 L14.2 8 L12.5 9.2 Z' fill='%23d8b876'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-size: contain;
}

/* --------------------------------------------------------------------
   The seal — Atelier direction's signature device. A ring plus the
   existing diamond/arrow glyph, in currentColor so the same markup
   reads correctly wherever it's placed (ink on paper, gold on the navy
   band). Deliberately has exactly three jobs on this page: the navbar
   brand mark, the hero anchor, and the final-CTA mark — see the design
   brief's own warning against turning every section into a stamp.
   Placeholder until the real logo replaces it; sizing/ring stay, only
   the inner mark swaps.
   -------------------------------------------------------------------- */
.s-seal {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  border-radius: 50%;
  border: 1.5px solid currentColor;
}

.s-seal svg {
  display: block;
}

.s-seal--sm {
  width: 30px;
  height: 30px;
}

.s-seal--sm svg {
  width: 13px;
  height: 13px;
}

.s-seal--md {
  width: 48px;
  height: 48px;
}

.s-seal--md svg {
  width: 20px;
  height: 20px;
}

.s-seal--lg {
  width: 88px;
  height: 88px;
  border-width: 2px;
}

.s-seal--lg svg {
  width: 36px;
  height: 36px;
}

/* Real logo mark — replaces the Seal specifically in the nav/footer
   brand slot now that a real logo exists. No ring: the hexagon icon
   has its own shape and doesn't need a second circular frame around
   it. Two source files, swapped per page at author time rather than
   with CSS/JS, since a raster image can't adapt to its background the
   way the Seal's currentColor SVG does: logo-icon-light.png (white +
   gold) on navy pages, logo-icon-dark.png (ink + gold) on the atelier
   pages (Services/About) — verified the light version is unreadable
   on paper before making that split, not guessed. */
.s-brand-mark {
  width: 30px;
  height: 30px;
  object-fit: contain;
  flex-shrink: 0;
}

/* Decorative-current-state color moves from AETHER's default primary
   (blue) to accent (gold) — brand decoration, not a functional signal,
   so it follows the studio's re-emphasis. The :focus-visible ring stays
   untouched in core (see file header). */
.c-nav-link::after {
  background: var(--aether-accent-hover);
}

.p-footer__link:hover {
  color: var(--aether-accent-hover);
}

/* --------------------------------------------------------------------
   Language toggle — plain "EN / FR" text, matching the simple toggle
   already used across the other projects (see nova-home-care's
   .lang-switch): the current language sits as inert text, the other is
   a link. No pill, no border, no dropdown — just two words in the nav.
   The link's hit area is padded out to 44px without changing its visual
   size, so "simple text toggle" and "accessible tap target" both hold.
   -------------------------------------------------------------------- */
.s-lang-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--aether-space-2);
  font-family: var(--aether-font-mono);
  font-size: var(--aether-text-xs);
  letter-spacing: var(--aether-tracking-wide);
}

.s-lang-toggle__current {
  color: var(--aether-accent);
  font-weight: var(--aether-weight-medium);
}

.s-lang-toggle__divider {
  color: var(--aether-text-faint);
}

.s-lang-toggle a {
  color: var(--aether-text-muted);
  transition: color var(--aether-transition-fast);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  margin: -14px -12px;
  padding: 14px 12px;
}

.s-lang-toggle a:hover {
  color: var(--aether-accent-hover);
}

/* --------------------------------------------------------------------
   Placeholder page body (Services / About / Contact / FR pages not yet
   built). Same shared classes every M1 page already uses — updating the
   rules here re-skins those pages with zero HTML changes.
   -------------------------------------------------------------------- */
.s-placeholder {
  min-height: 50vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: var(--aether-space-4);
  padding-block: var(--aether-section-spacing-lg);
}

.s-placeholder__eyebrow {
  font-family: var(--aether-font-mono);
  font-size: var(--aether-text-xs);
  letter-spacing: var(--aether-tracking-widest);
  text-transform: uppercase;
  color: var(--aether-accent);
}

.s-placeholder h1 {
  font-style: normal;
}

.s-placeholder__note {
  max-width: var(--aether-content-width-narrow);
  color: var(--aether-text-muted);
  font-size: var(--aether-text-sm);
}

/* ==========================================================================
   Hero — asymmetric, not centered. A thesis, not a banner: eyebrow, a
   large display headline with one emphasized word, a short subtext, a
   quiet meta line. The constellation motif sits behind it, low-opacity,
   never touching the text's reading area.
   ========================================================================== */
.s-hero {
  position: relative;
  padding-block: var(--aether-space-32) var(--aether-space-24);
  overflow: visible;
  background: var(--aether-bg);
  color: var(--aether-text);
}

/* Zone backgrounds must be painted explicitly, not left to inherit from
   <body> — a themed subtree's --aether-bg is only correct where
   something actually renders it. Without this rule, [data-theme
   ="daylight"] recolors every var(--aether-*) reference correctly but
   paints nothing, so light-theme text would sit on the still-navy body
   showing through underneath. */
[data-theme='daylight'] {
  background: var(--aether-bg);
  color: var(--aether-text);
}

/* Atelier wraps the whole page-shell (not just a subtree), so it needs
   the same explicit paint as daylight, plus suppression of <body>'s
   navy-tinted corner wash (see _base.css) — that wash was tuned for
   the "observatory at night" dark default and would show through as a
   stray navy glow at overscroll edges on an otherwise all-paper page. */
[data-theme='atelier'] {
  background: var(--aether-bg);
  color: var(--aether-text);
}

body:has([data-theme='atelier']) {
  background-image: none;
}


.s-hero__field {
  position: absolute;
  top: -10%;
  right: -8%;
  width: min(42vw, 480px);
  height: auto;
  aspect-ratio: 480 / 420;
  pointer-events: none;
  z-index: 0;
  opacity: 0.85;
}

.s-hero__field circle {
  transform-origin: center;
}

@media (prefers-reduced-motion: no-preference) {
  .s-hero__field .s-twinkle {
    animation: s-twinkle 4.5s ease-in-out infinite;
  }
  .s-hero__field .s-draw {
    stroke-dasharray: 420;
    stroke-dashoffset: 420;
    animation: s-draw 1.8s var(--aether-ease-emphasized-decelerate) 0.15s forwards;
  }
}

@keyframes s-twinkle {
  0%, 100% { opacity: 0.35; }
  50% { opacity: 1; }
}

@keyframes s-draw {
  to { stroke-dashoffset: 0; }
}

/* Source art is 1536x1024 with the wordmark/tagline block sitting in the
   vertical 32%-61% band. A 3/1 box + cover + center crops symmetrically to
   the 25%-75% band at every viewport width, so the text stays comfortably
   inside frame and full width is always shown (no left/right cropping).
   Full-bleed: breaks out of .l-container's max-width/padding to reach the
   true viewport edge, and a negative top margin cancels .s-hero's own
   padding-top so it sits flush under the navbar instead of floating in a
   gap below it. */
.s-hero__cover {
  position: relative;
  z-index: 1;
  display: block;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  margin-top: calc(-1 * var(--aether-space-32));
  aspect-ratio: 3 / 1;
  background-image: url('../assets/brand/samstudio coverpage.png');
  background-size: cover;
  background-position: center;
  margin-bottom: var(--aether-space-10);
}

.s-hero__eyebrow {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: var(--aether-space-3);
  font-family: var(--aether-font-mono);
  font-size: var(--aether-text-xs);
  letter-spacing: var(--aether-tracking-widest);
  text-transform: uppercase;
  color: var(--aether-accent);
  margin: 0 0 var(--aether-space-6);
}

.s-hero__eyebrow::before {
  content: '';
  width: 28px;
  height: 1px;
  background: var(--s-gold-dim);
  display: inline-block;
}

.s-hero__headline {
  position: relative;
  z-index: 1;
  font-family: var(--aether-font-heading);
  font-weight: 500;
  font-size: clamp(2.4rem, 1.9rem + 3vw, 4.6rem);
  line-height: 1.06;
  letter-spacing: var(--aether-tracking-tight);
  max-width: 34ch;
  text-wrap: balance;
  margin: 0 0 var(--aether-space-8);
  color: var(--aether-text);
}

.s-hero__headline em {
  font-style: italic;
  color: var(--aether-accent-hover);
}

/* The cover art carries the offer statement as baked-in type. That holds
   from ~600px up, but scales with the frame — on a 375px phone the
   tagline lands at roughly 7px and the location line at 4px, so the one
   thing a visitor most needs to read stops being readable exactly where
   most of them are. Below 600px the real headline takes the job back.
   It is the page's only H1 at every width — visually hidden above the
   breakpoint, never removed — so heading structure never changes. */
.s-hero__headline--sm-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

@media (max-width: 600px) {
  .s-hero__headline--sm-only {
    position: static;
    width: auto;
    height: auto;
    margin: 0 0 var(--aether-space-6);
    overflow: visible;
    clip: auto;
    white-space: normal;
    font-size: clamp(1.75rem, 1.35rem + 2.2vw, 2.3rem);
  }
}

.s-hero__sub {
  position: relative;
  z-index: 1;
  font-size: var(--aether-text-md);
  line-height: var(--aether-leading-normal);
  color: var(--aether-text-muted);
  max-width: var(--aether-content-width-normal);
  margin: 0 0 var(--aether-space-10);
}

.s-hero__actions {
  position: relative;
  z-index: 1;
  display: flex;
  flex-wrap: wrap;
  gap: var(--aether-space-4);
  margin-bottom: var(--aether-space-10);
}

.s-hero__meta {
  position: relative;
  z-index: 1;
  font-family: var(--aether-font-mono);
  font-size: var(--aether-text-xs);
  letter-spacing: var(--aether-tracking-wide);
  /* The real words (place names, availability) get the AA-passing
     color; only the decorative middot separators — redundant with the
     gap between them either way — get the faint tier. */
  color: var(--aether-text-muted);
  display: flex;
  gap: var(--aether-space-3);
}

.s-hero__meta span {
  color: var(--aether-text-faint);
}

@media (max-width: 700px) {
  .s-hero__field {
    display: none;
  }
}

/* ==========================================================================
   The honesty note — quiet, full-width, not a banner.
   ========================================================================== */
.s-note {
  border-top: 1px solid var(--aether-border);
  border-bottom: 1px solid var(--aether-border);
  padding-block: var(--aether-space-10);
}

.s-note p {
  max-width: var(--aether-content-width-wide);
  font-size: var(--aether-text-base);
  line-height: var(--aether-leading-relaxed);
  color: var(--aether-text-muted);
}

/* ==========================================================================
   Section system — hairline dividers instead of heavy visual breaks.
   ========================================================================== */
.s-section {
  padding-block: var(--aether-section-spacing-md);
  border-top: 1px solid var(--aether-border);
}

.s-section__label {
  font-family: var(--aether-font-mono);
  font-size: var(--aether-text-xs);
  letter-spacing: var(--aether-tracking-widest);
  text-transform: uppercase;
  color: var(--aether-accent);
  margin: 0 0 var(--aether-space-2);
}

.s-section__title {
  font-family: var(--aether-font-heading);
  font-weight: 500;
  font-size: var(--aether-text-2xl);
  max-width: 32ch;
  margin: 0 0 var(--aether-space-10);
  color: var(--aether-text);
}

/* Screenshot duotone/tint treatment was removed here — superseded by
   the Direction C decision that project work shows full native color on
   the light "gallery" canvas. See .s-plate__img below for the
   per-project placeholder color standing in until real screenshots
   exist. */

/* ==========================================================================
   Plates — the home page's featured-work treatment. Larger than a
   catalog row, image-led, same restraint underneath.
   ========================================================================== */
/* Gallery, not a comparison grid: one column always, generous space
   between pieces, no shared border joining them into a grid of cells.
   Each project is meant to be looked at on its own before the next one
   arrives — that's the whole point of three plates instead of a
   fifteen-row catalog. */
.s-plate-grid {
  display: flex;
  flex-direction: column;
  gap: var(--aether-space-32);
}

.s-plate {
  display: flex;
  flex-direction: column;
  gap: var(--aether-space-5);
  color: inherit;
  text-decoration: none;
}

.s-plate__num {
  font-family: var(--aether-font-mono);
  font-size: var(--aether-text-xs);
  letter-spacing: var(--aether-tracking-wide);
  color: var(--aether-text-muted);
}

.s-plate__img {
  height: 340px;
  border-radius: 2px;
  border: 1px solid var(--aether-border);
  background:
    linear-gradient(160deg, var(--aether-surface-2), var(--aether-surface-1)),
    repeating-linear-gradient(115deg, transparent 0 18px, rgba(198, 161, 91, 0.06) 18px 19px);
  transition: opacity var(--aether-transition-base);
}

/* Screenshot fitting for the plates. The `background` shorthand above
   resets size/position, so a plate given a real screenshot inline would
   otherwise paint it at native size anchored top-left — showing a corner
   fragment instead of the site. `cover` + `center top` fills the frame
   and keeps the part of a page that identifies it (nav + hero) rather
   than the middle of the scroll. Declared after the shorthand so it
   applies to both the gradient placeholders and real screenshots. */
.s-plate__img {
  background-size: cover;
  background-position: center top;
  background-repeat: no-repeat;
}

/* `cover` only crops vertically while the frame stays WIDER than the
   screenshot it holds; once the frame is narrower it starts cutting the
   sides, which slices the first characters off left-aligned headlines.
   The widest capture is 2.24:1, so below the width where a 340px-tall
   plate stops clearing that, the frame switches from a fixed height to a
   7/3 (2.33:1) ratio — never narrower than the art, so the crop stays
   vertical at every size. Desktop keeps its original fixed height. */
@media (max-width: 880px) {
  .s-plate__img {
    height: auto;
    aspect-ratio: 7 / 3;
  }
}

.s-plate:hover .s-plate__img,
.s-plate:focus-visible .s-plate__img {
  opacity: 0.88;
}

/* No fixed height here: a hard height at phone widths makes the frame
   far narrower than the art (≈1.5:1 against a 2.24:1 capture) and cover
   would cut a third of the width off the sides. The 7/3 ratio set above
   carries through instead. */

/* Per-project placeholder color, standing in for a real screenshot —
   approximating each project's own established palette, since the
   whole point of the light "gallery" canvas is letting client work
   keep its own identity instead of being tinted to match the studio's.
   Replace with a real <img> in Milestone 3+; drop these modifiers then. */
.s-plate__img--contour {
  background: linear-gradient(155deg, #f5f6f4, #e7dcd3 60%, #8a4a2b 130%);
}

.s-plate__img--nova {
  background: linear-gradient(155deg, #faf9f6, #d9e8de 55%, #1e5245 130%);
}

.s-plate__img--benin {
  background: linear-gradient(155deg, #f3e6ce, #e0b25f 55%, #c1440e 130%);
}

.s-plate__img--luna {
  background: linear-gradient(155deg, #f3e6ce, #e8a33d 55%, #1b2a4a 130%);
}

.s-plate__body {
  display: flex;
  flex-direction: column;
  gap: var(--aether-space-3);
  max-width: 56ch;
}

.s-plate__tag {
  font-family: var(--aether-font-mono);
  font-size: var(--aether-text-xs);
  letter-spacing: var(--aether-tracking-wide);
  text-transform: uppercase;
  color: var(--aether-accent);
}

.s-plate h3 {
  font-family: var(--aether-font-heading);
  font-weight: 500;
  font-size: var(--aether-text-xl);
  margin: 0;
  color: var(--aether-text);
}

.s-plate p {
  font-size: var(--aether-text-sm);
  line-height: var(--aether-leading-normal);
  color: var(--aether-text-muted);
  margin: 0;
}

.s-plate__proves {
  font-size: var(--aether-text-sm);
  color: var(--aether-text);
  margin: 0;
  padding-top: var(--aether-space-2);
  border-top: 1px dashed var(--aether-border);
}

/* ==========================================================================
   Catalog — the work index. Rows, not boxes: a scannable list where the
   number is a real coordinate tag (tier position), not decoration.
   ========================================================================== */
.s-catalog {
  border-top: 1px solid var(--aether-border);
}

.s-catalog__group-label {
  font-family: var(--aether-font-mono);
  font-size: var(--aether-text-xs);
  letter-spacing: var(--aether-tracking-widest);
  text-transform: uppercase;
  color: var(--aether-text-muted);
  padding-top: var(--aether-space-10);
  padding-bottom: var(--aether-space-3);
}

.s-catalog__group-label:first-child {
  padding-top: var(--aether-space-6);
}

.s-catalog-row {
  display: grid;
  grid-template-columns: 64px 1fr auto;
  gap: var(--aether-space-6);
  align-items: center;
  padding: var(--aether-space-6) var(--aether-space-2);
  border-bottom: 1px solid var(--aether-border);
  text-decoration: none;
  color: inherit;
}

.s-catalog-row:hover .s-catalog-row__title,
.s-catalog-row:focus-visible .s-catalog-row__title {
  color: var(--aether-accent-hover);
}

.s-catalog-row__num {
  font-family: var(--aether-font-mono);
  font-size: var(--aether-text-xs);
  letter-spacing: var(--aether-tracking-wide);
  color: var(--aether-text-muted);
}

.s-catalog-row__title {
  font-family: var(--aether-font-heading);
  font-weight: 500;
  font-size: var(--aether-text-md);
  margin: 0 0 var(--aether-space-1);
  color: var(--aether-text);
  transition: color var(--aether-transition-fast);
}

.s-catalog-row__desc {
  margin: 0;
  font-size: var(--aether-text-sm);
  color: var(--aether-text-muted);
  max-width: 60ch;
  line-height: var(--aether-leading-normal);
}

.s-catalog-row__chip {
  font-family: var(--aether-font-mono);
  font-size: 10px;
  letter-spacing: var(--aether-tracking-widest);
  text-transform: uppercase;
  color: var(--aether-accent);
  border: 1px solid var(--s-gold-dim);
  border-radius: var(--aether-radius-full);
  padding: var(--aether-space-1) var(--aether-space-3);
  white-space: nowrap;
}

.s-catalog-row__chip--muted {
  color: var(--aether-text-muted);
  border-color: var(--aether-border-strong);
}

@media (max-width: 700px) {
  .s-catalog-row {
    grid-template-columns: 1fr;
    gap: var(--aether-space-2);
  }
  .s-catalog-row__num {
    order: -1;
  }
}

/* ==========================================================================
   Work gallery — Atelier Phase 2. Replaces .s-catalog-row's flat list on
   the Work index only (that rule stays in the file, unused there, in
   case anything else ever needs a bare text row again). Two distinct
   treatments for two honestly different things: full case studies get
   real visual presence (large plate, alternating side), smaller catalog
   work stays compact — neither pretends to be the other. Numbering
   restarts per group (01, 02, 03…) on purpose: two collections, not one
   ranked list, so nothing reads as "the 13th-best project."
   ========================================================================== */
.s-work-intro {
  display: flex;
  align-items: center;
  gap: var(--aether-space-6);
  margin-bottom: var(--aether-space-4);
}

/* -------------------- Full case studies -------------------- */
.s-work-feature-list {
  display: flex;
  flex-direction: column;
  gap: var(--aether-space-24);
}

.s-work-feature {
  display: flex;
  gap: var(--aether-space-10);
  align-items: center;
  text-decoration: none;
  color: inherit;
}

.s-work-feature:nth-child(even) {
  flex-direction: row-reverse;
}

/* The frame was 4/3 with `cover`, sized for abstract gradient art. Real
   browser captures run about 2:1, so cover was scaling them to fill the
   height and cutting roughly a third off each side — enough to slice the
   opening characters off left-aligned headlines and body copy. Now the
   frame matches the captures (2/1) and uses `contain`, so the whole page
   is always shown and nothing is ever cut mid-word; the small letterbox
   left over reads as a mat, which suits the gallery framing. Per-project
   overrides still apply inline — Adjatché is a portrait phone frame and
   keeps its own contain + dark mat. */
.s-work-feature__visual {
  position: relative;
  flex: 1 1 52%;
  aspect-ratio: 2 / 1;
  border-radius: 2px;
  overflow: hidden;
  border: 1px solid var(--aether-border);
  background-color: var(--aether-surface-1);
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  transition: opacity var(--aether-transition-base);
}

.s-work-feature:hover .s-work-feature__visual,
.s-work-feature:focus-visible .s-work-feature__visual {
  opacity: 0.9;
}

.s-work-feature__pending {
  position: absolute;
  left: var(--aether-space-3);
  bottom: var(--aether-space-3);
  font-family: var(--aether-font-mono);
  font-size: 10px;
  letter-spacing: var(--aether-tracking-wide);
  text-transform: uppercase;
  color: #f6efe1;
  background: rgba(20, 17, 14, 0.6);
  padding: var(--aether-space-1) var(--aether-space-3);
  border-radius: var(--aether-radius-full);
}

.s-work-feature__body {
  flex: 1 1 48%;
}

/* Same 2.86:1 shortfall as the catalog ordinals — see note there. */
.s-work-feature__num {
  display: block;
  font-family: var(--aether-font-mono);
  font-size: var(--aether-text-sm);
  letter-spacing: var(--aether-tracking-wide);
  color: var(--aether-text-muted);
  margin-bottom: var(--aether-space-4);
}

.s-work-feature__body h3 {
  font-family: var(--aether-font-heading);
  font-weight: 500;
  font-size: var(--aether-text-2xl);
  margin: 0 0 var(--aether-space-3);
  color: var(--aether-text);
  transition: color var(--aether-transition-fast);
}

.s-work-feature:hover .s-work-feature__body h3,
.s-work-feature:focus-visible .s-work-feature__body h3 {
  color: var(--aether-accent-hover);
}

.s-work-feature__body p {
  font-size: var(--aether-text-md);
  line-height: var(--aether-leading-relaxed);
  color: var(--aether-text-muted);
  max-width: 48ch;
  margin: 0 0 var(--aether-space-4);
}

.s-work-feature__tag {
  display: inline-block;
  font-family: var(--aether-font-mono);
  font-size: 10px;
  letter-spacing: var(--aether-tracking-widest);
  text-transform: uppercase;
  color: var(--aether-accent);
  border: 1px solid var(--s-gold-dim);
  border-radius: var(--aether-radius-full);
  padding: var(--aether-space-1) var(--aether-space-3);
}

@media (max-width: 780px) {
  .s-work-feature,
  .s-work-feature:nth-child(even) {
    flex-direction: column;
    align-items: stretch;
    gap: var(--aether-space-5);
  }
}

/* -------------------- Smaller catalog work -------------------- */
.s-work-compact-list {
  display: flex;
  flex-direction: column;
}

.s-work-compact {
  display: grid;
  grid-template-columns: 44px 84px 1fr auto;
  gap: var(--aether-space-5);
  align-items: center;
  padding: var(--aether-space-5) var(--aether-space-2);
  border-bottom: 1px solid var(--aether-border);
  text-decoration: none;
  color: inherit;
}

/* Measured 2.86:1 on the gallery panel at faint — under AA for 12.8px.
   These ordinals carry the catalog's order, so they are content, not
   ornament; muted keeps them subordinate to the title and passes. */
.s-work-compact__num {
  font-family: var(--aether-font-mono);
  font-size: var(--aether-text-xs);
  color: var(--aether-text-muted);
}

.s-work-compact__visual {
  position: relative;
  width: 84px;
  height: 60px;
  border-radius: 2px;
  overflow: hidden;
  border: 1px solid var(--aether-border);
  background-size: cover;
  background-position: center;
  flex-shrink: 0;
}

.s-work-compact__pending {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: flex-end;
  padding: 3px 4px;
}

.s-work-compact__pending span {
  font-family: var(--aether-font-mono);
  font-size: 8px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #f6efe1;
  background: rgba(20, 17, 14, 0.6);
  padding: 1px 5px;
  border-radius: var(--aether-radius-full);
}

.s-work-compact__title {
  font-family: var(--aether-font-heading);
  font-weight: 500;
  font-size: var(--aether-text-md);
  margin: 0 0 var(--aether-space-1);
  color: var(--aether-text);
  transition: color var(--aether-transition-fast);
}

.s-work-compact:hover .s-work-compact__title,
.s-work-compact:focus-visible .s-work-compact__title {
  color: var(--aether-accent-hover);
}

/* Catalog rows on the French index point at case studies that only exist
   in English so far. Saying so before the click is the honest move — a
   site that claims bilingual done properly shouldn't switch language on
   someone without warning. The chip is never the only signal: each link
   also carries hreflang and a visually hidden sentence, so the meaning
   survives without colour or layout. */
/* AETHER has no case study to link to yet, and an <a href="#"> that
   silently jumps to the top reads as a broken link. The row keeps its
   place in the catalog as a plain element instead — the Pending badge
   already says why there is nothing to open. Muted so it does not
   invite a click it cannot honour. */
.s-work-compact--inert {
  cursor: default;
}

.s-work-compact--inert .s-work-compact__title {
  color: var(--aether-text-muted);
}

.s-work-compact__lang {
  display: inline-block;
  margin-left: var(--aether-space-3);
  vertical-align: middle;
  font-family: var(--aether-font-mono);
  font-size: 10px;
  letter-spacing: var(--aether-tracking-widest);
  text-transform: uppercase;
  /* muted, not faint: faint measured 2.86:1 on the gallery panel, which
     fails AA for text this size. Muted clears it. */
  color: var(--aether-text-muted);
  border: 1px solid var(--aether-border-strong);
  border-radius: var(--aether-radius-full);
  padding: 1px var(--aether-space-2);
  white-space: nowrap;
}

.s-work-compact__desc {
  margin: 0;
  font-size: var(--aether-text-sm);
  color: var(--aether-text-muted);
  max-width: 52ch;
  line-height: var(--aether-leading-normal);
}

.s-work-compact__tag {
  font-family: var(--aether-font-mono);
  font-size: 10px;
  letter-spacing: var(--aether-tracking-widest);
  text-transform: uppercase;
  color: var(--aether-text-muted);
  border: 1px solid var(--aether-border-strong);
  border-radius: var(--aether-radius-full);
  padding: var(--aether-space-1) var(--aether-space-3);
  white-space: nowrap;
}

@media (max-width: 700px) {
  .s-work-compact {
    grid-template-columns: 44px 1fr;
    grid-template-areas:
      "num visual"
      "num body"
      "num tag";
    row-gap: var(--aether-space-2);
  }
  .s-work-compact__num { grid-area: num; }
  .s-work-compact__visual { grid-area: visual; width: 100%; height: 120px; }
  .s-work-compact__body { grid-area: body; }
  .s-work-compact__tag { grid-area: tag; justify-self: start; }
}

/* ==========================================================================
   Services — a teaser for /services, not the full offer. Three parallel
   options, not a sequence, so no numbering here (see .s-process below for
   where numbers are actually earned).
   ========================================================================== */
.s-services-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1px;
  background: var(--aether-border);
  border: 1px solid var(--aether-border);
}

@media (min-width: 768px) {
  .s-services-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

.s-service-card {
  background: var(--aether-bg);
  padding: var(--aether-space-8) var(--aether-space-6);
  display: flex;
  flex-direction: column;
  gap: var(--aether-space-3);
}

.s-service-card h3 {
  font-family: var(--aether-font-heading);
  font-weight: 500;
  font-size: var(--aether-text-lg);
  color: var(--aether-text);
  margin: 0;
}

.s-service-card p {
  font-size: var(--aether-text-sm);
  line-height: var(--aether-leading-normal);
  color: var(--aether-text-muted);
  margin: 0;
}

/* ==========================================================================
   Offering rows — the /services page's own full treatment of the same
   three things .s-service-card teases on the home page. An editorial
   stacked list, not another bordered card grid: each offering gets full
   width and real room, marked with the studio glyph instead of a number
   (three parallel options, not a sequence).
   ========================================================================== */
.s-offering-list {
  display: flex;
  flex-direction: column;
}

.s-offering {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--aether-space-6);
  align-items: start;
  padding-block: var(--aether-space-10);
  border-top: 1px solid var(--aether-border);
}

.s-offering:first-child {
  border-top: none;
  padding-top: 0;
}

.s-offering__mark {
  flex-shrink: 0;
  color: var(--s-gold-bright);
  margin-top: var(--aether-space-1);
}

.s-offering__body h3 {
  font-family: var(--aether-font-heading);
  font-weight: 500;
  font-size: var(--aether-text-xl);
  margin: 0 0 var(--aether-space-3);
  color: var(--aether-text);
}

.s-offering__desc {
  font-size: var(--aether-text-md);
  line-height: var(--aether-leading-relaxed);
  color: var(--aether-text-muted);
  max-width: 60ch;
  margin: 0 0 var(--aether-space-3);
}

.s-offering__for {
  font-size: var(--aether-text-sm);
  color: var(--aether-text-muted);
  margin: 0;
}

.s-offering__for strong {
  color: var(--aether-text);
  font-weight: 600;
}

@media (max-width: 640px) {
  .s-offering {
    grid-template-columns: 1fr;
    gap: var(--aether-space-3);
  }
}

/* ==========================================================================
   Service items — Atelier Phase 3's own rhythm for /services, distinct
   from both .s-offering (the older icon-led pattern, still used on
   About) and Work's image-plate rows. No image — a service isn't a
   project with a color to show, so a large, confident catalogue
   number carries the anchor instead. The "for" line gets a small
   ember rule of its own so it reads as a distinct, scannable answer
   to "is this me?" rather than a second paragraph.
   ========================================================================== */
.s-service-list {
  display: flex;
  flex-direction: column;
}

.s-service-item {
  display: grid;
  grid-template-columns: 110px 1fr;
  gap: var(--aether-space-8);
  padding-block: var(--aether-space-12);
  border-top: 1px solid var(--aether-border);
}

.s-service-item:first-child {
  border-top: none;
  padding-top: 0;
}

.s-service-item__num {
  font-family: var(--aether-font-mono);
  font-size: clamp(2.2rem, 1.9rem + 1.2vw, 3rem);
  line-height: 1;
  color: var(--aether-border-strong);
}

.s-service-item__body h3 {
  font-family: var(--aether-font-heading);
  font-weight: 500;
  font-size: var(--aether-text-2xl);
  text-wrap: balance;
  margin: 0 0 var(--aether-space-4);
  color: var(--aether-text);
}

.s-service-item__desc {
  font-size: var(--aether-text-md);
  line-height: var(--aether-leading-relaxed);
  color: var(--aether-text-muted);
  max-width: 62ch;
  margin: 0 0 var(--aether-space-5);
}

.s-service-item__for {
  display: flex;
  gap: var(--aether-space-4);
  border-left: 2px solid var(--aether-accent);
  padding-left: var(--aether-space-4);
  max-width: 56ch;
}

.s-service-item__for-label {
  flex-shrink: 0;
  font-family: var(--aether-font-mono);
  font-size: var(--aether-text-xs);
  letter-spacing: var(--aether-tracking-wide);
  text-transform: uppercase;
  color: var(--aether-accent);
  padding-top: 2px;
}

.s-service-item__for p {
  margin: 0;
  font-size: var(--aether-text-sm);
  color: var(--aether-text-muted);
  line-height: var(--aether-leading-normal);
}

@media (max-width: 640px) {
  .s-service-item {
    grid-template-columns: 1fr;
    gap: var(--aether-space-4);
  }
  .s-service-item__for {
    flex-direction: column;
    gap: var(--aether-space-1);
  }
}

/* ==========================================================================
   About mark — a navy plate carrying the studio glyph at large scale,
   standing in for a portrait until a real photo exists. Deliberately
   reads as a brand mark, not an apologetic placeholder box: same navy
   the hero runs on, same gold the glyph always uses.
   ========================================================================== */
.s-about-mark {
  aspect-ratio: 4 / 5;
  border-radius: 3px;
  background: linear-gradient(155deg, #24365e, #1b2a4a);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--s-atelier-gold);
}

/* ==========================================================================
   Values — About's own rhythm. Neither Work's imagery nor Services'
   large numerals: just a hairline rule and type, the quietest of the
   three because this page is meant to feel personal, not presented.
   ========================================================================== */
.s-value-list {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--aether-space-10) var(--aether-space-12);
}

.s-value-item {
  border-top: 1px solid var(--aether-border);
  padding-top: var(--aether-space-5);
}

.s-value-item h3 {
  font-family: var(--aether-font-heading);
  font-weight: 500;
  font-size: var(--aether-text-lg);
  margin: 0 0 var(--aether-space-3);
  color: var(--aether-text);
}

.s-value-item p {
  font-size: var(--aether-text-sm);
  line-height: var(--aether-leading-relaxed);
  color: var(--aether-text-muted);
  margin: 0;
}

@media (max-width: 640px) {
  .s-value-list {
    grid-template-columns: 1fr;
    gap: var(--aether-space-6);
  }
}

.s-section__more {
  display: inline-flex;
  align-items: center;
  gap: var(--aether-space-2);
  margin-top: var(--aether-space-8);
  font-family: var(--aether-font-mono);
  font-size: var(--aether-text-xs);
  letter-spacing: var(--aether-tracking-wide);
  color: var(--aether-accent);
  transition: color var(--aether-transition-fast);
  /* Text stays small; the hit area doesn't — same technique as the
     language toggle's 44px tap target. */
  min-height: 44px;
  margin-block: calc(var(--aether-space-8) - 12px) -12px;
  padding-block: 12px;
}

.s-section__more:hover {
  color: var(--aether-accent-hover);
}

/* ==========================================================================
   Email row — mailto: link plus a copy fallback. Some browsers have no
   mail client configured and open a blank tab on mailto: instead of
   doing anything useful, so the address needs to be reachable without
   relying on that handoff working.
   ========================================================================== */
.s-email-row {
  display: inline-flex;
  align-items: center;
  gap: var(--aether-space-4);
  flex-wrap: wrap;
  justify-content: center;
}

.s-copy-btn {
  font-family: var(--aether-font-mono);
  font-size: var(--aether-text-xs);
  letter-spacing: var(--aether-tracking-wide);
  color: var(--aether-accent);
  background: none;
  border: 1px solid var(--aether-border);
  border-radius: var(--aether-radius-md);
  cursor: pointer;
  transition: color var(--aether-transition-fast), border-color var(--aether-transition-fast);
  min-height: 44px;
  min-width: 44px;
  padding-inline: var(--aether-space-4);
}

.s-copy-btn:hover {
  color: var(--aether-accent-hover);
  border-color: var(--aether-accent-hover);
}

/* ==========================================================================
   Process — "How I work." A real sequence, so real numbers: this is
   exactly the case the numbered-marker exception is for.
   ========================================================================== */
.s-process {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--aether-space-10);
}

@media (min-width: 768px) {
  .s-process {
    grid-template-columns: repeat(4, 1fr);
    gap: var(--aether-space-6);
  }

  /* Column-count modifier only — everywhere else .s-process--3 behaves
     exactly like .s-process. Used where a sequence genuinely has 3
     steps instead of 4, so it doesn't render with an empty trailing
     column. */
  .s-process--3 {
    grid-template-columns: repeat(3, 1fr);
  }
}

.s-process-step {
  padding-top: var(--aether-space-5);
  border-top: 1px solid var(--s-gold-dim);
}

.s-process-step__num {
  display: block;
  font-family: var(--aether-font-mono);
  font-size: var(--aether-text-sm);
  color: var(--aether-accent);
  margin-bottom: var(--aether-space-3);
}

.s-process-step h3 {
  font-family: var(--aether-font-heading);
  font-weight: 500;
  font-size: var(--aether-text-md);
  margin: 0 0 var(--aether-space-2);
  color: var(--aether-text);
}

.s-process-step p {
  font-size: var(--aether-text-sm);
  line-height: var(--aether-leading-normal);
  color: var(--aether-text-muted);
  margin: 0;
}

/* ==========================================================================
   Standards — a specification plate, not another card grid. Quiet,
   dense, mono — the register of a nameplate, not a marketing claim.
   ========================================================================== */
.s-standards {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--aether-space-4) var(--aether-space-8);
}

.s-standards li {
  font-family: var(--aether-font-mono);
  font-size: var(--aether-text-xs);
  letter-spacing: var(--aether-tracking-wide);
  color: var(--aether-text-muted);
  padding-left: var(--aether-space-5);
  position: relative;
}

.s-standards li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.55em;
  width: 12px;
  height: 1px;
  background: var(--s-gold-dim);
}

/* ==========================================================================
   Final CTA — quiet close, not a colored banner. Same ground as every
   other section; the only shift is centering and a single strong action.
   ========================================================================== */
.s-final-cta {
  text-align: center;
  background: var(--aether-bg);
  color: var(--aether-text);
}

/* Atelier pages only: the one deliberate navy moment on an otherwise
   all-paper page — see the theme file's contrast table for why paper
   and gold are the only two colors allowed as text here. Scoped to a
   modifier class rather than the bare .s-final-cta so that the navy
   pages, which already sit on this ground, are unaffected. Services and
   About are the Atelier pages and both use it; no page is pending
   migration. */
[data-theme='atelier'] .s-final-cta--band {
  background: var(--aether-secondary);
  color: var(--aether-text-on-secondary);
}

[data-theme='atelier'] .s-final-cta--band .s-final-cta__title {
  color: var(--aether-text-on-secondary);
}

[data-theme='atelier'] .s-final-cta--band .s-final-cta__sub {
  color: color-mix(in oklch, var(--aether-text-on-secondary) 78%, transparent);
}

[data-theme='atelier'] .s-final-cta--band .s-seal,
[data-theme='atelier'] .s-final-cta--band .s-final-cta__mark {
  color: var(--s-atelier-gold);
}

/* The default .c-button--cta is ink-on-paper (1.15:1 against navy —
   effectively invisible there, confirmed by direct measurement, not
   assumed). Inverted here: same solid-fill language, paper-on-navy
   (12.43:1) instead. */
[data-theme='atelier'] .s-final-cta--band .c-button--cta {
  background: var(--aether-text-on-secondary);
  color: var(--aether-secondary);
}

[data-theme='atelier'] .s-final-cta--band .c-button--cta:hover {
  background: color-mix(in oklch, var(--aether-text-on-secondary) 88%, var(--aether-secondary) 12%);
}

/* .c-button--ghost defaults to --aether-text-muted (2.28:1 against navy
   here — measured, not assumed — since it's tuned for muted text on
   paper, not on the one dark band on the page). Needed the moment a
   ghost button appears alongside the cta button in this band (About's
   closing CTA is the first page to pair them here). */
[data-theme='atelier'] .s-final-cta--band .c-button--ghost {
  color: var(--aether-text-on-secondary);
}

[data-theme='atelier'] .s-final-cta--band .c-button--ghost:hover {
  background: color-mix(in oklch, var(--aether-text-on-secondary) 15%, transparent);
  color: var(--aether-text-on-secondary);
}

.s-final-cta__mark {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-bottom: var(--aether-space-6);
  font-family: var(--aether-font-heading);
  font-style: italic;
  font-weight: 500;
  font-size: var(--aether-text-md);
  color: var(--aether-accent-hover);
}

.s-final-cta__title {
  font-family: var(--aether-font-heading);
  font-weight: 500;
  font-size: var(--aether-text-2xl);
  margin: 0 auto var(--aether-space-4);
  max-width: 24ch;
  color: var(--aether-text);
}

.s-final-cta__sub {
  font-size: var(--aether-text-base);
  color: var(--aether-text-muted);
  max-width: var(--aether-content-width-narrow);
  margin: 0 auto var(--aether-space-8);
}

/* ==========================================================================
   Case study — long-form, editorial. Header is its own navy "cover"
   moment (same register as the homepage hero); everything from the
   brief onward sits on the [data-theme="daylight"] AETHER pattern's
   .p-article-layout, which already gives consistent "owl" rhythm
   spacing between blocks — this file only adds what that pattern
   doesn't cover. Each project's own real palette (hero shot, palette
   chips) is what carries visual variation between case studies — no
   accent-tinting layer on top of it.
   ========================================================================== */
.s-case-header {
  background: var(--aether-bg);
  color: var(--aether-text);
  padding-block: var(--aether-space-24) var(--aether-space-16);
}

.s-case-header__tag {
  font-family: var(--aether-font-mono);
  font-size: var(--aether-text-xs);
  letter-spacing: var(--aether-tracking-widest);
  text-transform: uppercase;
  color: var(--aether-accent);
  border: 1px solid var(--s-gold-dim);
  border-radius: var(--aether-radius-full);
  padding: var(--aether-space-1) var(--aether-space-3);
  display: inline-block;
  margin-bottom: var(--aether-space-5);
}

.s-case-header h1 {
  font-family: var(--aether-font-heading);
  font-weight: 500;
  font-size: clamp(2.2rem, 1.8rem + 2vw, 3.4rem);
  line-height: 1.08;
  margin: 0 0 var(--aether-space-4);
  max-width: 18ch;
  color: var(--aether-text);
}

.s-case-header__desc {
  font-size: var(--aether-text-md);
  color: var(--aether-text-muted);
  max-width: var(--aether-content-width-normal);
  margin: 0 0 var(--aether-space-8);
}

.s-case-header__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--aether-space-5);
  margin-bottom: var(--aether-space-10);
}

/* Source stays available, but secondary — a client visitor has no use
   for a GitHub link fighting the primary CTA for attention. */
.s-case-header__source {
  font-family: var(--aether-font-mono);
  font-size: var(--aether-text-xs);
  letter-spacing: var(--aether-tracking-wide);
  color: var(--aether-text-muted);
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding-inline: var(--aether-space-2);
  margin-inline: calc(var(--aether-space-2) * -1);
  transition: color var(--aether-transition-fast);
}

.s-case-header__source:hover {
  color: var(--aether-text);
}

.s-case-header__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--aether-space-2) var(--aether-space-6);
  padding-top: var(--aether-space-6);
  border-top: 1px solid var(--aether-border);
  font-family: var(--aether-font-mono);
  font-size: var(--aether-text-xs);
  letter-spacing: var(--aether-tracking-wide);
}

.s-case-header__meta dt {
  color: var(--aether-accent);
  display: inline;
}

.s-case-header__meta dd {
  color: var(--aether-text-muted);
  display: inline;
  margin: 0 0 0 var(--aether-space-2);
}

/* --------------------------------------------------------------------
   Article body — content-level components layered onto AETHER's
   .p-article-layout. Headings inside the body are h2/h3, styled to
   match the rest of the site rather than the article pattern's
   defaults, which are generic on purpose (it has no opinion about a
   specific project's brand).
   -------------------------------------------------------------------- */
.p-article-layout__body h2 {
  font-family: var(--aether-font-heading);
  font-weight: 500;
  font-size: var(--aether-text-2xl);
  color: var(--aether-text);
}

.p-article-layout__body h3 {
  font-family: var(--aether-font-heading);
  font-weight: 500;
  font-size: var(--aether-text-lg);
  color: var(--aether-text);
}

.p-article-layout__body > p {
  font-size: var(--aether-text-base);
  line-height: var(--aether-leading-relaxed);
  color: var(--aether-text-muted);
}

.s-case-eyebrow {
  font-family: var(--aether-font-mono);
  font-size: var(--aether-text-xs);
  letter-spacing: var(--aether-tracking-widest);
  text-transform: uppercase;
  color: var(--aether-accent);
  margin-bottom: var(--aether-space-2) !important;
}

.s-case-constraints {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--aether-space-4);
}

.s-case-constraints li {
  padding-left: var(--aether-space-5);
  position: relative;
  font-size: var(--aether-text-base);
  line-height: var(--aether-leading-relaxed);
  color: var(--aether-text-muted);
}

.s-case-constraints li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.65em;
  width: 12px;
  height: 1px;
  background: var(--gold-on-light, var(--aether-accent));
}

.s-case-constraints strong {
  color: var(--aether-text);
}

/* Palette swatches — real project tokens, not invented values. */
.s-case-palette {
  display: flex;
  flex-wrap: wrap;
  gap: var(--aether-space-4);
  list-style: none;
  margin: 0;
  padding: 0;
}

.s-case-palette li {
  width: 92px;
}

.s-case-palette__chip {
  height: 56px;
  border-radius: 3px;
  border: 1px solid var(--aether-border);
  margin-bottom: var(--aether-space-2);
}

.s-case-palette__name {
  font-family: var(--aether-font-mono);
  font-size: 10.5px;
  color: var(--aether-text-muted);
  display: block;
}

.s-case-type-row {
  display: flex;
  align-items: baseline;
  gap: var(--aether-space-5);
  padding-block: var(--aether-space-3);
  border-bottom: 1px dashed var(--aether-border);
}

.s-case-type-row:last-child {
  border-bottom: none;
}

/* Measured 2.86:1 at faint on the article surface — under AA at 11px.
   These label which typeface does what, so they have to be readable. */
.s-case-type-row__role {
  font-family: var(--aether-font-mono);
  font-size: 11px;
  color: var(--aether-text-muted);
  width: 110px;
  flex-shrink: 0;
}

/* Screenshot placeholders — clearly labeled as placeholders, not
   presented as real captures. Real screenshots replace these once
   captured; see the case-study content-production checklist. */
.s-case-shots {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--aether-space-4);
  list-style: none;
  margin: 0;
  padding: 0;
}

.s-case-shots li {
  aspect-ratio: 16 / 10;
  border-radius: 3px;
  border: 1px dashed var(--aether-border-strong);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--aether-font-mono);
  font-size: 11px;
  /* Deliberately quiet, but 2.86:1 at faint was under AA. The dashed
     border already signals "placeholder"; the label still has to be
     readable to do its job. */
  color: var(--aether-text-muted);
  text-align: center;
  padding: var(--aether-space-3);
}

/* --------------------------------------------------------------------
   Decision block — the load-bearing section. Reads like a case file,
   not a feature card: a title, then labeled fields in sequence. The
   reasoning behind a choice is content here, not a caption under it.
   -------------------------------------------------------------------- */
.s-decision {
  background: var(--aether-surface-1);
  border: 1px solid var(--aether-border);
  border-radius: 4px;
  padding: var(--aether-space-8);
  margin-top: var(--aether-space-8) !important;
}

.s-decision__num {
  font-family: var(--aether-font-mono);
  font-size: var(--aether-text-xs);
  color: var(--aether-text-faint);
  display: block;
  margin-bottom: var(--aether-space-2);
}

.s-decision h3 {
  margin: 0 0 var(--aether-space-6);
}

.s-decision__field {
  padding-top: var(--aether-space-5);
  border-top: 1px solid var(--aether-border);
}

.s-decision__field:first-of-type {
  border-top: none;
  padding-top: 0;
}

.s-decision__field dt {
  font-family: var(--aether-font-mono);
  font-size: 10.5px;
  letter-spacing: var(--aether-tracking-widest);
  text-transform: uppercase;
  color: var(--aether-accent);
  margin-bottom: var(--aether-space-2);
}

.s-decision__field dd {
  margin: 0;
  font-size: var(--aether-text-sm);
  line-height: var(--aether-leading-relaxed);
  color: var(--aether-text-muted);
}

.s-decision__field--result dd {
  color: var(--aether-text);
}

.s-case-a11y {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--aether-space-3);
}

.s-case-a11y li {
  padding-left: var(--aether-space-5);
  position: relative;
  font-size: var(--aether-text-sm);
  line-height: var(--aether-leading-relaxed);
  color: var(--aether-text-muted);
}

.s-case-a11y li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.6em;
  width: 12px;
  height: 1px;
  background: var(--s-gold-dim);
}

.s-case-a11y strong {
  color: var(--aether-text);
  font-weight: var(--aether-weight-semibold);
}

.s-case-stack {
  display: flex;
  flex-wrap: wrap;
  gap: var(--aether-space-3);
  list-style: none;
  margin: 0 0 var(--aether-space-8) !important;
  padding: 0;
}

.s-case-stack li {
  font-family: var(--aether-font-mono);
  font-size: var(--aether-text-xs);
  color: var(--aether-text-muted);
  border: 1px solid var(--aether-border);
  border-radius: var(--aether-radius-full);
  padding: var(--aether-space-1) var(--aether-space-3);
}

.s-case-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--aether-space-4);
}

/* Prev/next — the article pattern's own footer slot. Only one case
   study exists right now, so there's no real neighbor to link to yet;
   this shows a single honest "back to all work" link rather than a
   next-case-study link that would point nowhere. */
.s-case-nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-family: var(--aether-font-mono);
  font-size: var(--aether-text-xs);
  letter-spacing: var(--aether-tracking-wide);
}

.s-case-nav a {
  color: var(--aether-accent);
  transition: color var(--aether-transition-fast);
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  margin-block: -12px;
  padding-block: 12px;
}

.s-case-nav a:hover {
  color: var(--aether-accent-hover);
}

/* ==========================================================================
   Case study — client-first revision. The default reading path (hero
   visual → story → highlights → design → outcomes → CTA) is short and
   visual on purpose; full technical depth moves into .s-case-disclosure
   below rather than disappearing.
   ========================================================================== */

/* Hero visual — the first thing in the light zone, before any prose.
   See the work before reading about it. */
/* Same fitting problem as the Work index frames, same fix: a fixed
   height made the frame narrower than the ~2:1 captures it holds, so
   `cover` cut the sides and sliced the first characters off left-aligned
   text. A 2/1 ratio plus `contain` shows the whole capture at any width.
   Pages whose screenshot is portrait or square (a phone frame, a card)
   keep their own mat colour inline and simply centre within the frame. */
.s-case-hero-shot {
  position: relative;
  aspect-ratio: 2 / 1;
  border-radius: 3px;
  border: 1px solid var(--aether-border);
  background-color: var(--aether-surface-1);
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  margin-top: 0 !important;
}

/* Portrait captures — a phone frame, a narrow card — in a 2/1 landscape
   frame. That is fine on a wide screen, where the mat reads as a stage,
   but on a phone the frame narrows faster than the art and the shot
   collapses: measured at 320px, Adjatché painted 76px wide inside a
   280px frame (73% mat), which is no longer legible as a screenshot.
   Below 700px these three switch to an upright frame so the art keeps
   real size. Still `contain`, so nothing is ever cropped either way. */
@media (max-width: 700px) {
  .s-case-hero-shot--portrait {
    aspect-ratio: 3 / 4;
  }
}

/* Highlights — "what makes it work." Lighter than the old decision
   dossier: a hook phrase and one supporting sentence, set apart by a
   thin rule rather than a bordered card. Meant to be scanned in
   seconds, not studied. */
.s-case-highlights {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--aether-space-6);
}

.s-case-highlight {
  padding-left: var(--aether-space-5);
  border-left: 2px solid var(--s-gold-dim);
}

.s-case-highlight strong {
  display: block;
  font-family: var(--aether-font-heading);
  font-weight: 500;
  font-size: var(--aether-text-md);
  color: var(--aether-text);
  margin-bottom: var(--aether-space-1);
}

.s-case-highlight span {
  font-size: var(--aether-text-sm);
  line-height: var(--aether-leading-relaxed);
  color: var(--aether-text-muted);
}

/* Outcomes — "built to last." Short, plain-language, scannable —
   the translated version of what used to be a jargon bullet list. */
.s-case-outcomes {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--aether-space-3) var(--aether-space-8);
}

@media (min-width: 640px) {
  .s-case-outcomes {
    grid-template-columns: 1fr 1fr;
  }
}

.s-case-outcomes li {
  font-size: var(--aether-text-sm);
  line-height: var(--aether-leading-normal);
  color: var(--aether-text);
  padding-left: var(--aether-space-5);
  position: relative;
}

.s-case-outcomes li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.6em;
  width: 12px;
  height: 1px;
  background: var(--s-gold-dim);
}

/* Closing CTA — same shape as the homepage's, scaled to a case study. */
.s-case-close {
  text-align: center;
  padding-block: var(--aether-space-10);
  border-top: 1px solid var(--aether-border);
  border-bottom: 1px solid var(--aether-border);
}

.s-case-close p {
  color: var(--aether-text-muted);
  margin-bottom: var(--aether-space-6);
}

.s-case-close .c-button {
  margin-inline: var(--aether-space-2);
}

/* --------------------------------------------------------------------
   Technical disclosure — everything that used to be forced reading
   lives here now, trimmed, closed by default. Native <details> means
   this needs no JavaScript and is keyboard-operable for free; only the
   visual chrome around the browser default is this file's job.
   -------------------------------------------------------------------- */
.s-case-disclosure {
  margin-top: var(--aether-space-16) !important;
  padding-top: var(--aether-space-8);
  border-top: 1px solid var(--aether-border);
}

.s-case-disclosure summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  gap: var(--aether-space-3);
  font-family: var(--aether-font-mono);
  font-size: var(--aether-text-xs);
  letter-spacing: var(--aether-tracking-wide);
  text-transform: uppercase;
  color: var(--aether-accent);
  min-height: 44px;
}

.s-case-disclosure summary::-webkit-details-marker {
  display: none;
}

.s-case-disclosure summary::after {
  content: '';
  width: 7px;
  height: 7px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg);
  transition: transform var(--aether-transition-fast);
  flex-shrink: 0;
}

.s-case-disclosure[open] summary::after {
  transform: rotate(45deg);
}

.s-case-disclosure summary:hover {
  color: var(--aether-accent-hover);
}

.s-case-disclosure__body {
  padding-top: var(--aether-space-8);
}

.s-case-disclosure__body > * + * {
  margin-top: var(--aether-space-6);
}

/* Trimmed decision — same case-file idea as before, three fields
   instead of six, meant for a reader who chose to open this section. */
.s-mini-decision {
  border-top: 1px solid var(--aether-border);
  padding-top: var(--aether-space-5);
}

.s-mini-decision:first-child {
  border-top: none;
  padding-top: 0;
}

.s-mini-decision h4 {
  font-family: var(--aether-font-heading);
  font-weight: 500;
  font-size: var(--aether-text-base);
  margin: 0 0 var(--aether-space-3);
  color: var(--aether-text);
}

.s-mini-decision dl {
  display: flex;
  flex-direction: column;
  gap: var(--aether-space-2);
}

.s-mini-decision dt {
  display: inline;
  font-family: var(--aether-font-mono);
  font-size: 10.5px;
  letter-spacing: var(--aether-tracking-widest);
  text-transform: uppercase;
  color: var(--aether-accent);
}

.s-mini-decision dd {
  display: inline;
  margin: 0 0 0 var(--aether-space-2);
  font-size: var(--aether-text-sm);
  color: var(--aether-text-muted);
}

.s-mini-decision dd + dt {
  display: block;
  margin-top: var(--aether-space-2);
}
